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
+11 -1
View File
@@ -19,6 +19,16 @@ const (
AuthSourceTypeOIDC = "oidc"
)
// Shared GORM column name constants used across model package.
const (
colName = "name"
colEnabled = "enabled"
colRemark = "remark"
tableOfProxyRoutes = "of_proxy_routes"
optionKeyUptimeKumaPassword = "UptimeKumaPassword"
optionValueTrue = "true"
)
var authSourceNamePattern = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$`)
// AuthSource 认证源实体
@@ -192,7 +202,7 @@ func UpdateAuthSource(ctx context.Context, source *AuthSource, keepSecret bool)
return err
}
return db.DB(ctx).Model(&current).Updates(map[string]any{
"name": source.Name,
colName: source.Name,
"type": source.Type,
"display_name": source.DisplayName,
"is_active": source.IsActive,
+36 -11
View File
@@ -5,11 +5,19 @@ package model
import (
"context"
"math"
"sort"
"strings"
"time"
)
const (
columnRemoteAddr = "remote_addr"
columnHost = "host"
sortOrderAsc = "asc"
secondsPerMinute = 60
)
type openFlareAccessLogBucketAggregateRow struct {
BucketEpoch int64 `gorm:"column:bucket_epoch"`
RequestCount int64 `gorm:"column:request_count"`
@@ -147,7 +155,7 @@ func ListOpenFlareAccessLogIPTrend(ctx context.Context, query OpenFlareAccessLog
Host: query.Host,
Since: query.Since,
}
bucketSeconds := int64(query.BucketMinutes * 60)
bucketSeconds := int64(query.BucketMinutes * secondsPerMinute)
if bucketSeconds <= 0 {
bucketSeconds = 1800
}
@@ -182,7 +190,7 @@ func DeleteOpenFlareAccessLogsByNodeBefore(ctx context.Context, nodeID string, c
func buildOpenFlareAccessLogBucketRows(ctx context.Context, query OpenFlareAccessLogBucketQuery) ([]*OpenFlareAccessLogBucketRow, error) {
filter := openFlareAccessLogQueryFromBucket(query)
bucketSeconds := int64(query.FoldMinutes * 60)
bucketSeconds := int64(query.FoldMinutes * secondsPerMinute)
if bucketSeconds <= 0 {
bucketSeconds = 180
}
@@ -216,7 +224,7 @@ func buildOpenFlareAccessLogBucketRows(ctx context.Context, query OpenFlareAcces
accumulator.serverErrorCount += partial.ServerErrorCount
}
for _, column := range []string{"remote_addr", "host"} {
for _, column := range []string{columnRemoteAddr, columnHost} {
dimensions, err := currentAccessLogStore().BucketDimensions(ctx, filter, column, bucketSeconds)
if err != nil {
return nil, err
@@ -235,9 +243,9 @@ func buildOpenFlareAccessLogBucketRows(ctx context.Context, query OpenFlareAcces
continue
}
switch column {
case "remote_addr":
case columnRemoteAddr:
accumulator.uniqueIPs[trimmed] = struct{}{}
case "host":
case columnHost:
accumulator.uniqueHosts[trimmed] = struct{}{}
}
}
@@ -346,7 +354,7 @@ func openFlareAccessLogQueryFromBucket(query OpenFlareAccessLogBucketQuery) Open
}
func sortOpenFlareAccessLogBucketIPRows(items []*OpenFlareAccessLogBucketIPRow, sortBy string, sortOrder string) {
desc := openFlareAccessLogNormalizeSortOrder(sortOrder) != "asc"
desc := openFlareAccessLogNormalizeSortOrder(sortOrder) != sortOrderAsc
sort.Slice(items, func(i, j int) bool {
left := items[i]
right := items[j]
@@ -376,7 +384,7 @@ func sortOpenFlareAccessLogBucketIPRows(items []*OpenFlareAccessLogBucketIPRow,
}
func sortOpenFlareAccessLogBucketRows(items []*OpenFlareAccessLogBucketRow, sortBy string, sortOrder string) {
desc := openFlareAccessLogNormalizeSortOrder(sortOrder) != "asc"
desc := openFlareAccessLogNormalizeSortOrder(sortOrder) != sortOrderAsc
sort.Slice(items, func(i, j int) bool {
left := items[i]
right := items[j]
@@ -401,7 +409,7 @@ func sortOpenFlareAccessLogBucketRows(items []*OpenFlareAccessLogBucketRow, sort
}
func sortOpenFlareAccessLogIPSummaryRows(items []*OpenFlareAccessLogIPSummaryRow, sortBy string, sortOrder string) {
desc := openFlareAccessLogNormalizeSortOrder(sortOrder) != "asc"
desc := openFlareAccessLogNormalizeSortOrder(sortOrder) != sortOrderAsc
sort.Slice(items, func(i, j int) bool {
left := items[i]
right := items[j]
@@ -451,12 +459,30 @@ func openFlareAccessLogPaginateBounds(total int, page int, pageSize int) (int, i
}
func openFlareAccessLogNormalizeSortOrder(sortOrder string) string {
if strings.EqualFold(strings.TrimSpace(sortOrder), "asc") {
return "asc"
if strings.EqualFold(strings.TrimSpace(sortOrder), sortOrderAsc) {
return sortOrderAsc
}
return "desc"
}
func openFlareAccessLogStatusCodeToInt32(code int) int32 {
switch {
case code > math.MaxInt32:
return math.MaxInt32
case code < math.MinInt32:
return math.MinInt32
default:
return int32(code)
}
}
func openFlareAccessLogUintToInt64(value uint) int64 {
if value > math.MaxInt64 {
return math.MaxInt64
}
return int64(value)
}
func openFlareAccessLogCompareInt64(left int64, right int64) int {
switch {
case left > right:
@@ -467,4 +493,3 @@ func openFlareAccessLogCompareInt64(left int64, right int64) int {
return 0
}
}
+2 -2
View File
@@ -221,7 +221,7 @@ func toAnalyticsNodeAccessLog(record *OpenFlareAccessLog) analyticsmodel.NodeAcc
Region: record.Region,
Host: record.Host,
Path: record.Path,
StatusCode: int32(record.StatusCode),
StatusCode: openFlareAccessLogStatusCodeToInt32(record.StatusCode),
CreatedAt: record.CreatedAt,
}
}
@@ -242,4 +242,4 @@ func fromAnalyticsNodeAccessLogs(rows []analyticsmodel.NodeAccessLog) []*OpenFla
}
}
return result
}
}
@@ -133,9 +133,9 @@ func (s *memoryAccessLogStore) BucketDimensions(_ context.Context, filter OpenFl
for _, row := range rows {
var value string
switch column {
case "remote_addr":
case columnRemoteAddr:
value = strings.TrimSpace(row.RemoteAddr)
case "host":
case columnHost:
value = strings.TrimSpace(row.Host)
default:
continue
@@ -345,7 +345,7 @@ func cloneAccessLogSlice(rows []*OpenFlareAccessLog) []*OpenFlareAccessLog {
}
func sortOpenFlareAccessLogRows(items []*OpenFlareAccessLog, sortBy string, sortOrder string) {
desc := openFlareAccessLogNormalizeSortOrder(sortOrder) != "asc"
desc := openFlareAccessLogNormalizeSortOrder(sortOrder) != sortOrderAsc
sort.Slice(items, func(i, j int) bool {
left := items[i]
right := items[j]
@@ -356,9 +356,9 @@ func sortOpenFlareAccessLogRows(items []*OpenFlareAccessLog, sortBy string, sort
switch strings.TrimSpace(sortBy) {
case "status_code":
compare = left.StatusCode - right.StatusCode
case "remote_addr":
case columnRemoteAddr:
compare = strings.Compare(left.RemoteAddr, right.RemoteAddr)
case "host":
case columnHost:
compare = strings.Compare(left.Host, right.Host)
case "path":
compare = strings.Compare(left.Path, right.Path)
@@ -369,11 +369,11 @@ func sortOpenFlareAccessLogRows(items []*OpenFlareAccessLog, sortBy string, sort
compare = openFlareAccessLogCompareInt64(left.LoggedAt.Unix(), right.LoggedAt.Unix())
}
if compare == 0 {
compare = openFlareAccessLogCompareInt64(int64(left.ID), int64(right.ID))
compare = openFlareAccessLogCompareInt64(openFlareAccessLogUintToInt64(left.ID), openFlareAccessLogUintToInt64(right.ID))
}
if desc {
return compare > 0
}
return compare < 0
})
}
}
+14 -94
View File
@@ -285,56 +285,39 @@ func isMissingTableError(err error) bool {
strings.Contains(msg, "does not exist")
}
// ListOpenFlareMetricSnapshotsSince returns metric snapshots since the given time.
func ListOpenFlareMetricSnapshotsSince(ctx context.Context, nodeID string, since time.Time, limit int) ([]*OpenFlareMetricSnapshot, error) {
func listOpenFlareSince[T any](ctx context.Context, nodeID string, since time.Time, limit int, orderBy string, sinceColumn string) ([]*T, error) {
conn := db.DB(ctx)
if conn == nil {
return nil, errors.New(errDatabaseNotInitialized)
}
query := conn.Model(&OpenFlareMetricSnapshot{}).Order("captured_at desc, id desc")
query := conn.Model(new(T)).Order(orderBy)
if nodeID != "" {
query = query.Where("node_id = ?", nodeID)
}
if !since.IsZero() {
query = query.Where("captured_at >= ?", since)
query = query.Where(sinceColumn+" >= ?", since)
}
if limit > 0 {
query = query.Limit(limit)
}
var rows []*OpenFlareMetricSnapshot
var rows []*T
if err := query.Find(&rows).Error; err != nil {
if isMissingTableError(err) {
return []*OpenFlareMetricSnapshot{}, nil
return []*T{}, nil
}
return nil, err
}
return rows, nil
}
// ListOpenFlareMetricSnapshotsSince returns metric snapshots since the given time.
func ListOpenFlareMetricSnapshotsSince(ctx context.Context, nodeID string, since time.Time, limit int) ([]*OpenFlareMetricSnapshot, error) {
return listOpenFlareSince[OpenFlareMetricSnapshot](ctx, nodeID, since, limit, "captured_at desc, id desc", "captured_at")
}
// ListOpenFlareRequestReportsSince returns request reports since the given time.
func ListOpenFlareRequestReportsSince(ctx context.Context, nodeID string, since time.Time, limit int) ([]*OpenFlareRequestReport, error) {
conn := db.DB(ctx)
if conn == nil {
return nil, errors.New(errDatabaseNotInitialized)
}
query := conn.Model(&OpenFlareRequestReport{}).Order("window_ended_at desc, id desc")
if nodeID != "" {
query = query.Where("node_id = ?", nodeID)
}
if !since.IsZero() {
query = query.Where("window_ended_at >= ?", since)
}
if limit > 0 {
query = query.Limit(limit)
}
var rows []*OpenFlareRequestReport
if err := query.Find(&rows).Error; err != nil {
if isMissingTableError(err) {
return []*OpenFlareRequestReport{}, nil
}
return nil, err
}
return rows, nil
return listOpenFlareSince[OpenFlareRequestReport](ctx, nodeID, since, limit, "window_ended_at desc, id desc", "window_ended_at")
}
// ListOpenFlareActiveHealthEvents returns active health events across all nodes.
@@ -474,78 +457,15 @@ func GetOpenFlareNodeSystemProfile(ctx context.Context, nodeID string) (*OpenFla
// ListOpenFlareNodeObservationOpenresty returns openresty observations.
func ListOpenFlareNodeObservationOpenresty(ctx context.Context, nodeID string, since time.Time, limit int) ([]*OpenFlareNodeObservationOpenresty, error) {
conn := db.DB(ctx)
if conn == nil {
return nil, errors.New(errDatabaseNotInitialized)
}
query := conn.Model(&OpenFlareNodeObservationOpenresty{}).Order("captured_at desc, id desc")
if nodeID != "" {
query = query.Where("node_id = ?", nodeID)
}
if !since.IsZero() {
query = query.Where("captured_at >= ?", since)
}
if limit > 0 {
query = query.Limit(limit)
}
var rows []*OpenFlareNodeObservationOpenresty
if err := query.Find(&rows).Error; err != nil {
if isMissingTableError(err) {
return []*OpenFlareNodeObservationOpenresty{}, nil
}
return nil, err
}
return rows, nil
return listOpenFlareSince[OpenFlareNodeObservationOpenresty](ctx, nodeID, since, limit, "captured_at desc, id desc", "captured_at")
}
// ListOpenFlareNodeObservationFrpc returns frpc observations.
func ListOpenFlareNodeObservationFrpc(ctx context.Context, nodeID string, since time.Time, limit int) ([]*OpenFlareNodeObservationFrpc, error) {
conn := db.DB(ctx)
if conn == nil {
return nil, errors.New(errDatabaseNotInitialized)
}
query := conn.Model(&OpenFlareNodeObservationFrpc{}).Order("captured_at desc, id desc")
if nodeID != "" {
query = query.Where("node_id = ?", nodeID)
}
if !since.IsZero() {
query = query.Where("captured_at >= ?", since)
}
if limit > 0 {
query = query.Limit(limit)
}
var rows []*OpenFlareNodeObservationFrpc
if err := query.Find(&rows).Error; err != nil {
if isMissingTableError(err) {
return []*OpenFlareNodeObservationFrpc{}, nil
}
return nil, err
}
return rows, nil
return listOpenFlareSince[OpenFlareNodeObservationFrpc](ctx, nodeID, since, limit, "captured_at desc, id desc", "captured_at")
}
// ListOpenFlareNodeObservationFrps returns frps observations.
func ListOpenFlareNodeObservationFrps(ctx context.Context, nodeID string, since time.Time, limit int) ([]*OpenFlareNodeObservationFrps, error) {
conn := db.DB(ctx)
if conn == nil {
return nil, errors.New(errDatabaseNotInitialized)
}
query := conn.Model(&OpenFlareNodeObservationFrps{}).Order("captured_at desc, id desc")
if nodeID != "" {
query = query.Where("node_id = ?", nodeID)
}
if !since.IsZero() {
query = query.Where("captured_at >= ?", since)
}
if limit > 0 {
query = query.Limit(limit)
}
var rows []*OpenFlareNodeObservationFrps
if err := query.Find(&rows).Error; err != nil {
if isMissingTableError(err) {
return []*OpenFlareNodeObservationFrps{}, nil
}
return nil, err
}
return rows, nil
return listOpenFlareSince[OpenFlareNodeObservationFrps](ctx, nodeID, since, limit, "captured_at desc, id desc", "captured_at")
}
+85 -184
View File
@@ -34,81 +34,81 @@ var (
StartTime = time.Now().Unix()
// Hot-reload mirrors for frequently read options (legacy OpenFlare keys).
SystemName = "OpenFlare"
ServerAddress = ""
Footer = ""
HomePageLink = ""
PasswordLoginEnabled = true
CapLoginEnabled = true
PasswordRegisterEnabled = false
EmailVerificationEnabled = false
GitHubOAuthEnabled = false
WeChatAuthEnabled = false
GitHubClientId = ""
GitHubClientSecret = ""
WeChatServerAddress = ""
WeChatServerToken = ""
WeChatAccountQRCodeImageURL = ""
SMTPServer = ""
SMTPPort = 587
SMTPAccount = ""
SMTPToken = ""
AgentDiscoveryToken = ""
AgentHeartbeatInterval = 10000
AgentWebsocketUpgradeEnabled = true
NodeOfflineThreshold = 2 * time.Minute
AgentUpdateRepo = "Rain-kl/OpenFlare"
GeoIPProvider = "ipinfo"
DatabaseAutoCleanupEnabled = false
DatabaseAutoCleanupRetentionDays = 30
UptimeKumaEnabled = false
UptimeKumaUrl = ""
UptimeKumaUsername = ""
UptimeKumaPassword = ""
UptimeKumaMonitorScope = "all"
UptimeKumaSelectedSites = ""
UptimeKumaSyncInterval = 5
UptimeKumaInterval = 60
UptimeKumaRetry = 0
UptimeKumaRetryInterval = 60
UptimeKumaTimeout = 48
OpenRestyDefaultServerReturnStatus = 421
OpenRestyWorkerProcesses = "auto"
OpenRestyWorkerConnections = 4096
OpenRestyWorkerRlimitNofile = 65535
OpenRestyEventsUse = "epoll"
OpenRestyEventsMultiAcceptEnabled = true
OpenRestyKeepaliveTimeout = 20
OpenRestyKeepaliveRequests = 1000
OpenRestyClientHeaderTimeout = 15
OpenRestyClientBodyTimeout = 15
OpenRestyClientMaxBodySize = "64m"
OpenRestyLargeClientHeaderBuffers = "4 16k"
OpenRestySendTimeout = 30
OpenRestyResolvers = ""
OpenRestyProxyConnectTimeout = 3
OpenRestyProxySendTimeout = 60
OpenRestyProxyReadTimeout = 60
OpenRestyWebsocketEnabled = true
OpenRestyHTTP3Enabled = true
OpenRestyProxyRequestBufferingEnabled = false
OpenRestyProxyBufferingEnabled = true
OpenRestyProxyBuffers = "16 16k"
OpenRestyProxyBufferSize = "8k"
OpenRestyProxyBusyBuffersSize = "64k"
OpenRestyGzipEnabled = true
OpenRestyGzipMinLength = 1024
OpenRestyGzipCompLevel = 5
OpenRestyCacheEnabled = false
OpenRestyCachePath = ""
OpenRestyCacheLevels = "1:2"
OpenRestyCacheInactive = "30m"
OpenRestyCacheMaxSize = "1g"
OpenRestyCacheKeyTemplate = "$scheme$host$request_uri"
OpenRestyCacheLockEnabled = true
OpenRestyCacheLockTimeout = "5s"
OpenRestyCacheUseStale = "error timeout updating http_500 http_502 http_503 http_504"
OpenRestyMainConfigTemplate = defaultOpenRestyMainConfigTemplate
SystemName = "OpenFlare"
ServerAddress = ""
Footer = ""
HomePageLink = ""
PasswordLoginEnabled = true
CapLoginEnabled = true
PasswordRegisterEnabled = false
EmailVerificationEnabled = false
GitHubOAuthEnabled = false
WeChatAuthEnabled = false
GitHubClientID = ""
GitHubClientSecret = ""
WeChatServerAddress = ""
WeChatServerToken = ""
WeChatAccountQRCodeImageURL = ""
SMTPServer = ""
SMTPPort = 587
SMTPAccount = ""
SMTPToken = ""
AgentDiscoveryToken = ""
AgentHeartbeatInterval = 10000
AgentWebsocketUpgradeEnabled = true
NodeOfflineThreshold = 2 * time.Minute
AgentUpdateRepo = "Rain-kl/OpenFlare"
GeoIPProvider = "ipinfo"
DatabaseAutoCleanupEnabled = false
DatabaseAutoCleanupRetentionDays = 30
UptimeKumaEnabled = false
UptimeKumaURL = ""
UptimeKumaUsername = ""
UptimeKumaPassword = ""
UptimeKumaMonitorScope = "all"
UptimeKumaSelectedSites = ""
UptimeKumaSyncInterval = 5
UptimeKumaInterval = 60
UptimeKumaRetry = 0
UptimeKumaRetryInterval = 60
UptimeKumaTimeout = 48
OpenRestyDefaultServerReturnStatus = 421
OpenRestyWorkerProcesses = "auto"
OpenRestyWorkerConnections = 4096
OpenRestyWorkerRlimitNofile = 65535
OpenRestyEventsUse = "epoll"
OpenRestyEventsMultiAcceptEnabled = true
OpenRestyKeepaliveTimeout = 20
OpenRestyKeepaliveRequests = 1000
OpenRestyClientHeaderTimeout = 15
OpenRestyClientBodyTimeout = 15
OpenRestyClientMaxBodySize = "64m"
OpenRestyLargeClientHeaderBuffers = "4 16k"
OpenRestySendTimeout = 30
OpenRestyResolvers = ""
OpenRestyProxyConnectTimeout = 3
OpenRestyProxySendTimeout = 60
OpenRestyProxyReadTimeout = 60
OpenRestyWebsocketEnabled = true
OpenRestyHTTP3Enabled = true
OpenRestyProxyRequestBufferingEnabled = false
OpenRestyProxyBufferingEnabled = true
OpenRestyProxyBuffers = "16 16k"
OpenRestyProxyBufferSize = "8k"
OpenRestyProxyBusyBuffersSize = "64k"
OpenRestyGzipEnabled = true
OpenRestyGzipMinLength = 1024
OpenRestyGzipCompLevel = 5
OpenRestyCacheEnabled = false
OpenRestyCachePath = ""
OpenRestyCacheLevels = "1:2"
OpenRestyCacheInactive = "30m"
OpenRestyCacheMaxSize = "1g"
OpenRestyCacheKeyTemplate = "$scheme$host$request_uri"
OpenRestyCacheLockEnabled = true
OpenRestyCacheLockTimeout = "5s"
OpenRestyCacheUseStale = "error timeout updating http_500 http_502 http_503 http_504"
OpenRestyMainConfigTemplate = defaultOpenRestyMainConfigTemplate
)
const defaultOpenRestyMainConfigTemplate = `# This file is generated by OpenFlare. Do not edit manually.
@@ -183,9 +183,9 @@ func DefaultOpenFlareOptions() map[string]string {
"GeoIPProvider": GeoIPProvider,
"DatabaseAutoCleanupEnabled": strconv.FormatBool(DatabaseAutoCleanupEnabled),
"UptimeKumaEnabled": strconv.FormatBool(UptimeKumaEnabled),
"UptimeKumaUrl": UptimeKumaUrl,
"UptimeKumaUrl": UptimeKumaURL,
"UptimeKumaUsername": UptimeKumaUsername,
"UptimeKumaPassword": UptimeKumaPassword,
optionKeyUptimeKumaPassword: UptimeKumaPassword,
"UptimeKumaMonitorScope": UptimeKumaMonitorScope,
"UptimeKumaSelectedSites": UptimeKumaSelectedSites,
"UptimeKumaSyncInterval": strconv.Itoa(UptimeKumaSyncInterval),
@@ -229,7 +229,7 @@ func DefaultOpenFlareOptions() map[string]string {
"OpenRestyCacheLockEnabled": strconv.FormatBool(OpenRestyCacheLockEnabled),
"OpenRestyCacheLockTimeout": OpenRestyCacheLockTimeout,
"OpenRestyCacheUseStale": OpenRestyCacheUseStale,
"OpenRestyMainConfigTemplate": OpenRestyMainConfigTemplate,
"OpenRestyMainConfigTemplate": OpenRestyMainConfigTemplate,
}
}
@@ -271,7 +271,7 @@ func UpdateOpenFlareOptions(ctx context.Context, options []OpenFlareOption) erro
if err := db.DB(ctx).Transaction(func(tx *gorm.DB) error {
for _, item := range options {
if item.Key == "UptimeKumaPassword" && strings.TrimSpace(item.Value) == "" {
if item.Key == optionKeyUptimeKumaPassword && strings.TrimSpace(item.Value) == "" {
continue
}
option := OpenFlareOption{Key: item.Key}
@@ -289,7 +289,7 @@ func UpdateOpenFlareOptions(ctx context.Context, options []OpenFlareOption) erro
}
for _, item := range options {
if item.Key == "UptimeKumaPassword" && strings.TrimSpace(item.Value) == "" {
if item.Key == optionKeyUptimeKumaPassword && strings.TrimSpace(item.Value) == "" {
continue
}
applyOptionMap(item.Key, item.Value)
@@ -316,112 +316,13 @@ func ResetOptionMapForTest() {
func applyOptionMap(key, value string) {
OptionMapRWMutex.Lock()
defer OptionMapRWMutex.Unlock()
if OptionMap == nil {
OptionMap = make(map[string]string)
}
OptionMap[key] = value
if strings.HasSuffix(key, "Enabled") {
boolValue := value == "true"
switch key {
case "PasswordRegisterEnabled":
PasswordRegisterEnabled = boolValue
case "PasswordLoginEnabled":
PasswordLoginEnabled = boolValue
case "CapLoginEnabled":
CapLoginEnabled = boolValue
case "EmailVerificationEnabled":
EmailVerificationEnabled = boolValue
case "GitHubOAuthEnabled":
GitHubOAuthEnabled = boolValue
case "WeChatAuthEnabled":
WeChatAuthEnabled = boolValue
}
}
switch key {
case "SMTPServer":
SMTPServer = value
case "SMTPPort":
if intValue, err := strconv.Atoi(value); err == nil {
SMTPPort = intValue
}
case "SMTPAccount":
SMTPAccount = value
case "SMTPToken":
SMTPToken = value
case "ServerAddress":
ServerAddress = value
case "GitHubClientId":
GitHubClientId = value
case "GitHubClientSecret":
GitHubClientSecret = value
case "Footer":
Footer = value
case "HomePageLink":
HomePageLink = value
case "SystemName":
SystemName = value
case "WeChatServerAddress":
WeChatServerAddress = value
case "WeChatServerToken":
WeChatServerToken = value
case "WeChatAccountQRCodeImageURL":
WeChatAccountQRCodeImageURL = value
case "AgentDiscoveryToken":
AgentDiscoveryToken = value
case "AgentHeartbeatInterval":
if v, err := strconv.Atoi(value); err == nil && v > 0 {
AgentHeartbeatInterval = v
}
case "AgentWebsocketUpgradeEnabled":
AgentWebsocketUpgradeEnabled = value == "true"
case "NodeOfflineThreshold":
if v, err := strconv.Atoi(value); err == nil && v > 0 {
NodeOfflineThreshold = time.Duration(v) * time.Millisecond
}
case "AgentUpdateRepo":
if value != "" {
AgentUpdateRepo = value
}
case "GeoIPProvider":
GeoIPProvider = value
case "UptimeKumaEnabled":
UptimeKumaEnabled = value == "true"
case "UptimeKumaUrl":
UptimeKumaUrl = value
case "UptimeKumaUsername":
UptimeKumaUsername = value
case "UptimeKumaPassword":
UptimeKumaPassword = value
case "UptimeKumaMonitorScope":
UptimeKumaMonitorScope = value
case "UptimeKumaSelectedSites":
UptimeKumaSelectedSites = value
case "UptimeKumaSyncInterval":
if v, err := strconv.Atoi(value); err == nil && v > 0 {
UptimeKumaSyncInterval = v
}
case "UptimeKumaInterval":
if v, err := strconv.Atoi(value); err == nil && v > 0 {
UptimeKumaInterval = v
}
case "UptimeKumaRetry":
if v, err := strconv.Atoi(value); err == nil && v >= 0 {
UptimeKumaRetry = v
}
case "UptimeKumaRetryInterval":
if v, err := strconv.Atoi(value); err == nil && v > 0 {
UptimeKumaRetryInterval = v
}
case "UptimeKumaTimeout":
if v, err := strconv.Atoi(value); err == nil && v > 0 {
UptimeKumaTimeout = v
}
case "DatabaseAutoCleanupEnabled":
DatabaseAutoCleanupEnabled = value == "true"
case "DatabaseAutoCleanupRetentionDays":
if v, err := strconv.Atoi(value); err == nil && v >= 1 {
DatabaseAutoCleanupRetentionDays = v
}
}
OptionMapRWMutex.Unlock()
applyEnabledOptionMirror(key, value)
applyStringOptionMirror(key, value)
applyIntegerOptionMirror(key, value)
applySpecialOptionMirror(key, value)
}
+96
View File
@@ -0,0 +1,96 @@
package model
import (
"strconv"
"strings"
"time"
)
var enabledOptionAppliers = map[string]func(bool){
"PasswordRegisterEnabled": func(v bool) { PasswordRegisterEnabled = v },
"PasswordLoginEnabled": func(v bool) { PasswordLoginEnabled = v },
"CapLoginEnabled": func(v bool) { CapLoginEnabled = v },
"EmailVerificationEnabled": func(v bool) { EmailVerificationEnabled = v },
"GitHubOAuthEnabled": func(v bool) { GitHubOAuthEnabled = v },
"WeChatAuthEnabled": func(v bool) { WeChatAuthEnabled = v },
"AgentWebsocketUpgradeEnabled": func(v bool) { AgentWebsocketUpgradeEnabled = v },
"UptimeKumaEnabled": func(v bool) { UptimeKumaEnabled = v },
"DatabaseAutoCleanupEnabled": func(v bool) { DatabaseAutoCleanupEnabled = v },
}
var stringOptionAppliers = map[string]func(string){
"SMTPServer": func(v string) { SMTPServer = v },
"SMTPAccount": func(v string) { SMTPAccount = v },
"SMTPToken": func(v string) { SMTPToken = v },
"ServerAddress": func(v string) { ServerAddress = v },
"GitHubClientId": func(v string) { GitHubClientID = v },
"GitHubClientSecret": func(v string) { GitHubClientSecret = v },
"Footer": func(v string) { Footer = v },
"HomePageLink": func(v string) { HomePageLink = v },
"SystemName": func(v string) { SystemName = v },
"WeChatServerAddress": func(v string) { WeChatServerAddress = v },
"WeChatServerToken": func(v string) { WeChatServerToken = v },
"WeChatAccountQRCodeImageURL": func(v string) { WeChatAccountQRCodeImageURL = v },
"AgentDiscoveryToken": func(v string) { AgentDiscoveryToken = v },
"GeoIPProvider": func(v string) { GeoIPProvider = v },
"UptimeKumaUrl": func(v string) { UptimeKumaURL = v },
"UptimeKumaUsername": func(v string) { UptimeKumaUsername = v },
optionKeyUptimeKumaPassword: func(v string) { UptimeKumaPassword = v },
"UptimeKumaMonitorScope": func(v string) { UptimeKumaMonitorScope = v },
"UptimeKumaSelectedSites": func(v string) { UptimeKumaSelectedSites = v },
}
func applyEnabledOptionMirror(key, value string) {
applier, ok := enabledOptionAppliers[key]
if !ok {
return
}
applier(value == optionValueTrue)
}
func applyStringOptionMirror(key, value string) {
if applier, ok := stringOptionAppliers[key]; ok {
applier(value)
}
}
type intOptionApplier struct {
apply func(int)
min int
}
var integerOptionAppliers = map[string]intOptionApplier{
"SMTPPort": {apply: func(v int) { SMTPPort = v }},
"AgentHeartbeatInterval": {apply: func(v int) { AgentHeartbeatInterval = v }, min: 1},
"UptimeKumaSyncInterval": {apply: func(v int) { UptimeKumaSyncInterval = v }, min: 1},
"UptimeKumaInterval": {apply: func(v int) { UptimeKumaInterval = v }, min: 1},
"UptimeKumaRetry": {apply: func(v int) { UptimeKumaRetry = v }, min: 0},
"UptimeKumaRetryInterval": {apply: func(v int) { UptimeKumaRetryInterval = v }, min: 1},
"UptimeKumaTimeout": {apply: func(v int) { UptimeKumaTimeout = v }, min: 1},
"DatabaseAutoCleanupRetentionDays": {apply: func(v int) { DatabaseAutoCleanupRetentionDays = v }, min: 1},
}
func applyIntegerOptionMirror(key, value string) {
applier, ok := integerOptionAppliers[key]
if !ok {
return
}
intValue, err := strconv.Atoi(value)
if err != nil || intValue < applier.min {
return
}
applier.apply(intValue)
}
func applySpecialOptionMirror(key, value string) {
switch key {
case "NodeOfflineThreshold":
if v, err := strconv.Atoi(value); err == nil && v > 0 {
NodeOfflineThreshold = time.Duration(v) * time.Millisecond
}
case "AgentUpdateRepo":
if strings.TrimSpace(value) != "" {
AgentUpdateRepo = value
}
}
}
+1 -1
View File
@@ -44,7 +44,7 @@ type OriginProxyRoute struct {
// TableName 表名。
func (OriginProxyRoute) TableName() string {
return "of_proxy_routes"
return tableOfProxyRoutes
}
// HasProxyRoutesTable 判断代理规则表是否已迁移。
+1
View File
@@ -10,6 +10,7 @@ import (
"github.com/Rain-kl/Wavelet/internal/db"
)
// Pages deployment status constants.
const (
PagesDeploymentStatusUploaded = "uploaded"
PagesDeploymentStatusActive = "active"
+3 -3
View File
@@ -48,7 +48,7 @@ type ProxyRoute struct {
// TableName 表名。
func (ProxyRoute) TableName() string {
return "of_proxy_routes"
return tableOfProxyRoutes
}
// ListProxyRoutes 列出全部代理规则。
@@ -84,7 +84,7 @@ func UpdateProxyRouteRecord(ctx context.Context, route *ProxyRoute) error {
"origin_url": route.OriginURL,
"origin_host": route.OriginHost,
"upstreams": route.Upstreams,
"enabled": route.Enabled,
colEnabled: route.Enabled,
"enable_https": route.EnableHTTPS,
"cert_id": route.CertID,
"cert_ids": route.CertIDs,
@@ -100,7 +100,7 @@ func UpdateProxyRouteRecord(ctx context.Context, route *ProxyRoute) error {
"basic_auth_enabled": route.BasicAuthEnabled,
"basic_auth_username": route.BasicAuthUsername,
"basic_auth_password": route.BasicAuthPassword,
"remark": route.Remark,
colRemark: route.Remark,
"upstream_type": route.UpstreamType,
"tunnel_node_id": route.TunnelNodeID,
"tunnel_target_addr": route.TunnelTargetAddr,
+2 -2
View File
@@ -22,7 +22,7 @@ type TLSCertificate struct {
Remark string `json:"remark" gorm:"size:255"`
Provider string `json:"provider" gorm:"size:64;default:upload"`
AcmeAccountID uint `json:"acme_account_id"`
DnsAccountID uint `json:"dns_account_id"`
DNSAccountID uint `json:"dns_account_id"`
KeyAlgorithm string `json:"key_algorithm" gorm:"size:32"`
AutoRenew bool `json:"auto_renew"`
PrimaryDomain string `json:"primary_domain" gorm:"size:255"`
@@ -52,7 +52,7 @@ type TLSProxyRouteRef struct {
// TableName 表名。
func (TLSProxyRouteRef) TableName() string {
return "of_proxy_routes"
return tableOfProxyRoutes
}
// HasTLSProxyRoutesTable 判断代理规则表是否已迁移。
+2 -2
View File
@@ -144,7 +144,7 @@ func UpdateOpenFlareWAFRuleGroup(ctx context.Context, group *OpenFlareWAFRuleGro
}
return conn.Model(&OpenFlareWAFRuleGroup{}).Where("id = ?", group.ID).Updates(map[string]any{
"name": group.Name,
"enabled": group.Enabled,
colEnabled: group.Enabled,
"is_global": group.IsGlobal,
"block_status_code": group.BlockStatusCode,
"block_response_body": group.BlockResponseBody,
@@ -158,7 +158,7 @@ func UpdateOpenFlareWAFRuleGroup(ctx context.Context, group *OpenFlareWAFRuleGro
"region_blacklist": group.RegionBlacklist,
"pow_enabled": group.PoWEnabled,
"pow_config": group.PoWConfig,
"remark": group.Remark,
colRemark: group.Remark,
}).Error
}