From b76f707c8b48aad25715a5e0dab7ee97ca030ebe Mon Sep 17 00:00:00 2001 From: ryan Date: Sun, 16 Aug 2026 17:28:22 +0800 Subject: [PATCH] =?UTF-8?q?modernize=2037=E2=86=925=EF=BC=88-32=EF=BC=89?= =?UTF-8?q?=EF=BC=9Ainterface{}=E2=86=92any=E3=80=81=E5=86=85=E7=BD=AE=20m?= =?UTF-8?q?ax/min=E3=80=81slices/maps=20=E8=BE=85=E5=8A=A9=E3=80=81strings?= =?UTF-8?q?.Cut/SplitSeq=E3=80=81strings.Builder=EF=BC=88=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20mail.go=20O(n=C2=B2)=20=E6=8B=BC=E6=8E=A5=EF=BC=89?= =?UTF-8?q?=E3=80=82=E9=80=90=20hunk=20=E6=A0=B8=E5=AF=B9=E8=AF=AD?= =?UTF-8?q?=E4=B9=89=E7=AD=89=E4=BB=B7=EF=BC=9Bomitzero=20=E5=86=B2?= =?UTF-8?q?=E7=AA=81=E4=BF=AE=E5=A4=8D=E8=A2=AB=E8=87=AA=E5=8A=A8=E8=B7=B3?= =?UTF-8?q?=E8=BF=87=EF=BC=88wire=20=E6=A0=BC=E5=BC=8F=E4=B8=8D=E5=8F=98?= =?UTF-8?q?=EF=BC=89=EF=BC=9B=E6=89=8B=E5=8A=A8=E6=B8=85=204=20=E5=A4=84?= =?UTF-8?q?=E9=81=97=E7=95=99=20sort=20import=20+=202=20=E5=A4=84=20QF1012?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Result: {"status":"keep","total_issues":74,"golint_canonicalheader":8,"golint_errname":1,"golint_errorlint":12,"golint_forcetypeassert":3,"golint_gosec":0,"golint_intrange":3,"golint_modernize":5,"golint_nilnil":3,"golint_perfsprint":18,"golint_prealloc":3,"golint_recvcheck":7,"golint_usestdlibvars":3,"golint_wastedassign":7,"golint_total":73,"eslint_problems":1,"eslint_errors":0,"eslint_warnings":1,"tsc_errors":0,"measure_s":38} --- .auto/log.jsonl | 1 + internal/apps/admin/db_manage/routers.go | 49 ++++++++----------- internal/apps/admin/logs/utils.go | 4 +- .../apps/admin/push/channels_definition.go | 10 ++-- internal/apps/admin/push/events.go | 5 +- internal/apps/admin/updater/logics.go | 15 ++---- internal/apps/admin/user/routers.go | 17 +++---- .../apps/agent/runtimeuser/runtimeuser.go | 2 +- internal/apps/agent/sync/pages.go | 7 +-- internal/apps/agent/sync/service.go | 4 +- internal/apps/cap/manager.go | 5 +- internal/apps/edge/observability/linux.go | 14 ++---- internal/apps/edge/updater/service.go | 2 +- internal/apps/flared/frpc/manager.go | 2 +- internal/apps/oauth/auth_source_resolver.go | 8 +-- .../apps/openflare/agent/observability.go | 15 ++---- internal/apps/openflare/agent/waf_ip_group.go | 5 +- internal/apps/openflare/cloudflare/client.go | 2 +- .../apps/openflare/config_version/snapshot.go | 5 +- .../openflare/option/openresty_validators.go | 2 +- internal/apps/openflare/origin/helpers.go | 4 +- internal/apps/openflare/pages/helpers.go | 13 ++--- internal/apps/openflare/pages/logics.go | 2 +- internal/apps/openflare/pages/source_sync.go | 4 +- .../apps/openflare/proxy_route/helpers.go | 8 +-- internal/apps/openflare/proxy_route/logics.go | 4 +- internal/apps/openflare/tls/obtain.go | 2 +- internal/apps/openflare/uptimekuma/client.go | 9 ++-- internal/apps/openflare/waf/graph_compile.go | 3 +- internal/apps/openflare/waf/graph_validate.go | 8 +-- internal/apps/openflare/waf/ip_group_sync.go | 7 ++- internal/apps/openflare/zone/stats.go | 5 +- internal/apps/relay/frps/manager.go | 2 +- internal/apps/upload/ingest/helpers.go | 4 +- .../apps/upload/task/storage_migration.go | 16 +++--- internal/apps/upload/util/media.go | 22 ++------- internal/cmd/all.go | 18 +++---- internal/infra/config/config.go | 9 ++-- internal/infra/persistence/postgres_logger.go | 10 ++-- internal/infra/task/executor.go | 2 +- internal/infra/task/utils.go | 6 +-- .../analytics/node_observability.go | 4 +- internal/repository/openflare_access_log.go | 10 +--- internal/router/middlewares.go | 6 +-- internal/shared/response/response.go | 4 +- pkg/cache/ram/manager.go | 5 +- pkg/cap/cap.go | 4 +- pkg/geoip/country_centroid.go | 2 +- pkg/logger/logger.go | 8 +-- pkg/logger/ringbuffer.go | 5 +- pkg/mail/mail.go | 20 ++++---- pkg/pagesarchive/path.go | 2 +- pkg/render/openresty/render.go | 2 +- pkg/render/openresty/status_codes.go | 6 +-- pkg/util/value.go | 2 +- pkg/util/version_compare.go | 15 ++---- 56 files changed, 164 insertions(+), 263 deletions(-) diff --git a/.auto/log.jsonl b/.auto/log.jsonl index 40eca8cf..098d17dc 100644 --- a/.auto/log.jsonl +++ b/.auto/log.jsonl @@ -1,2 +1,3 @@ {"type":"config","name":"前后端代码质量优化(符合最佳实践)","metricName":"total_issues","metricUnit":"","bestDirection":"lower"} {"run":1,"commit":"305d609","metric":108,"metrics":{"golint_canonicalheader":8,"golint_errname":1,"golint_errorlint":12,"golint_forcetypeassert":3,"golint_gosec":2,"golint_intrange":3,"golint_modernize":37,"golint_nilnil":3,"golint_perfsprint":18,"golint_prealloc":3,"golint_recvcheck":7,"golint_usestdlibvars":3,"golint_wastedassign":7,"golint_total":107,"eslint_problems":1,"eslint_errors":0,"eslint_warnings":1,"tsc_errors":0,"measure_s":36},"status":"checks_failed","description":"基线:总问题 108(golangci 107 + eslint 1)。checks 失败的唯一原因:repo 自带 golangci gate 有 2 个既有 gosec G115 问题(预期内,首次修复后即绿)。","timestamp":1786871594292,"segment":0,"confidence":null,"asi":{"hypothesis":"baseline","next_action_hint":"修复 internal/apps/edge/observability/linux.go 的 2 个 G115 gosec 问题后 checks.sh 才能通过;之后每次迭代即可正常 keep/discard"}} +{"run":2,"commit":"f1f6bb8","metric":106,"metrics":{"golint_canonicalheader":8,"golint_errname":1,"golint_errorlint":12,"golint_forcetypeassert":3,"golint_gosec":0,"golint_intrange":3,"golint_modernize":37,"golint_nilnil":3,"golint_perfsprint":18,"golint_prealloc":3,"golint_recvcheck":7,"golint_usestdlibvars":3,"golint_wastedassign":7,"golint_total":105,"eslint_problems":1,"eslint_errors":0,"eslint_warnings":1,"tsc_errors":0,"measure_s":38},"status":"keep","description":"修复 internal/apps/edge/observability/linux.go 的 2 个 gosec G115 整数溢出转换:helper 改为接收 int64 b,用 gosec 认可的饱和乘法模式(uint64 域乘积 + 上界比较),去掉原 //nolint:gosec,语义不变(Bsize 恒为正)。repo 自带 gate 首次全绿。","timestamp":1786872064145,"segment":0,"confidence":null,"asi":{"hypothesis":"修复 gosec G115:multiplyUint64ToInt64 改为 accept int64 b 并采用 gosec 认可的饱和乘法模式","insight":"gosec G115 不接受分支上界证明(a > MaxInt64/b),但接受先算 uint64 乘积再 if v > MaxInt64 饱和的模式,无需 nolint","next_action_hint":"下一步批量清理 modernize(37)/perfsprint(18) 等自动可修复类别,用 golangci-lint --fix 后人工核对 diff"}} diff --git a/internal/apps/admin/db_manage/routers.go b/internal/apps/admin/db_manage/routers.go index a6381fbb..10ff54b6 100644 --- a/internal/apps/admin/db_manage/routers.go +++ b/internal/apps/admin/db_manage/routers.go @@ -50,9 +50,9 @@ type GetTableDataRequest struct { // TableDataResponse 动态数据表响应结构体 type TableDataResponse struct { - Columns []string `json:"columns"` - Total int64 `json:"total"` - Results []map[string]interface{} `json:"results"` + Columns []string `json:"columns"` + Total int64 `json:"total"` + Results []map[string]any `json:"results"` } // ExecuteSQLRequest 执行自定义 SQL 请求结构体 @@ -62,11 +62,11 @@ type ExecuteSQLRequest struct { // ExecuteSQLResponse 执行自定义 SQL 响应结构体 type ExecuteSQLResponse struct { - Type string `json:"type"` // "select" 或 "exec" - Columns []string `json:"columns,omitempty"` - Results []map[string]interface{} `json:"results,omitempty"` - AffectedRows int64 `json:"affected_rows"` - ExecutionTimeMs int64 `json:"execution_time_ms"` + Type string `json:"type"` // "select" 或 "exec" + Columns []string `json:"columns,omitempty"` + Results []map[string]any `json:"results,omitempty"` + AffectedRows int64 `json:"affected_rows"` + ExecutionTimeMs int64 `json:"execution_time_ms"` } // formatBytes 格式化字节大小为可读字符串 @@ -119,10 +119,7 @@ func getSQLiteOverview(gormDB *gorm.DB) (DBOverviewResponse, error) { var sizeStr string if fi, err := os.Stat(name); err == nil { - size := fi.Size() - if size < 0 { - size = 0 - } + size := max(fi.Size(), 0) sizeStr = formatBytes(uint64(size)) } else { sizeStr = "0 B" @@ -165,10 +162,7 @@ func getPostgresOverview(gormDB *gorm.DB) (DBOverviewResponse, error) { var sizeStr string var sizeBytes sql.NullInt64 if err := gormDB.Raw("SELECT pg_database_size(current_database())").Scan(&sizeBytes).Error; err == nil && sizeBytes.Valid { - size := sizeBytes.Int64 - if size < 0 { - size = 0 - } + size := max(sizeBytes.Int64, 0) sizeStr = formatBytes(uint64(size)) } else { sizeStr = "0 B" @@ -294,10 +288,7 @@ func GetDBTableData(c *gin.Context) { return } - offset := (req.Page - 1) * req.PageSize - if offset < 0 { - offset = 0 - } + offset := max((req.Page-1)*req.PageSize, 0) limit := req.PageSize if limit <= 0 { limit = 10 @@ -332,11 +323,11 @@ func GetDBTableData(c *gin.Context) { } // scanTableRows 扫描并提取数据表行数据,做截断处理 -func scanTableRows(rows *sql.Rows, cols []string) ([]map[string]interface{}, error) { - results := make([]map[string]interface{}, 0) +func scanTableRows(rows *sql.Rows, cols []string) ([]map[string]any, error) { + results := make([]map[string]any, 0) for rows.Next() { - columns := make([]interface{}, len(cols)) - columnPointers := make([]interface{}, len(cols)) + columns := make([]any, len(cols)) + columnPointers := make([]any, len(cols)) for i := range columns { columnPointers[i] = &columns[i] } @@ -345,7 +336,7 @@ func scanTableRows(rows *sql.Rows, cols []string) ([]map[string]interface{}, err return nil, err } - rowMap := make(map[string]interface{}) + rowMap := make(map[string]any) for i, colName := range cols { val := columns[i] if b, ok := val.([]byte); ok { @@ -385,10 +376,10 @@ func executeSQLQuery(gormDB *gorm.DB, sqlStr string, startTime time.Time) (Execu return ExecuteSQLResponse{}, err } - results := make([]map[string]interface{}, 0) + results := make([]map[string]any, 0) for rows.Next() { - columns := make([]interface{}, len(cols)) - columnPointers := make([]interface{}, len(cols)) + columns := make([]any, len(cols)) + columnPointers := make([]any, len(cols)) for i := range columns { columnPointers[i] = &columns[i] } @@ -397,7 +388,7 @@ func executeSQLQuery(gormDB *gorm.DB, sqlStr string, startTime time.Time) (Execu return ExecuteSQLResponse{}, err } - rowMap := make(map[string]interface{}) + rowMap := make(map[string]any) for i, colName := range cols { val := columns[i] if b, ok := val.([]byte); ok { diff --git a/internal/apps/admin/logs/utils.go b/internal/apps/admin/logs/utils.go index 3c93edcc..20349679 100644 --- a/internal/apps/admin/logs/utils.go +++ b/internal/apps/admin/logs/utils.go @@ -35,8 +35,8 @@ func getUpgrader() *websocket.Upgrader { ctx := r.Context() if sc, err := repository.GetSystemConfigByKey(ctx, model.ConfigKeyServerAddress); err == nil && sc.Value != "" { originToCheck := strings.TrimRight(strings.TrimSpace(origin), "/") - allowedOrigins := strings.Split(sc.Value, ",") - for _, allowed := range allowedOrigins { + allowedOrigins := strings.SplitSeq(sc.Value, ",") + for allowed := range allowedOrigins { allowed = strings.TrimRight(strings.TrimSpace(allowed), "/") if allowed != "" && strings.EqualFold(allowed, originToCheck) { return true diff --git a/internal/apps/admin/push/channels_definition.go b/internal/apps/admin/push/channels_definition.go index 0d810569..ad5d0134 100644 --- a/internal/apps/admin/push/channels_definition.go +++ b/internal/apps/admin/push/channels_definition.go @@ -3,6 +3,8 @@ package push +import "slices" + import "sync" const ( @@ -66,13 +68,7 @@ func ListDefinitions() []Definition { } // Add any others for t, d := range definitions { - found := false - for _, o := range order { - if o == t { - found = true - break - } - } + found := slices.Contains(order, t) if !found { res = append(res, d) } diff --git a/internal/apps/admin/push/events.go b/internal/apps/admin/push/events.go index 6cc26bc2..ca5687c2 100644 --- a/internal/apps/admin/push/events.go +++ b/internal/apps/admin/push/events.go @@ -9,6 +9,7 @@ import ( "encoding/json" "errors" "fmt" + "maps" "strings" "github.com/Rain-kl/Wavelet/internal/infra/task" @@ -34,9 +35,7 @@ func (m NotificationMessage) Flatten() map[string]any { keyContent: m.Content, keyLevel: m.Level, } - for k, v := range m.Ext { - res[k] = v - } + maps.Copy(res, m.Ext) return res } diff --git a/internal/apps/admin/updater/logics.go b/internal/apps/admin/updater/logics.go index 0fe32b6a..df2ea282 100644 --- a/internal/apps/admin/updater/logics.go +++ b/internal/apps/admin/updater/logics.go @@ -17,6 +17,7 @@ import ( "os" "path/filepath" "runtime" + "slices" "strings" "sync" "time" @@ -163,13 +164,7 @@ func selectLatestRelease(repository string, releases []githubRelease) (githubRel } expectedNames := expectedAssetNames(repository, release.TagName) for _, asset := range release.Assets { - matched := false - for _, name := range expectedNames { - if asset.Name == name { - matched = true - break - } - } + matched := slices.Contains(expectedNames, asset.Name) if !matched || asset.BrowserDownloadURL == "" || asset.State != "uploaded" { continue } @@ -348,10 +343,8 @@ func getCandidateBinaryNames(executable string, repository string) []string { if runtime.GOOS == windowsOS && !strings.HasSuffix(strings.ToLower(name), ".exe") { name += ".exe" } - for _, existing := range names { - if existing == name { - return - } + if slices.Contains(names, name) { + return } names = append(names, name) } diff --git a/internal/apps/admin/user/routers.go b/internal/apps/admin/user/routers.go index c4009424..321bb817 100644 --- a/internal/apps/admin/user/routers.go +++ b/internal/apps/admin/user/routers.go @@ -7,6 +7,7 @@ package user import ( "errors" "net/http" + "slices" "strconv" "time" @@ -93,17 +94,13 @@ func abortUserLogicError(c *gin.Context, err error, notFoundMsg string, forbidde return true } msg := err.Error() - for _, m := range badRequestMsgs { - if msg == m { - response.AbortBadRequest(c, msg) - return true - } + if slices.Contains(badRequestMsgs, msg) { + response.AbortBadRequest(c, msg) + return true } - for _, m := range forbiddenMsgs { - if msg == m { - response.AbortForbidden(c, msg) - return true - } + if slices.Contains(forbiddenMsgs, msg) { + response.AbortForbidden(c, msg) + return true } logger.ErrorF(c.Request.Context(), "Admin user error: %v", err) response.AbortInternal(c, "内部服务器错误") diff --git a/internal/apps/agent/runtimeuser/runtimeuser.go b/internal/apps/agent/runtimeuser/runtimeuser.go index bf8e43a0..7a4089f0 100644 --- a/internal/apps/agent/runtimeuser/runtimeuser.go +++ b/internal/apps/agent/runtimeuser/runtimeuser.go @@ -120,7 +120,7 @@ func ensureWorldTraversablePath(targetDir string) error { if current == "" || current == "." { return nil } - for depth := 0; depth < maxDepth; depth++ { + for range maxDepth { if err := os.Chmod(current, DefaultDirPerm); err != nil { //nolint:gosec // parent dirs must be traversable by the runtime user if os.IsNotExist(err) || os.IsPermission(err) { break diff --git a/internal/apps/agent/sync/pages.go b/internal/apps/agent/sync/pages.go index 5364ec4d..f2c64fc1 100644 --- a/internal/apps/agent/sync/pages.go +++ b/internal/apps/agent/sync/pages.go @@ -198,7 +198,7 @@ func (s *Service) ensurePagesProject(ctx context.Context, snapshot *state.Snapsh } var lastErr error - for attempt := 0; attempt < pagesLatestPullAttempts; attempt++ { + for attempt := range pagesLatestPullAttempts { latest, err := s.client.GetPagesProjectLatestHash(ctx, projectID) if err != nil { return fmt.Errorf("fetch Pages project %d latest hash: %w", projectID, err) @@ -359,10 +359,7 @@ func validatePagesPackageMetadata( if extractedBytes == 0 { extractedBytes = 1 } - maxFileBytes := extractedBytes - if maxFileBytes > agentPagesMaxFileBytes { - maxFileBytes = agentPagesMaxFileBytes - } + maxFileBytes := min(extractedBytes, agentPagesMaxFileBytes) return pagesPackageLimits{ PackageBytes: metadata.PackageSize, diff --git a/internal/apps/agent/sync/service.go b/internal/apps/agent/sync/service.go index 8798d35e..47b04d13 100644 --- a/internal/apps/agent/sync/service.go +++ b/internal/apps/agent/sync/service.go @@ -12,7 +12,7 @@ import ( "fmt" "io" "log/slog" - "sort" + "slices" "strconv" "strings" "sync" @@ -363,7 +363,7 @@ func referencedWAFIPGroupIDs(supportFiles []protocol.SupportFile) ([]uint, error for id := range seen { ids = append(ids, id) } - sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] }) + slices.Sort(ids) return ids, nil } diff --git a/internal/apps/cap/manager.go b/internal/apps/cap/manager.go index b99fff24..474993c1 100644 --- a/internal/apps/cap/manager.go +++ b/internal/apps/cap/manager.go @@ -78,10 +78,7 @@ func (m *Manager) Redeem(ctx context.Context, token string, solutions []int, sco } now := time.Now().UnixNano() / int64(time.Millisecond) - nonceTTL := time.Duration(payload.Expires-now) * time.Millisecond - if nonceTTL < time.Second { - nonceTTL = time.Second - } + nonceTTL := max(time.Duration(payload.Expires-now)*time.Millisecond, time.Second) set, err := m.store.SetNX(ctx, nonceKey, "1", nonceTTL) if err != nil { diff --git a/internal/apps/edge/observability/linux.go b/internal/apps/edge/observability/linux.go index 483f37ba..64c86fa4 100644 --- a/internal/apps/edge/observability/linux.go +++ b/internal/apps/edge/observability/linux.go @@ -96,10 +96,7 @@ func ReadMemInfo() (int64, int64) { if total == 0 { return 0, 0 } - used := total - (memAvailableKB * 1024) - if used < 0 { - used = 0 - } + used := max(total-(memAvailableKB*1024), 0) return total, used } @@ -138,8 +135,8 @@ func ReadLinuxCPUStat() (uint64, uint64) { if err != nil { return 0, 0 } - lines := strings.Split(string(content), "\n") - for _, line := range lines { + lines := strings.SplitSeq(string(content), "\n") + for line := range lines { if !strings.HasPrefix(line, "cpu ") { continue } @@ -260,10 +257,7 @@ func StatFilesystem(path string) (int64, int64) { } total := multiplyUint64Int64(stat.Blocks, stat.Bsize) free := multiplyUint64Int64(stat.Bavail, stat.Bsize) - used := total - free - if used < 0 { - used = 0 - } + used := max(total-free, 0) return total, used } diff --git a/internal/apps/edge/updater/service.go b/internal/apps/edge/updater/service.go index 86833883..cf38a824 100644 --- a/internal/apps/edge/updater/service.go +++ b/internal/apps/edge/updater/service.go @@ -285,7 +285,7 @@ func (s *Service) downloadChecksum(ctx context.Context, url string, assetName st func parseSHA256Checksum(content string, assetName string) (string, error) { assetName = strings.TrimSpace(assetName) - for _, line := range strings.Split(content, "\n") { + for line := range strings.SplitSeq(content, "\n") { line = strings.TrimSpace(line) if line == "" || strings.HasPrefix(line, "#") { continue diff --git a/internal/apps/flared/frpc/manager.go b/internal/apps/flared/frpc/manager.go index 2b0c9598..c74f7bf9 100644 --- a/internal/apps/flared/frpc/manager.go +++ b/internal/apps/flared/frpc/manager.go @@ -203,7 +203,7 @@ func (m *Manager) restartProcess(ctx context.Context, relayID string, configPath startedAt := time.Now() err := cmd.Start() if err == nil { - _ = os.WriteFile(pidPath, []byte(fmt.Sprintf("%d", cmd.Process.Pid)), frpcConfigFilePerm) + _ = os.WriteFile(pidPath, fmt.Appendf(nil, "%d", cmd.Process.Pid), frpcConfigFilePerm) err = cmd.Wait() } _ = os.Remove(pidPath) diff --git a/internal/apps/oauth/auth_source_resolver.go b/internal/apps/oauth/auth_source_resolver.go index e996c4be..306ad5c2 100644 --- a/internal/apps/oauth/auth_source_resolver.go +++ b/internal/apps/oauth/auth_source_resolver.go @@ -6,6 +6,7 @@ package oauth import ( "context" "errors" + "slices" "strings" "github.com/Rain-kl/Wavelet/internal/model" @@ -109,10 +110,5 @@ func buildOAuthConfig(ctx context.Context, source *model.AuthSource, redirectURL } func containsScope(scopes []string, scope string) bool { - for _, item := range scopes { - if item == scope { - return true - } - } - return false + return slices.Contains(scopes, scope) } diff --git a/internal/apps/openflare/agent/observability.go b/internal/apps/openflare/agent/observability.go index 0b81b633..0e6cf8ac 100644 --- a/internal/apps/openflare/agent/observability.go +++ b/internal/apps/openflare/agent/observability.go @@ -179,18 +179,9 @@ func buildNodeAccessLogRecords(nodeID string, direct []NodeAccessLog, buffered [ records := make([]*model.OpenFlareAccessLog, 0, total) appendLogs := func(logs []NodeAccessLog) { for _, item := range logs { - bytesSent := item.BytesSent - if bytesSent < 0 { - bytesSent = 0 - } - requestLength := item.RequestLength - if requestLength < 0 { - requestLength = 0 - } - requestTimeMs := item.RequestTimeMs - if requestTimeMs < 0 { - requestTimeMs = 0 - } + bytesSent := max(item.BytesSent, 0) + requestLength := max(item.RequestLength, 0) + requestTimeMs := max(item.RequestTimeMs, 0) record := &model.OpenFlareAccessLog{ NodeID: nodeID, LoggedAt: timeFromUnix(item.LoggedAtUnix, reportedAt), diff --git a/internal/apps/openflare/agent/waf_ip_group.go b/internal/apps/openflare/agent/waf_ip_group.go index af0de03b..73167d23 100644 --- a/internal/apps/openflare/agent/waf_ip_group.go +++ b/internal/apps/openflare/agent/waf_ip_group.go @@ -11,6 +11,7 @@ import ( "encoding/json" "errors" "fmt" + "slices" "sort" "strconv" "strings" @@ -97,7 +98,7 @@ func buildAgentWAFIPGroups(ctx context.Context, ids []uint) ([]WAFIPGroup, error if len(ids) == 0 { return []WAFIPGroup{}, nil } - sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] }) + slices.Sort(ids) groups, err := repository.ListOpenFlareWAFIPGroupsByIDs(ctx, ids) if err != nil { return nil, err @@ -204,7 +205,7 @@ func activeConfigWAFIPGroupIDs(ctx context.Context) ([]uint, error) { for id := range idSet { ids = append(ids, id) } - sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] }) + slices.Sort(ids) return ids, nil } diff --git a/internal/apps/openflare/cloudflare/client.go b/internal/apps/openflare/cloudflare/client.go index 4190bd7d..0d141cc1 100644 --- a/internal/apps/openflare/cloudflare/client.go +++ b/internal/apps/openflare/cloudflare/client.go @@ -192,7 +192,7 @@ func (client *HTTPClient) do(ctx context.Context, method, path string, query url return err } requestURL := buildRequestURL(client.baseURL, path, query) - for attempt := 0; attempt < maxRequestAttempts; attempt++ { + for attempt := range maxRequestAttempts { statusCode, retryHeader, responseBody, requestErr := client.send(ctx, method, requestURL, encodedBody) if requestErr != nil { return requestErr diff --git a/internal/apps/openflare/config_version/snapshot.go b/internal/apps/openflare/config_version/snapshot.go index 9a86b867..a72947b5 100644 --- a/internal/apps/openflare/config_version/snapshot.go +++ b/internal/apps/openflare/config_version/snapshot.go @@ -8,6 +8,7 @@ import ( "encoding/json" "errors" "fmt" + "slices" "sort" "strconv" "strings" @@ -429,7 +430,7 @@ func buildSnapshotWAFIPGroups(ctx context.Context, idSet map[uint]struct{}) ([]s for id := range idSet { ids = append(ids, id) } - sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] }) + slices.Sort(ids) groups, err := listWAFIPGroupsByIDs(ctx, ids) if err != nil { return nil, err @@ -629,7 +630,7 @@ func buildCertificateSupportFiles(ctx context.Context, routes []snapshotRoute) ( for certID := range certIDSet { certIDs = append(certIDs, certID) } - sort.Slice(certIDs, func(i, j int) bool { return certIDs[i] < certIDs[j] }) + slices.Sort(certIDs) files := make([]SupportFile, 0, len(certIDs)*supportFilesPerCertificate) for _, certID := range certIDs { certificate, err := repository.GetTLSCertificateByID(ctx, certID) diff --git a/internal/apps/openflare/option/openresty_validators.go b/internal/apps/openflare/option/openresty_validators.go index dddcd475..493db502 100644 --- a/internal/apps/openflare/option/openresty_validators.go +++ b/internal/apps/openflare/option/openresty_validators.go @@ -189,7 +189,7 @@ func validateOpenRestyCacheUseStale(key, trimmed string) error { "http_500": {}, "http_502": {}, "http_503": {}, "http_504": {}, "http_403": {}, "http_404": {}, "http_429": {}, "off": {}, } - for _, token := range strings.Fields(trimmed) { + for token := range strings.FieldsSeq(trimmed) { if _, ok := allowedTokens[token]; !ok { return fmt.Errorf("%s 包含不支持的值 %q", key, token) } diff --git a/internal/apps/openflare/origin/helpers.go b/internal/apps/openflare/origin/helpers.go index 7638da96..c7f6cae5 100644 --- a/internal/apps/openflare/origin/helpers.go +++ b/internal/apps/openflare/origin/helpers.go @@ -34,8 +34,8 @@ func validateOriginAddress(address string) error { if len(address) > maxOriginHostnameLength { return errors.New(errOriginAddressInvalid) } - labels := strings.Split(address, ".") - for _, label := range labels { + labels := strings.SplitSeq(address, ".") + for label := range labels { if len(label) == 0 || len(label) > 63 { return errors.New(errOriginAddressInvalid) } diff --git a/internal/apps/openflare/pages/helpers.go b/internal/apps/openflare/pages/helpers.go index 8e017ea2..d592e32c 100644 --- a/internal/apps/openflare/pages/helpers.go +++ b/internal/apps/openflare/pages/helpers.go @@ -80,18 +80,11 @@ func resolvePagesLimits(ctx context.Context) pagesLimits { historyCount := defaultPagesMaxHistoryCount if value, err := repository.GetIntByKey(ctx, model.ConfigKeyPagesMaxHistoryCount); err == nil { - if value < 0 { - historyCount = 0 - } else { - historyCount = value - } + historyCount = max(value, 0) } packageBytes := int64(packageMB) * bytesPerMiB - extractedBytes := packageBytes * pagesExtractedSizeMultiplier - if extractedBytes < pagesMinExtractedSizeBytes { - extractedBytes = pagesMinExtractedSizeBytes - } + extractedBytes := max(packageBytes*pagesExtractedSizeMultiplier, pagesMinExtractedSizeBytes) return pagesLimits{ PackageBytes: packageBytes, @@ -154,7 +147,7 @@ func normalizePagesFallbackPath(raw string) (string, error) { return "", errors.New("spa fallback 回退路径不能包含空白或控制字符") } } - for _, segment := range strings.Split(value, "/") { + for segment := range strings.SplitSeq(value, "/") { if segment == "." || segment == ".." { return "", errors.New("spa fallback 回退路径不能包含 . 或 .. 路径段") } diff --git a/internal/apps/openflare/pages/logics.go b/internal/apps/openflare/pages/logics.go index 007aeeaa..57cdf7f7 100644 --- a/internal/apps/openflare/pages/logics.go +++ b/internal/apps/openflare/pages/logics.go @@ -513,7 +513,7 @@ func pruneProjectDeploymentHistory(ctx context.Context, projectID uint, keepCoun // Two passes: first pass after upload, second pass heals a concurrent race // that inserted another deployment between our list and delete. var lastErr error - for pass := 0; pass < 2; pass++ { + for range 2 { deleted, err := pruneProjectDeploymentHistoryOnce(ctx, projectID, keepCount, preserveCandidateID) if err != nil { lastErr = err diff --git a/internal/apps/openflare/pages/source_sync.go b/internal/apps/openflare/pages/source_sync.go index 68293777..117ebaf2 100644 --- a/internal/apps/openflare/pages/source_sync.go +++ b/internal/apps/openflare/pages/source_sync.go @@ -9,7 +9,7 @@ import ( "errors" "fmt" "path" - "sort" + "slices" "strings" "sync" "time" @@ -611,7 +611,7 @@ func lockSourceDeploymentUploadsTx( if hasIngest && ingestResult.Upload.ID != 0 && ingestResult.Upload.ID != target.UploadID { uploadIDs = append(uploadIDs, ingestResult.Upload.ID) } - sort.Slice(uploadIDs, func(i, j int) bool { return uploadIDs[i] < uploadIDs[j] }) + slices.Sort(uploadIDs) var records []model.Upload if err := tx.Clauses(clause.Locking{Strength: pagesRowLockStrength}). Where("id IN ?", uploadIDs). diff --git a/internal/apps/openflare/proxy_route/helpers.go b/internal/apps/openflare/proxy_route/helpers.go index e5f07a4a..98418483 100644 --- a/internal/apps/openflare/proxy_route/helpers.go +++ b/internal/apps/openflare/proxy_route/helpers.go @@ -86,8 +86,8 @@ func validateOriginAddress(address string) error { if len(address) > maxOriginHostnameLength { return errors.New(errProxyRouteOriginInvalid) } - labels := strings.Split(address, ".") - for _, label := range labels { + labels := strings.SplitSeq(address, ".") + for label := range labels { if len(label) == 0 || len(label) > 63 { return errors.New(errProxyRouteOriginInvalid) } @@ -167,8 +167,8 @@ func buildOriginURLFromParts(scheme, address, port, uri string) (string, error) Host: formatOriginHost(normalizedAddress, normalizedPort), } if normalizedURI != "" { - if strings.HasPrefix(normalizedURI, "?") { - parsed.RawQuery = strings.TrimPrefix(normalizedURI, "?") + if after, ok := strings.CutPrefix(normalizedURI, "?"); ok { + parsed.RawQuery = after } else { pathQuery := strings.SplitN(normalizedURI, "?", originURIPathQueryParts) parsed.Path = pathQuery[0] diff --git a/internal/apps/openflare/proxy_route/logics.go b/internal/apps/openflare/proxy_route/logics.go index f4890e3b..60a99fc7 100644 --- a/internal/apps/openflare/proxy_route/logics.go +++ b/internal/apps/openflare/proxy_route/logics.go @@ -6,7 +6,7 @@ package proxy_route import ( "context" "errors" - "sort" + "slices" "strings" "time" @@ -201,7 +201,7 @@ func lockPagesProjectsForRouteMutation(tx *gorm.DB, previousProjectID uint, rout if nextProjectID != 0 && nextProjectID != previousProjectID { projectIDs = append(projectIDs, nextProjectID) } - sort.Slice(projectIDs, func(i int, j int) bool { return projectIDs[i] < projectIDs[j] }) + slices.Sort(projectIDs) for _, projectID := range projectIDs { project, err := repository.LockPagesProjectByIDTx(tx, projectID) diff --git a/internal/apps/openflare/tls/obtain.go b/internal/apps/openflare/tls/obtain.go index 266c72dc..89c0a0f7 100644 --- a/internal/apps/openflare/tls/obtain.go +++ b/internal/apps/openflare/tls/obtain.go @@ -123,7 +123,7 @@ func splitAcmeDomains(primaryDomain, otherDomains string) []string { if !strings.Contains(otherDomains, "\n") && strings.Contains(otherDomains, ",") { separator = "," } - for _, domain := range strings.Split(otherDomains, separator) { + for domain := range strings.SplitSeq(otherDomains, separator) { domain = strings.TrimSpace(domain) if domain != "" { domains = append(domains, domain) diff --git a/internal/apps/openflare/uptimekuma/client.go b/internal/apps/openflare/uptimekuma/client.go index 14f182c5..0d1bbdc0 100644 --- a/internal/apps/openflare/uptimekuma/client.go +++ b/internal/apps/openflare/uptimekuma/client.go @@ -10,6 +10,7 @@ import ( "fmt" "io" "log/slog" + "maps" "net/http" "strconv" "strings" @@ -180,8 +181,8 @@ func (c *SocketIOClient) pollLoop() { } slog.Debug("Received polling payload from Uptime Kuma", "length", len(bodyStr)) - packets := strings.Split(bodyStr, "\x1e") - for _, pkt := range packets { + packets := strings.SplitSeq(bodyStr, "\x1e") + for pkt := range packets { if len(pkt) == 0 { continue } @@ -352,9 +353,7 @@ func (c *SocketIOClient) GetMonitorList() map[string]Monitor { defer c.monitorListMutex.RUnlock() m := make(map[string]Monitor, len(c.monitorList)) - for k, v := range c.monitorList { - m[k] = v - } + maps.Copy(m, c.monitorList) return m } diff --git a/internal/apps/openflare/waf/graph_compile.go b/internal/apps/openflare/waf/graph_compile.go index 42223630..20b970f7 100644 --- a/internal/apps/openflare/waf/graph_compile.go +++ b/internal/apps/openflare/waf/graph_compile.go @@ -5,6 +5,7 @@ package waf import ( "fmt" + "slices" "sort" ) @@ -142,7 +143,7 @@ func sortedUniqueStrings(values []string) []string { func sortedUniqueUints(values []uint) []uint { result := append([]uint(nil), values...) - sort.Slice(result, func(i, j int) bool { return result[i] < result[j] }) + slices.Sort(result) write := 0 for _, value := range result { if write == 0 || result[write-1] != value { diff --git a/internal/apps/openflare/waf/graph_validate.go b/internal/apps/openflare/waf/graph_validate.go index ddab7fef..1025f8ec 100644 --- a/internal/apps/openflare/waf/graph_validate.go +++ b/internal/apps/openflare/waf/graph_validate.go @@ -12,6 +12,7 @@ import ( "io" "net/netip" "regexp" + "slices" "strings" ) @@ -374,12 +375,7 @@ func decodeStrictConfig(raw json.RawMessage, dst any) error { } func validSourceHandle(t RuleNodeType, handle string) bool { - for _, expected := range requiredHandles(t) { - if handle == expected { - return true - } - } - return false + return slices.Contains(requiredHandles(t), handle) } func requiredHandles(t RuleNodeType) []string { switch t { diff --git a/internal/apps/openflare/waf/ip_group_sync.go b/internal/apps/openflare/waf/ip_group_sync.go index 1016b556..3a2e706b 100644 --- a/internal/apps/openflare/waf/ip_group_sync.go +++ b/internal/apps/openflare/waf/ip_group_sync.go @@ -11,6 +11,7 @@ import ( "fmt" "io" "log/slog" + "maps" "net" "net/http" "net/netip" @@ -325,9 +326,7 @@ func evaluateParsedIPGroupAutoConfig(ctx context.Context, config ipGroupAutoConf lastSeen = time.Unix(item.LastSeenEpoch, 0).UTC() } statusCounts := make(map[int]int, len(item.StatusCounts)) - for code, count := range item.StatusCounts { - statusCounts[code] = count - } + maps.Copy(statusCounts, item.StatusCounts) accumulators[ip] = &ipGroupAutoAccumulator{ ip: ip, requestCount: item.RequestCount, @@ -479,7 +478,7 @@ func selectJSONMappingNodes(payload any, mappingRule string) ([]any, error) { } rule = strings.TrimPrefix(rule, "$.") nodes := []any{payload} - for _, rawSegment := range strings.Split(rule, ".") { + for rawSegment := range strings.SplitSeq(rule, ".") { segment := strings.TrimSpace(rawSegment) if segment == "" { continue diff --git a/internal/apps/openflare/zone/stats.go b/internal/apps/openflare/zone/stats.go index 6a5dcfc9..002b0abe 100644 --- a/internal/apps/openflare/zone/stats.go +++ b/internal/apps/openflare/zone/stats.go @@ -183,10 +183,7 @@ func emptyStatsSeries(since, until time.Time, bucketMinutes int) []StatsPoint { } // Cap points to keep chart readable. maxPoints := 120 - capacity := int(end.Sub(start)/bucket) + 1 - if capacity > maxPoints { - capacity = maxPoints - } + capacity := min(int(end.Sub(start)/bucket)+1, maxPoints) points := make([]StatsPoint, 0, capacity) for cursor := start; !cursor.After(end) && len(points) < maxPoints; cursor = cursor.Add(bucket) { points = append(points, StatsPoint{BucketStartedAt: cursor}) diff --git a/internal/apps/relay/frps/manager.go b/internal/apps/relay/frps/manager.go index 0c9a5e92..929ba08c 100644 --- a/internal/apps/relay/frps/manager.go +++ b/internal/apps/relay/frps/manager.go @@ -240,7 +240,7 @@ func (m *Manager) supervise(ctx context.Context, generation uint64) { continue } - _ = os.WriteFile(m.pidPath, []byte(fmt.Sprintf("%d", cmd.Process.Pid)), frpsPidFilePerm) + _ = os.WriteFile(m.pidPath, fmt.Appendf(nil, "%d", cmd.Process.Pid), frpsPidFilePerm) m.cmd = cmd m.status = "healthy" diff --git a/internal/apps/upload/ingest/helpers.go b/internal/apps/upload/ingest/helpers.go index 5905bbf4..175e6abe 100644 --- a/internal/apps/upload/ingest/helpers.go +++ b/internal/apps/upload/ingest/helpers.go @@ -59,8 +59,8 @@ func validateAllowedExtension(ctx context.Context, ext string) error { return nil } - allowedExts := strings.Split(strings.ToLower(sc.Value), ",") - for _, allowedExt := range allowedExts { + allowedExts := strings.SplitSeq(strings.ToLower(sc.Value), ",") + for allowedExt := range allowedExts { if strings.TrimSpace(allowedExt) == ext { return nil } diff --git a/internal/apps/upload/task/storage_migration.go b/internal/apps/upload/task/storage_migration.go index 616d2d56..dd5746f8 100644 --- a/internal/apps/upload/task/storage_migration.go +++ b/internal/apps/upload/task/storage_migration.go @@ -193,18 +193,18 @@ func migrateObjects( const batchSize = 50 const migrationConcurrency = 10 const sha256HexLength = 64 - var migrated int64 + var migrated atomic.Int64 var lastFilePath string for { if err := ctx.Err(); err != nil { - return atomic.LoadInt64(&migrated), fmt.Errorf("storage migration canceled: %w", err) + return migrated.Load(), fmt.Errorf("storage migration canceled: %w", err) } - task.AppendLog(ctx, "正在查询待迁移对象批次,当前已完成迁移: %d/%d", atomic.LoadInt64(&migrated), total) + task.AppendLog(ctx, "正在查询待迁移对象批次,当前已完成迁移: %d/%d", migrated.Load(), total) objects, err := repository.ListDistinctActiveStorageObjects(ctx, lastFilePath, batchSize) if err != nil { - return atomic.LoadInt64(&migrated), fmt.Errorf("query source objects: %w", err) + return migrated.Load(), fmt.Errorf("query source objects: %w", err) } if len(objects) == 0 { task.AppendLog(ctx, "所有对象迁移完毕") @@ -223,18 +223,18 @@ func migrateObjects( if err := migrateSingleObject(ctx, sourceBackend, targetBackend, obj, sha256HexLength); err != nil { return err } - atomic.AddInt64(&migrated, 1) + migrated.Add(1) return nil }) } if err := g.Wait(); err != nil { - return atomic.LoadInt64(&migrated), err + return migrated.Load(), err } - task.AppendLog(ctx, "当前批次迁移完成。迁移进度: %d/%d", atomic.LoadInt64(&migrated), total) + task.AppendLog(ctx, "当前批次迁移完成。迁移进度: %d/%d", migrated.Load(), total) } - return atomic.LoadInt64(&migrated), nil + return migrated.Load(), nil } func migrateSingleObject( diff --git a/internal/apps/upload/util/media.go b/internal/apps/upload/util/media.go index eba2d864..c712afae 100644 --- a/internal/apps/upload/util/media.go +++ b/internal/apps/upload/util/media.go @@ -4,6 +4,7 @@ package util import ( + "slices" "strings" "github.com/Rain-kl/Wavelet/internal/apps/upload/shared" @@ -11,32 +12,17 @@ import ( // IsImageExtension reports whether ext is a common image format. func IsImageExtension(ext string) bool { - for _, imgExt := range []string{"jpg", "jpeg", "png", "webp", "gif"} { - if ext == imgExt { - return true - } - } - return false + return slices.Contains([]string{"jpg", "jpeg", "png", "webp", "gif"}, ext) } // IsArchiveExtension reports whether ext is a common archive format. func IsArchiveExtension(ext string) bool { - for _, e := range []string{"zip", "rar", "7z", "tar", "gz", "tgz", "bz2", "xz"} { - if ext == e { - return true - } - } - return false + return slices.Contains([]string{"zip", "rar", "7z", "tar", "gz", "tgz", "bz2", "xz"}, ext) } // IsDocumentExtension reports whether ext is a common document format. func IsDocumentExtension(ext string) bool { - for _, e := range []string{"pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "md", "csv", "json", "yaml", "yml", "xml"} { - if ext == e { - return true - } - } - return false + return slices.Contains([]string{"pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "md", "csv", "json", "yaml", "yml", "xml"}, ext) } // NormalizeImageQuality normalizes the requested image quality query parameter. diff --git a/internal/cmd/all.go b/internal/cmd/all.go index db7f0799..9da6e689 100644 --- a/internal/cmd/all.go +++ b/internal/cmd/all.go @@ -27,34 +27,28 @@ var allCmd = &cobra.Command{ var wg sync.WaitGroup // 启动 API HTTP 服务 - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { log.Println("[All] 启动 API 服务") router.Serve(func() { printStartupBanner(startupState{mode: "API + Worker + Scheduler", relationalDB: latestMigrationState.relationalDB, clickHouseDB: latestMigrationState.clickHouseDB, listensForHTTP: true}) }) - }() + }) // 启动 Asynq Worker 任务处理服务 - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { log.Println("[All] 启动 Worker 服务") if err := worker.StartWorker(); err != nil { log.Printf("[All] Worker 启动失败: %v\n", err) } - }() + }) // 启动 Asynq 定时任务调度器 - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { log.Println("[All] 启动 Scheduler 服务") if err := scheduler.StartScheduler(); err != nil { log.Printf("[All] Scheduler 启动失败: %v\n", err) } - }() + }) wg.Wait() }, diff --git a/internal/infra/config/config.go b/internal/infra/config/config.go index 9a0b040a..dadc416f 100644 --- a/internal/infra/config/config.go +++ b/internal/infra/config/config.go @@ -31,10 +31,11 @@ func findConfigPath(configPath string) string { if _, err := os.Stat(configPath); err == nil { return configPath } - dir := "." - for i := 0; i < 5; i++ { - dir += "/.." - path := dir + "/" + configPath + var dir strings.Builder + dir.WriteString(".") + for range 5 { + dir.WriteString("/..") + path := dir.String() + "/" + configPath if _, err := os.Stat(path); err == nil { return path } diff --git a/internal/infra/persistence/postgres_logger.go b/internal/infra/persistence/postgres_logger.go index 2ba1433c..d7398daf 100644 --- a/internal/infra/persistence/postgres_logger.go +++ b/internal/infra/persistence/postgres_logger.go @@ -31,26 +31,26 @@ func (l *gormZapLogger) LogMode(level gormLogger.LogLevel) gormLogger.Interface return &clone } -func (l *gormZapLogger) Info(ctx context.Context, fmt string, args ...interface{}) { +func (l *gormZapLogger) Info(ctx context.Context, fmt string, args ...any) { if l.logLevel >= gormLogger.Info { logger.InfoF(ctx, fmt, args...) } } -func (l *gormZapLogger) Warn(ctx context.Context, fmt string, args ...interface{}) { +func (l *gormZapLogger) Warn(ctx context.Context, fmt string, args ...any) { if l.logLevel >= gormLogger.Warn { logger.WarnF(ctx, fmt, args...) } } -func (l *gormZapLogger) Error(ctx context.Context, fmt string, args ...interface{}) { +func (l *gormZapLogger) Error(ctx context.Context, fmt string, args ...any) { if l.logLevel >= gormLogger.Error { logger.ErrorF(ctx, fmt, args...) } } // ParamsFilter 让 GORM 的 Trace 回调只接收参数化 SQL,避免绑定值被 Dialector.Explain 展开到日志。 -func (l *gormZapLogger) ParamsFilter(_ context.Context, sql string, _ ...interface{}) (string, []interface{}) { +func (l *gormZapLogger) ParamsFilter(_ context.Context, sql string, _ ...any) (string, []any) { return sql, nil } @@ -70,7 +70,7 @@ func (l *gormZapLogger) Trace(ctx context.Context, begin time.Time, fc func() (s } } -func formatRows(rows int64) interface{} { +func formatRows(rows int64) any { if rows == -1 { return "-" } diff --git a/internal/infra/task/executor.go b/internal/infra/task/executor.go index c8dfac41..89ef029f 100644 --- a/internal/infra/task/executor.go +++ b/internal/infra/task/executor.go @@ -103,7 +103,7 @@ func IsFinalAttempt(ctx context.Context) bool { // AppendLog 追加日志到任务执行记录 // 在 TaskHandler.Execute 中调用,日志会自动追加到 TaskExecution.Log 字段 -func AppendLog(ctx context.Context, format string, args ...interface{}) { +func AppendLog(ctx context.Context, format string, args ...any) { taskID := GetTaskID(ctx) if taskID == "" { // 上下文中没有 taskID,降级到普通日志 diff --git a/internal/infra/task/utils.go b/internal/infra/task/utils.go index d5afa098..5c409aae 100644 --- a/internal/infra/task/utils.go +++ b/internal/infra/task/utils.go @@ -15,7 +15,7 @@ type redisClientConnOpt struct { options redis.Options } -func (opt redisClientConnOpt) MakeRedisClient() interface{} { +func (opt redisClientConnOpt) MakeRedisClient() any { return redis.NewClient(&opt.options) } @@ -23,7 +23,7 @@ type redisClusterConnOpt struct { options redis.ClusterOptions } -func (opt redisClusterConnOpt) MakeRedisClient() interface{} { +func (opt redisClusterConnOpt) MakeRedisClient() any { return redis.NewClusterClient(&opt.options) } @@ -32,7 +32,7 @@ type redisFailoverConnOpt struct { maintNotificationsEnabled bool } -func (opt redisFailoverConnOpt) MakeRedisClient() interface{} { +func (opt redisFailoverConnOpt) MakeRedisClient() any { client := redis.NewFailoverClient(&opt.options) // go-redis v9.16 does not expose maintenance notification settings on // FailoverOptions, so apply the configured mode before the client is used. diff --git a/internal/repository/analytics/node_observability.go b/internal/repository/analytics/node_observability.go index 2c9ec39c..3fba630b 100644 --- a/internal/repository/analytics/node_observability.go +++ b/internal/repository/analytics/node_observability.go @@ -6,7 +6,7 @@ package analytics import ( "context" "fmt" - "sort" + "slices" "time" "github.com/ClickHouse/clickhouse-go/v2/lib/driver" @@ -367,7 +367,7 @@ func mergeNodeMetricHourlyPreferRollup(rollup, raw []NodeMetricHourly) []NodeMet } result := make([]NodeMetricHourly, 0, len(order)) // Keep chronological order of first-seen keys; re-sort by hour for stability. - sort.Slice(order, func(i, j int) bool { return order[i] < order[j] }) + slices.Sort(order) for _, key := range order { result = append(result, byHour[key]) } diff --git a/internal/repository/openflare_access_log.go b/internal/repository/openflare_access_log.go index b5ac1ca1..0c6d177a 100644 --- a/internal/repository/openflare_access_log.go +++ b/internal/repository/openflare_access_log.go @@ -418,14 +418,8 @@ func openFlareAccessLogPaginateBounds(total int, page int, pageSize int) (int, i if pageSize <= 0 { return 0, total } - start := page * pageSize - if start > total { - start = total - } - end := start + pageSize - if end > total { - end = total - } + start := min(page*pageSize, total) + end := min(start+pageSize, total) return start, end } diff --git a/internal/router/middlewares.go b/internal/router/middlewares.go index 58a2389b..b32c10a2 100644 --- a/internal/router/middlewares.go +++ b/internal/router/middlewares.go @@ -63,7 +63,7 @@ func loggerMiddleware() gin.HandlerFunc { func logRequest(ctx context.Context, c *gin.Context, path string, start, end time.Time, latency time.Duration) { format := "[LoggerMiddleware] %s %s\nStartTime: %s\nEndTime: %s\nLatency: %d\nClientIP: %s\nResponse: %d %d" - args := []interface{}{ + args := []any{ c.Request.Method, path, start.Format(time.RFC3339), @@ -89,8 +89,8 @@ func isOriginAllowed(ctx context.Context, origin string) bool { if err != nil || sc.Value == "" { return false } - allowedOrigins := strings.Split(sc.Value, ",") - for _, allowed := range allowedOrigins { + allowedOrigins := strings.SplitSeq(sc.Value, ",") + for allowed := range allowedOrigins { allowed = strings.TrimRight(strings.TrimSpace(allowed), "/") if allowed != "" && strings.EqualFold(allowed, origin) { return true diff --git a/internal/shared/response/response.go b/internal/shared/response/response.go index 14e32b0f..185972b1 100644 --- a/internal/shared/response/response.go +++ b/internal/shared/response/response.go @@ -16,8 +16,8 @@ type Response[T any] struct { // Any 用于 Swagger 文档的响应类型(非泛型) // swag 不支持泛型,使用此类型替代 Response[T] type Any struct { - ErrorMsg string `json:"error_msg" example:""` - Data interface{} `json:"data"` + ErrorMsg string `json:"error_msg" example:""` + Data any `json:"data"` } // APIError 统一的 API 业务错误类型,可被全局错误处理中间件捕获 diff --git a/pkg/cache/ram/manager.go b/pkg/cache/ram/manager.go index 1198a70a..92245ece 100644 --- a/pkg/cache/ram/manager.go +++ b/pkg/cache/ram/manager.go @@ -6,6 +6,7 @@ package ram import ( "context" "errors" + "maps" "sync" "time" ) @@ -119,9 +120,7 @@ func Set(item CacheItem) { currentMap, ok := managerCache.GetIfPresent(item.Type) newMap := make(map[string]cacheEntry) if ok { - for k, v := range currentMap { - newMap[k] = v - } + maps.Copy(newMap, currentMap) } var expireAt time.Time diff --git a/pkg/cap/cap.go b/pkg/cap/cap.go index 0d3727f0..240d12ff 100644 --- a/pkg/cap/cap.go +++ b/pkg/cap/cap.go @@ -238,14 +238,14 @@ func VerifyChallengeSolutions(token string, solutions []int, secret []byte, expe func Solve(token string, count, size, difficulty int) []int { solutions := make([]int, count) tokenFnv := fnv1a(token) - for i := 0; i < count; i++ { + for i := range count { idxStr := strconv.Itoa(i + 1) saltSeed := fnv1aResume(tokenFnv, idxStr) targetSeed := fnv1aResume(saltSeed, "d") salt := prngFromHash(saltSeed, size) target := prngFromHash(targetSeed, difficulty) - for nonce := 0; nonce < 1000000; nonce++ { + for nonce := range 1000000 { hashInput := salt + strconv.Itoa(nonce) hashBytes := sha256.Sum256([]byte(hashInput)) hashHex := hex.EncodeToString(hashBytes[:]) diff --git a/pkg/geoip/country_centroid.go b/pkg/geoip/country_centroid.go index 3697ff34..de84a8ad 100644 --- a/pkg/geoip/country_centroid.go +++ b/pkg/geoip/country_centroid.go @@ -194,7 +194,7 @@ func CountryCentroidByName(name string) (lat float64, lon float64, ok bool) { return v.lat, v.lon, true } // Try comma-separated parts (city / region / country / ISO). - for _, part := range strings.Split(name, ",") { + for part := range strings.SplitSeq(name, ",") { part = strings.TrimSpace(part) if part == "" { continue diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 7f9ba192..ba9bedb3 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -78,25 +78,25 @@ func Init(cfg Config) { } // DebugF 输出 Debug 级别日志 -func DebugF(ctx context.Context, format string, args ...interface{}) { +func DebugF(ctx context.Context, format string, args ...any) { msg := fmt.Sprintf(format, args...) logger.Ctx(ctx).Debug(msg, getTraceIDFields(ctx)...) } // InfoF 输出 Info 级别日志 -func InfoF(ctx context.Context, format string, args ...interface{}) { +func InfoF(ctx context.Context, format string, args ...any) { msg := fmt.Sprintf(format, args...) logger.Ctx(ctx).Info(msg, getTraceIDFields(ctx)...) } // WarnF 输出 Warn 级别日志 -func WarnF(ctx context.Context, format string, args ...interface{}) { +func WarnF(ctx context.Context, format string, args ...any) { msg := fmt.Sprintf(format, args...) logger.Ctx(ctx).Warn(msg, getTraceIDFields(ctx)...) } // ErrorF 输出 Error 级别日志 -func ErrorF(ctx context.Context, format string, args ...interface{}) { +func ErrorF(ctx context.Context, format string, args ...any) { msg := fmt.Sprintf(format, args...) logger.Ctx(ctx).Error(msg, getTraceIDFields(ctx)...) } diff --git a/pkg/logger/ringbuffer.go b/pkg/logger/ringbuffer.go index 71a77f37..89761e76 100644 --- a/pkg/logger/ringbuffer.go +++ b/pkg/logger/ringbuffer.go @@ -141,10 +141,7 @@ func (r *LogRingBuffer) Query(cursor int, limit int) ([]LogEntry, bool) { } // 返回 cut 之前的最后 limit 条 - start := cut - limit - if start < 0 { - start = 0 - } + start := max(cut-limit, 0) hasMore := start > 0 return ordered[start:cut], hasMore diff --git a/pkg/mail/mail.go b/pkg/mail/mail.go index ed34ccad..1321d1cf 100644 --- a/pkg/mail/mail.go +++ b/pkg/mail/mail.go @@ -55,21 +55,21 @@ func SendMailHTML(ctx context.Context, cfg Config, to string, subject, body stri header["MIME-Version"] = "1.0" header["Content-Type"] = "text/html; charset=UTF-8" - message := "" + var message strings.Builder for k, v := range header { - message += fmt.Sprintf("%s: %s\r\n", k, v) + fmt.Fprintf(&message, "%s: %s\r\n", k, v) } - message += "\r\n" + body + message.WriteString("\r\n" + body) auth := smtp.PlainAuth("", cfg.Username, cfg.Password, cfg.Host) // If using SSL port 465, we connection via TLS dial if cfg.Port == smtpSSLPort { - return sendMailViaSSL(ctx, addr, auth, cfg, to, message) + return sendMailViaSSL(ctx, addr, auth, cfg, to, message.String()) } // For standard port (587 / 25), use smtp.SendMail directly (handles STARTTLS automatically if server supports it) - err := smtp.SendMail(addr, auth, cfg.Username, []string{to}, []byte(message)) + err := smtp.SendMail(addr, auth, cfg.Username, []string{to}, []byte(message.String())) if err != nil { return fmt.Errorf(errSendMailFailed, err) } @@ -127,7 +127,7 @@ func sendMailViaSSL(ctx context.Context, addr string, auth smtp.Auth, cfg Config // SendMailWithLog sends a test email and records a detailed SMTP connection log func SendMailWithLog(ctx context.Context, cfg Config, to string, subject, body string) (string, error) { var logBuf bytes.Buffer - logLine := func(dir string, format string, args ...interface{}) { + logLine := func(dir string, format string, args ...any) { fmt.Fprintf(&logBuf, "[%s] %s\n", dir, fmt.Sprintf(format, args...)) } @@ -227,14 +227,14 @@ func SendMailWithLog(ctx context.Context, cfg Config, to string, subject, body s header["MIME-Version"] = "1.0" header["Content-Type"] = "text/html; charset=UTF-8" - message := "" + var message strings.Builder for k, v := range header { - message += fmt.Sprintf("%s: %s\r\n", k, v) + fmt.Fprintf(&message, "%s: %s\r\n", k, v) } - message += "\r\n" + body + message.WriteString("\r\n" + body) logLine("System", "Sending message body...") - if _, err = w.Write([]byte(message)); err != nil { + if _, err = w.Write([]byte(message.String())); err != nil { _ = w.Close() logLine("Error", "Writing message body failed: %v", err) return logBuf.String(), err diff --git a/pkg/pagesarchive/path.go b/pkg/pagesarchive/path.go index 94562c8b..85d15375 100644 --- a/pkg/pagesarchive/path.go +++ b/pkg/pagesarchive/path.go @@ -66,7 +66,7 @@ func validateLogicalPathRunes(raw string) error { } func validateLogicalPathSegments(raw string) error { - for _, segment := range strings.Split(raw, "/") { + for segment := range strings.SplitSeq(raw, "/") { if len(segment) >= 2 && segment[1] == ':' { return fmt.Errorf("pages path contains a Windows drive: %s", raw) } diff --git a/pkg/render/openresty/render.go b/pkg/render/openresty/render.go index cdf4d7ba..e11f8d45 100644 --- a/pkg/render/openresty/render.go +++ b/pkg/render/openresty/render.go @@ -414,7 +414,7 @@ func pagesFallbackPath(deployment *PagesDeployment) string { if value == "/" || strings.HasSuffix(value, "/") || strings.Contains(value, "\\") || strings.ContainsAny(value, "\"';") || strings.ContainsAny(value, " \t\r\n") { return indexHTML } - for _, segment := range strings.Split(value, "/") { + for segment := range strings.SplitSeq(value, "/") { if segment == "." || segment == ".." { return indexHTML } diff --git a/pkg/render/openresty/status_codes.go b/pkg/render/openresty/status_codes.go index e7758b0b..7eed8161 100644 --- a/pkg/render/openresty/status_codes.go +++ b/pkg/render/openresty/status_codes.go @@ -24,12 +24,12 @@ func ParseStatusCodeTag(tag string) (lo, hi int, err error) { if tag == "" { return 0, 0, fmt.Errorf("状态码标签不能为空") } - if i := strings.IndexByte(tag, '-'); i >= 0 { - lo, err = strconv.Atoi(tag[:i]) + if before, after, ok := strings.Cut(tag, "-"); ok { + lo, err = strconv.Atoi(before) if err != nil { return 0, 0, fmt.Errorf("无效状态码区间: %s", tag) } - hi, err = strconv.Atoi(tag[i+1:]) + hi, err = strconv.Atoi(after) if err != nil { return 0, 0, fmt.Errorf("无效状态码区间: %s", tag) } diff --git a/pkg/util/value.go b/pkg/util/value.go index 759a62f2..7c627d65 100644 --- a/pkg/util/value.go +++ b/pkg/util/value.go @@ -3,7 +3,7 @@ package util import "fmt" // Interface2String converts a string, int, or float64 value to its string representation. -func Interface2String(inter interface{}) string { +func Interface2String(inter any) string { switch v := inter.(type) { case string: return v diff --git a/pkg/util/version_compare.go b/pkg/util/version_compare.go index dc490081..3e53d269 100644 --- a/pkg/util/version_compare.go +++ b/pkg/util/version_compare.go @@ -3,10 +3,7 @@ package util import "strconv" func compareVersionNumbers(left, right VersionInfo) int { - maxLen := len(left.Numbers) - if len(right.Numbers) > maxLen { - maxLen = len(right.Numbers) - } + maxLen := max(len(right.Numbers), len(left.Numbers)) for index := 0; index < maxLen; index++ { leftValue := 0 rightValue := 0 @@ -37,10 +34,7 @@ func compareGitDescribeDistance(left, right VersionInfo) int { } func compareGitDescribeTails(left, right VersionInfo) int { - maxLen := len(left.GitDescribeTail) - if len(right.GitDescribeTail) > maxLen { - maxLen = len(right.GitDescribeTail) - } + maxLen := max(len(right.GitDescribeTail), len(left.GitDescribeTail)) for index := 0; index < maxLen; index++ { if index >= len(left.GitDescribeTail) { return -1 @@ -69,10 +63,7 @@ func comparePrereleaseIdentifiers(left, right VersionInfo) int { return -1 } - maxLen := len(left.Prerelease) - if len(right.Prerelease) > maxLen { - maxLen = len(right.Prerelease) - } + maxLen := max(len(right.Prerelease), len(left.Prerelease)) for index := 0; index < maxLen; index++ { if index >= len(left.Prerelease) { return -1