This commit is contained in:
ryan
2026-06-19 15:13:24 +08:00
parent 0b34792709
commit 32861c5db9
376 changed files with 3648 additions and 19957 deletions
@@ -1,6 +1,7 @@
// Copyright 2026 Arctel.net
// SPDX-License-Identifier: Apache-2.0
// Package config_version defines shared error messages for configuration versions.
package config_version
const (
@@ -8,6 +8,7 @@ import (
"encoding/json"
"errors"
"fmt"
"slices"
"sort"
"strconv"
"strings"
@@ -17,6 +18,11 @@ import (
"gorm.io/gorm"
)
const (
cleanupSuccessMessage = "清理成功"
minConfigVersionKeepCount = 3
)
// ConfigPreviewResult is the preview response payload.
type ConfigPreviewResult struct {
SnapshotJSON string `json:"snapshot_json"`
@@ -243,15 +249,15 @@ func ActivateConfigVersion(ctx context.Context, id uint) (*model.ConfigVersion,
// CleanupConfigVersions removes old inactive config versions.
func CleanupConfigVersions(ctx context.Context, keepCount int) (*CleanupResult, error) {
if keepCount < 3 {
keepCount = 3
if keepCount < minConfigVersionKeepCount {
keepCount = minConfigVersionKeepCount
}
versions, err := model.ListConfigVersionSummaries(ctx)
if err != nil {
return nil, err
}
if len(versions) <= keepCount {
return &CleanupResult{DeletedCount: 0, Message: "清理成功"}, nil
return &CleanupResult{DeletedCount: 0, Message: cleanupSuccessMessage}, nil
}
var deleteIDs []uint
for index, version := range versions {
@@ -264,13 +270,13 @@ func CleanupConfigVersions(ctx context.Context, keepCount int) (*CleanupResult,
deleteIDs = append(deleteIDs, version.ID)
}
if len(deleteIDs) == 0 {
return &CleanupResult{DeletedCount: 0, Message: "清理成功"}, nil
return &CleanupResult{DeletedCount: 0, Message: cleanupSuccessMessage}, nil
}
deletedCount, err := model.DeleteConfigVersionsByIDs(ctx, deleteIDs)
if err != nil {
return nil, err
}
return &CleanupResult{DeletedCount: deletedCount, Message: "清理成功"}, nil
return &CleanupResult{DeletedCount: deletedCount, Message: cleanupSuccessMessage}, nil
}
func nextVersionNumber(ctx context.Context, now time.Time) (string, error) {
@@ -368,50 +374,50 @@ func flattenSnapshotRoutesByDomain(routes []snapshotRoute) map[string]snapshotRo
}
func snapshotRouteConfigEqual(left snapshotRoute, right snapshotRoute) bool {
if left.SiteName != right.SiteName || left.Domain != right.Domain || left.OriginURL != right.OriginURL ||
left.OriginHost != right.OriginHost || left.EnableHTTPS != right.EnableHTTPS || left.RedirectHTTP != right.RedirectHTTP ||
left.LimitConnPerServer != right.LimitConnPerServer || left.LimitConnPerIP != right.LimitConnPerIP ||
left.LimitRate != right.LimitRate || left.CacheEnabled != right.CacheEnabled || left.CachePolicy != right.CachePolicy ||
left.BasicAuthEnabled != right.BasicAuthEnabled || left.BasicAuthUsername != right.BasicAuthUsername ||
left.BasicAuthPassword != right.BasicAuthPassword || left.UpstreamType != right.UpstreamType ||
!uintPtrEqual(left.TunnelNodeID, right.TunnelNodeID) || left.TunnelTargetAddr != right.TunnelTargetAddr ||
left.TunnelTargetProto != right.TunnelTargetProto || !uintPtrEqual(left.PagesProjectID, right.PagesProjectID) ||
!uintSliceEqual(left.CertIDs, right.CertIDs) || !uintSliceEqual(left.DomainCertIDs, right.DomainCertIDs) {
return false
}
if len(left.Domains) != len(right.Domains) {
return false
}
for index := range left.Domains {
if left.Domains[index] != right.Domains[index] {
return false
}
}
if len(left.Upstreams) != len(right.Upstreams) {
return false
}
for index := range left.Upstreams {
if left.Upstreams[index] != right.Upstreams[index] {
return false
}
}
if len(left.CacheRules) != len(right.CacheRules) {
return false
}
for index := range left.CacheRules {
if left.CacheRules[index] != right.CacheRules[index] {
return false
}
}
if len(left.CustomHeaders) != len(right.CustomHeaders) {
return false
}
for index := range left.CustomHeaders {
if left.CustomHeaders[index] != right.CustomHeaders[index] {
return false
}
}
return true
return snapshotRouteScalarsEqual(left, right) &&
slices.Equal(left.Domains, right.Domains) &&
slices.Equal(left.Upstreams, right.Upstreams) &&
slices.Equal(left.CacheRules, right.CacheRules) &&
slices.Equal(left.CustomHeaders, right.CustomHeaders)
}
func snapshotRouteScalarsEqual(left, right snapshotRoute) bool {
return snapshotRouteIdentityEqual(left, right) &&
snapshotRouteOriginEqual(left, right) &&
snapshotRoutePolicyEqual(left, right) &&
snapshotRouteTunnelEqual(left, right) &&
uintSliceEqual(left.CertIDs, right.CertIDs) &&
uintSliceEqual(left.DomainCertIDs, right.DomainCertIDs)
}
func snapshotRouteIdentityEqual(left, right snapshotRoute) bool {
return left.SiteName == right.SiteName && left.Domain == right.Domain
}
func snapshotRouteOriginEqual(left, right snapshotRoute) bool {
return left.OriginURL == right.OriginURL &&
left.OriginHost == right.OriginHost &&
left.UpstreamType == right.UpstreamType
}
func snapshotRoutePolicyEqual(left, right snapshotRoute) bool {
return left.EnableHTTPS == right.EnableHTTPS &&
left.RedirectHTTP == right.RedirectHTTP &&
left.LimitConnPerServer == right.LimitConnPerServer &&
left.LimitConnPerIP == right.LimitConnPerIP &&
left.LimitRate == right.LimitRate &&
left.CacheEnabled == right.CacheEnabled &&
left.CachePolicy == right.CachePolicy &&
left.BasicAuthEnabled == right.BasicAuthEnabled &&
left.BasicAuthUsername == right.BasicAuthUsername &&
left.BasicAuthPassword == right.BasicAuthPassword
}
func snapshotRouteTunnelEqual(left, right snapshotRoute) bool {
return left.TunnelTargetAddr == right.TunnelTargetAddr &&
left.TunnelTargetProto == right.TunnelTargetProto &&
uintPtrEqual(left.TunnelNodeID, right.TunnelNodeID) &&
uintPtrEqual(left.PagesProjectID, right.PagesProjectID)
}
func snapshotWAFConfigEqual(left snapshotWAFDocument, right snapshotWAFDocument) bool {
@@ -16,6 +16,8 @@ import (
openrestyrender "github.com/Rain-kl/Wavelet/pkg/render/openresty"
)
const supportFilesPerCertificate = 2
type snapshotRoute struct {
ID uint `json:"id,omitempty"`
SiteName string `json:"site_name,omitempty"`
@@ -227,13 +229,14 @@ func buildSnapshotRoutes(ctx context.Context, routes []*model.ProxyRoute) ([]sna
var tunnelTargetAddr string
var tunnelTargetProtocol string
var pagesProjectID *uint
if upstreamType == "tunnel" {
switch upstreamType {
case "tunnel":
originURL = resolveTunnelOpenRestyUpstreamURL(ctx)
upstreams = []string{originURL}
tunnelNodeID = route.TunnelNodeID
tunnelTargetAddr = strings.TrimSpace(route.TunnelTargetAddr)
tunnelTargetProtocol = normalizeTunnelTargetProtocol(route.TunnelTargetProtocol)
} else if upstreamType == "pages" {
case "pages":
return nil, fmt.Errorf("路由 %s Pages 配置无效: pages module is not available", route.Domain)
}
cacheRules, err := decodeStoredCacheRules(route.CacheRules)
@@ -495,7 +498,7 @@ func buildCertificateSupportFiles(ctx context.Context, routes []snapshotRoute) (
certIDs = append(certIDs, certID)
}
sort.Slice(certIDs, func(i, j int) bool { return certIDs[i] < certIDs[j] })
files := make([]SupportFile, 0, len(certIDs)*2)
files := make([]SupportFile, 0, len(certIDs)*supportFilesPerCertificate)
for _, certID := range certIDs {
certificate, err := model.GetTLSCertificateByID(ctx, certID)
if err != nil {