perfsprint 18→0:strconv.Itoa/FormatInt/FormatUint/FormatBool 替代 fmt.Sprintf、无动词 fmt.Errorf→errors.New、纯字符串拼接。全部语义等价(已核对 diff)。修正 fixer 遗留的 import 问题(引入 goimports 统一整理)。

Result: {"status":"keep","total_issues":56,"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":0,"golint_prealloc":3,"golint_recvcheck":7,"golint_usestdlibvars":3,"golint_wastedassign":7,"golint_total":55,"eslint_problems":1,"eslint_errors":0,"eslint_warnings":1,"tsc_errors":0,"measure_s":47}
This commit is contained in:
ryan
2026-08-16 17:34:44 +08:00
parent b76f707c8b
commit 699e95f12c
54 changed files with 188 additions and 157 deletions
+1
View File
@@ -1,3 +1,4 @@
{"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"}}
{"run":3,"commit":"b76f707","metric":74,"metrics":{"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},"status":"keep","description":"modernize 37→5(-32):interface{}→any、内置 max/min、slices/maps 辅助、strings.Cut/SplitSeq、strings.Builder(修复 mail.go O(n²) 拼接)。逐 hunk 核对语义等价;omitzero 冲突修复被自动跳过(wire 格式不变);手动清 4 处遗留 sort import + 2 处 QF1012。","timestamp":1786872502383,"segment":0,"confidence":17,"asi":{"hypothesis":"批量应用 modernize 自动修复(interface{}→any、max/min、slices.Sort/Contains、strings.Cut/SplitSeq、maps.Copy、strings.Builder)","insight":"golangci-lint --fix 会把 omitempty→omitzero 的冲突修复跳过(2个文件保留原 tag,wire 格式不变,好);但 fixer 会遗留未使用的 sort import,需手动清 4 处;mail.go 的 Builder 迁移附带暴露 2 个 QF1012,顺手用 fmt.Fprintf 修复。全部修复语义等价,已逐项核对 diff","next_action_hint":"剩余 modernize=5 应为 omitzero 冲突文件;下轮先处理 perfsprint(18):先看 --fix 是否安全再决定"}}
+3 -2
View File
@@ -14,6 +14,7 @@ import (
"os"
"os/exec"
"runtime"
"strconv"
"time"
"github.com/Rain-kl/Wavelet/internal/infra/config"
@@ -309,7 +310,7 @@ func exportSQLite(c *gin.Context) {
c.Header("Content-Disposition", `attachment; filename="openflare.db"`)
c.Header("Content-Type", "application/octet-stream")
c.Header("Content-Length", fmt.Sprintf("%d", fi.Size()))
c.Header("Content-Length", strconv.FormatInt(fi.Size(), 10))
c.Status(http.StatusOK)
http.ServeContent(c.Writer, c.Request, "openflare.db", fi.ModTime(), f)
}
@@ -328,7 +329,7 @@ func exportPostgres(c *gin.Context) {
args := []string{
"--no-password",
"-h", dbCfg.Host,
"-p", fmt.Sprintf("%d", dbCfg.Port),
"-p", strconv.Itoa(dbCfg.Port),
"-U", dbCfg.Username,
dbCfg.Database,
}
+2 -2
View File
@@ -516,7 +516,7 @@ func (m *Manager) CurrentChecksum() (string, error) {
normalizedMain = strings.ReplaceAll(normalizedMain, listen, openrestyrender.ObservabilityListenPlaceholder)
}
if m.OpenrestyObservabilityPort > 0 {
normalizedMain = strings.ReplaceAll(normalizedMain, fmt.Sprintf("%d", m.OpenrestyObservabilityPort), openrestyrender.ObservabilityPortPlaceholder)
normalizedMain = strings.ReplaceAll(normalizedMain, strconv.Itoa(m.OpenrestyObservabilityPort), openrestyrender.ObservabilityPortPlaceholder)
}
if resolverDirective := strings.TrimSpace(m.OpenrestyResolverDirective); resolverDirective != "" {
normalizedMain = strings.ReplaceAll(normalizedMain, resolverDirective, ResolverDirectivePlaceholder)
@@ -1463,7 +1463,7 @@ func (m *Manager) renderMainConfig(content string) string {
rendered = strings.ReplaceAll(rendered, openrestyrender.ObservabilityListenPlaceholder, listen)
}
if m.OpenrestyObservabilityPort > 0 {
rendered = strings.ReplaceAll(rendered, openrestyrender.ObservabilityPortPlaceholder, fmt.Sprintf("%d", m.OpenrestyObservabilityPort))
rendered = strings.ReplaceAll(rendered, openrestyrender.ObservabilityPortPlaceholder, strconv.Itoa(m.OpenrestyObservabilityPort))
}
if resolverDirective := strings.TrimSpace(m.OpenrestyResolverDirective); resolverDirective != "" {
rendered = strings.ReplaceAll(rendered, ResolverDirectivePlaceholder, resolverDirective)
+5 -4
View File
@@ -15,6 +15,7 @@ import (
"log/slog"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/Rain-kl/Wavelet/internal/apps/agent/protocol"
@@ -392,7 +393,7 @@ func (s *Service) downloadPagesProjectPackage(
metadata *protocol.PagesProjectLatestHashResponse,
maxBytes int64,
) (packagePath string, hash string, err error) {
releasesRoot := filepath.Join(s.pagesDir, "projects", fmt.Sprintf("%d", projectID), "releases")
releasesRoot := filepath.Join(s.pagesDir, "projects", strconv.FormatUint(uint64(projectID), 10), "releases")
if err := os.MkdirAll(releasesRoot, pagesDirPerm); err != nil {
return "", "", err
}
@@ -441,7 +442,7 @@ func cleanupPagesProjectStaleReleases(baseDir string, projectID uint, keepHash s
if projectID == 0 || keepHash == "" {
return nil
}
releasesRoot := filepath.Join(baseDir, "projects", fmt.Sprintf("%d", projectID), "releases")
releasesRoot := filepath.Join(baseDir, "projects", strconv.FormatUint(uint64(projectID), 10), "releases")
entries, err := os.ReadDir(releasesRoot) //nolint:gosec // managed PagesDir
if err != nil {
if os.IsNotExist(err) {
@@ -982,9 +983,9 @@ func writePagesMarker(dir string, project pagesProjectRef) error {
}
func pagesProjectCurrentDir(baseDir string, projectID uint) string {
return filepath.Join(baseDir, "projects", fmt.Sprintf("%d", projectID), "current")
return filepath.Join(baseDir, "projects", strconv.FormatUint(uint64(projectID), 10), "current")
}
func pagesProjectReleaseDir(baseDir string, projectID uint, checksum string) string {
return filepath.Join(baseDir, "projects", fmt.Sprintf("%d", projectID), "releases", checksum)
return filepath.Join(baseDir, "projects", strconv.FormatUint(uint64(projectID), 10), "releases", checksum)
}
+2 -1
View File
@@ -4,6 +4,7 @@
package updater
import (
"errors"
"fmt"
"log/slog"
"os"
@@ -37,7 +38,7 @@ func replaceAndRestart(execPath string, tmpPath string) error {
if err := syscall.Exec(execPath, os.Args, os.Environ()); err != nil { //nolint:gosec // execPath is the validated edge updater binary path
return fmt.Errorf("exec restart: %w", err)
}
return fmt.Errorf("unreachable after exec")
return errors.New("unreachable after exec")
}
func removeBackupBinary(path string) error {
+3 -2
View File
@@ -6,6 +6,7 @@ import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"log/slog"
@@ -295,7 +296,7 @@ func parseSHA256Checksum(content string, assetName string) (string, error) {
}
}
if assetName == "" {
return "", fmt.Errorf("checksum asset does not contain a valid sha256 digest")
return "", errors.New("checksum asset does not contain a valid sha256 digest")
}
return "", fmt.Errorf("checksum asset does not contain a sha256 digest for %q", assetName)
}
@@ -340,7 +341,7 @@ func isSHA256Hex(value string) bool {
func (s *Service) downloadAndRestart(ctx context.Context, url string, expectedChecksum string, targetPath string) error {
expectedChecksum = strings.ToLower(strings.TrimSpace(expectedChecksum))
if !isSHA256Hex(expectedChecksum) {
return fmt.Errorf("invalid expected sha256 checksum")
return errors.New("invalid expected sha256 checksum")
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
+3 -2
View File
@@ -5,6 +5,7 @@ package oauth
import (
"context"
"errors"
"fmt"
"strconv"
"sync"
@@ -140,7 +141,7 @@ func GetCachedToken(ctx context.Context, tokenHash string) (*model.AccessToken,
return &token, nil
}
}
return nil, fmt.Errorf("cache miss")
return nil, errors.New("cache miss")
}
// SetCachedToken 设置 AccessToken 缓存
@@ -183,7 +184,7 @@ func GetCachedUser(ctx context.Context, userID uint64) (*model.User, error) {
return &u, nil
}
}
return nil, fmt.Errorf("cache miss")
return nil, errors.New("cache miss")
}
// SetCachedUser 设置 User 缓存
@@ -46,7 +46,7 @@ func ChangedWAFIPGroupsForAgent(ctx context.Context, ids []uint, checksums map[s
}
changed := make([]WAFIPGroup, 0, len(groups))
for _, group := range groups {
if strings.TrimSpace(checksums[fmt.Sprintf("%d", group.ID)]) == group.Checksum {
if strings.TrimSpace(checksums[strconv.FormatUint(uint64(group.ID), 10)]) == group.Checksum {
continue
}
changed = append(changed, group)
@@ -6,6 +6,7 @@ package config_version
import (
"context"
"encoding/json"
"errors"
"fmt"
"net"
"strconv"
@@ -27,7 +28,7 @@ func normalizeSnapshotDomains(domains []string) ([]string, error) {
for _, raw := range domains {
domain := strings.ToLower(strings.TrimSpace(raw))
if domain == "" || strings.Contains(domain, "://") || strings.Contains(domain, "/") {
return nil, fmt.Errorf("domains payload is invalid")
return nil, errors.New("domains payload is invalid")
}
if _, ok := seen[domain]; ok {
continue
@@ -36,7 +37,7 @@ func normalizeSnapshotDomains(domains []string) ([]string, error) {
normalized = append(normalized, domain)
}
if len(normalized) == 0 {
return nil, fmt.Errorf("domain is required")
return nil, errors.New("domain is required")
}
return normalized, nil
}
@@ -55,7 +56,7 @@ func decodeStoredUpstreams(raw string, fallbackOriginURL string) ([]string, erro
}
var upstreams []string
if err := json.Unmarshal([]byte(text), &upstreams); err != nil {
return nil, fmt.Errorf("upstreams payload is invalid")
return nil, errors.New("upstreams payload is invalid")
}
return normalizeUpstreams(fallbackOriginURL, upstreams)
}
@@ -79,7 +80,7 @@ func normalizeUpstreams(originURL string, upstreams []string) ([]string, error)
normalized = append(normalized, value)
}
if len(normalized) == 0 {
return nil, fmt.Errorf("upstream is required")
return nil, errors.New("upstream is required")
}
return normalized, nil
}
@@ -91,7 +92,7 @@ func decodeStoredCustomHeaders(raw string) ([]customHeaderInput, error) {
}
var headers []customHeaderInput
if err := json.Unmarshal([]byte(text), &headers); err != nil {
return nil, fmt.Errorf("custom_headers payload is invalid")
return nil, errors.New("custom_headers payload is invalid")
}
return headers, nil
}
@@ -103,7 +104,7 @@ func decodeStoredCacheRules(raw string) ([]string, error) {
}
var rules []string
if err := json.Unmarshal([]byte(text), &rules); err != nil {
return nil, fmt.Errorf("cache_rules payload is invalid")
return nil, errors.New("cache_rules payload is invalid")
}
normalized := make([]string, 0, len(rules))
for _, rule := range rules {
@@ -494,51 +494,51 @@ func diffOpenRestyOptionDetails(left openRestyConfigSnapshot, right openRestyCon
CurrentValue: current,
})
}
appendIfChanged("OpenRestyDefaultServerReturnStatus", fmt.Sprintf("%d", left.DefaultServerReturnStatus), fmt.Sprintf("%d", right.DefaultServerReturnStatus))
appendIfChanged("OpenRestyDefaultServerReturnStatus", strconv.Itoa(left.DefaultServerReturnStatus), strconv.Itoa(right.DefaultServerReturnStatus))
appendIfChanged("OpenRestyWorkerProcesses", left.WorkerProcesses, right.WorkerProcesses)
appendIfChanged("OpenRestyWorkerConnections", fmt.Sprintf("%d", left.WorkerConnections), fmt.Sprintf("%d", right.WorkerConnections))
appendIfChanged("OpenRestyWorkerRlimitNofile", fmt.Sprintf("%d", left.WorkerRlimitNofile), fmt.Sprintf("%d", right.WorkerRlimitNofile))
appendIfChanged("OpenRestyWorkerConnections", strconv.Itoa(left.WorkerConnections), strconv.Itoa(right.WorkerConnections))
appendIfChanged("OpenRestyWorkerRlimitNofile", strconv.Itoa(left.WorkerRlimitNofile), strconv.Itoa(right.WorkerRlimitNofile))
appendIfChanged("OpenRestyEventsUse", left.EventsUse, right.EventsUse)
appendIfChanged("OpenRestyEventsMultiAcceptEnabled", fmt.Sprintf("%t", left.EventsMultiAcceptEnabled), fmt.Sprintf("%t", right.EventsMultiAcceptEnabled))
appendIfChanged("OpenRestyKeepaliveTimeout", fmt.Sprintf("%d", left.KeepaliveTimeout), fmt.Sprintf("%d", right.KeepaliveTimeout))
appendIfChanged("OpenRestyKeepaliveRequests", fmt.Sprintf("%d", left.KeepaliveRequests), fmt.Sprintf("%d", right.KeepaliveRequests))
appendIfChanged("OpenRestyClientHeaderTimeout", fmt.Sprintf("%d", left.ClientHeaderTimeout), fmt.Sprintf("%d", right.ClientHeaderTimeout))
appendIfChanged("OpenRestyClientBodyTimeout", fmt.Sprintf("%d", left.ClientBodyTimeout), fmt.Sprintf("%d", right.ClientBodyTimeout))
appendIfChanged("OpenRestyEventsMultiAcceptEnabled", strconv.FormatBool(left.EventsMultiAcceptEnabled), strconv.FormatBool(right.EventsMultiAcceptEnabled))
appendIfChanged("OpenRestyKeepaliveTimeout", strconv.Itoa(left.KeepaliveTimeout), strconv.Itoa(right.KeepaliveTimeout))
appendIfChanged("OpenRestyKeepaliveRequests", strconv.Itoa(left.KeepaliveRequests), strconv.Itoa(right.KeepaliveRequests))
appendIfChanged("OpenRestyClientHeaderTimeout", strconv.Itoa(left.ClientHeaderTimeout), strconv.Itoa(right.ClientHeaderTimeout))
appendIfChanged("OpenRestyClientBodyTimeout", strconv.Itoa(left.ClientBodyTimeout), strconv.Itoa(right.ClientBodyTimeout))
appendIfChanged("OpenRestyClientMaxBodySize", left.ClientMaxBodySize, right.ClientMaxBodySize)
appendIfChanged("OpenRestyLargeClientHeaderBuffers", left.LargeClientHeaderBuffers, right.LargeClientHeaderBuffers)
appendIfChanged("OpenRestySendTimeout", fmt.Sprintf("%d", left.SendTimeout), fmt.Sprintf("%d", right.SendTimeout))
appendIfChanged("OpenRestyProxyConnectTimeout", fmt.Sprintf("%d", left.ProxyConnectTimeout), fmt.Sprintf("%d", right.ProxyConnectTimeout))
appendIfChanged("OpenRestyProxySendTimeout", fmt.Sprintf("%d", left.ProxySendTimeout), fmt.Sprintf("%d", right.ProxySendTimeout))
appendIfChanged("OpenRestyProxyReadTimeout", fmt.Sprintf("%d", left.ProxyReadTimeout), fmt.Sprintf("%d", right.ProxyReadTimeout))
appendIfChanged("OpenRestyWebsocketEnabled", fmt.Sprintf("%t", left.WebsocketEnabled), fmt.Sprintf("%t", right.WebsocketEnabled))
appendIfChanged("OpenRestyHTTP3Enabled", fmt.Sprintf("%t", left.HTTP3Enabled), fmt.Sprintf("%t", right.HTTP3Enabled))
appendIfChanged("OpenRestyProxyRequestBufferingEnabled", fmt.Sprintf("%t", left.ProxyRequestBuffering), fmt.Sprintf("%t", right.ProxyRequestBuffering))
appendIfChanged("OpenRestyProxyBufferingEnabled", fmt.Sprintf("%t", left.ProxyBufferingEnabled), fmt.Sprintf("%t", right.ProxyBufferingEnabled))
appendIfChanged("OpenRestySendTimeout", strconv.Itoa(left.SendTimeout), strconv.Itoa(right.SendTimeout))
appendIfChanged("OpenRestyProxyConnectTimeout", strconv.Itoa(left.ProxyConnectTimeout), strconv.Itoa(right.ProxyConnectTimeout))
appendIfChanged("OpenRestyProxySendTimeout", strconv.Itoa(left.ProxySendTimeout), strconv.Itoa(right.ProxySendTimeout))
appendIfChanged("OpenRestyProxyReadTimeout", strconv.Itoa(left.ProxyReadTimeout), strconv.Itoa(right.ProxyReadTimeout))
appendIfChanged("OpenRestyWebsocketEnabled", strconv.FormatBool(left.WebsocketEnabled), strconv.FormatBool(right.WebsocketEnabled))
appendIfChanged("OpenRestyHTTP3Enabled", strconv.FormatBool(left.HTTP3Enabled), strconv.FormatBool(right.HTTP3Enabled))
appendIfChanged("OpenRestyProxyRequestBufferingEnabled", strconv.FormatBool(left.ProxyRequestBuffering), strconv.FormatBool(right.ProxyRequestBuffering))
appendIfChanged("OpenRestyProxyBufferingEnabled", strconv.FormatBool(left.ProxyBufferingEnabled), strconv.FormatBool(right.ProxyBufferingEnabled))
appendIfChanged("OpenRestyProxyBuffers", left.ProxyBuffers, right.ProxyBuffers)
appendIfChanged("OpenRestyProxyBufferSize", left.ProxyBufferSize, right.ProxyBufferSize)
appendIfChanged("OpenRestyProxyBusyBuffersSize", left.ProxyBusyBuffersSize, right.ProxyBusyBuffersSize)
appendIfChanged("OpenRestyGzipEnabled", fmt.Sprintf("%t", left.GzipEnabled), fmt.Sprintf("%t", right.GzipEnabled))
appendIfChanged("OpenRestyGzipMinLength", fmt.Sprintf("%d", left.GzipMinLength), fmt.Sprintf("%d", right.GzipMinLength))
appendIfChanged("OpenRestyGzipCompLevel", fmt.Sprintf("%d", left.GzipCompLevel), fmt.Sprintf("%d", right.GzipCompLevel))
appendIfChanged("OpenRestyGzipEnabled", strconv.FormatBool(left.GzipEnabled), strconv.FormatBool(right.GzipEnabled))
appendIfChanged("OpenRestyGzipMinLength", strconv.Itoa(left.GzipMinLength), strconv.Itoa(right.GzipMinLength))
appendIfChanged("OpenRestyGzipCompLevel", strconv.Itoa(left.GzipCompLevel), strconv.Itoa(right.GzipCompLevel))
appendIfChanged("OpenRestyResolvers", left.Resolvers, right.Resolvers)
appendIfChanged("OpenRestyCacheEnabled", fmt.Sprintf("%t", left.CacheEnabled), fmt.Sprintf("%t", right.CacheEnabled))
appendIfChanged("OpenRestyCacheEnabled", strconv.FormatBool(left.CacheEnabled), strconv.FormatBool(right.CacheEnabled))
appendIfChanged("OpenRestyCachePath", left.CachePath, right.CachePath)
appendIfChanged("OpenRestyCacheLevels", left.CacheLevels, right.CacheLevels)
appendIfChanged("OpenRestyCacheInactive", left.CacheInactive, right.CacheInactive)
appendIfChanged("OpenRestyCacheMaxSize", left.CacheMaxSize, right.CacheMaxSize)
appendIfChanged("OpenRestyCacheKeyTemplate", left.CacheKeyTemplate, right.CacheKeyTemplate)
appendIfChanged("OpenRestyCacheLockEnabled", fmt.Sprintf("%t", left.CacheLockEnabled), fmt.Sprintf("%t", right.CacheLockEnabled))
appendIfChanged("OpenRestyCacheLockEnabled", strconv.FormatBool(left.CacheLockEnabled), strconv.FormatBool(right.CacheLockEnabled))
appendIfChanged("OpenRestyCacheLockTimeout", left.CacheLockTimeout, right.CacheLockTimeout)
appendIfChanged("OpenRestyCacheUseStale", left.CacheUseStale, right.CacheUseStale)
appendIfChanged("OpenRestyDefaultLimitConnPerServer", fmt.Sprintf("%d", left.DefaultLimitConnPerServer), fmt.Sprintf("%d", right.DefaultLimitConnPerServer))
appendIfChanged("OpenRestyDefaultLimitConnPerIP", fmt.Sprintf("%d", left.DefaultLimitConnPerIP), fmt.Sprintf("%d", right.DefaultLimitConnPerIP))
appendIfChanged("OpenRestyDefaultLimitConnPerServer", strconv.Itoa(left.DefaultLimitConnPerServer), strconv.Itoa(right.DefaultLimitConnPerServer))
appendIfChanged("OpenRestyDefaultLimitConnPerIP", strconv.Itoa(left.DefaultLimitConnPerIP), strconv.Itoa(right.DefaultLimitConnPerIP))
appendIfChanged("OpenRestyDefaultLimitRate", left.DefaultLimitRate, right.DefaultLimitRate)
appendIfChanged("OpenRestyDefaultLimitReqPerIP", left.DefaultLimitReqPerIP, right.DefaultLimitReqPerIP)
appendIfChanged("OriginErrorPageEnabled", fmt.Sprintf("%t", left.OriginErrorPageEnabled), fmt.Sprintf("%t", right.OriginErrorPageEnabled))
appendIfChanged("OriginErrorPageEnabled", strconv.FormatBool(left.OriginErrorPageEnabled), strconv.FormatBool(right.OriginErrorPageEnabled))
appendIfChanged("OriginErrorPageStatusCodes", encodeOriginErrorPageStatusCodes(left.OriginErrorPageStatusCodes), encodeOriginErrorPageStatusCodes(right.OriginErrorPageStatusCodes))
appendIfChanged("OriginErrorPageHTML", left.OriginErrorPageHTML, right.OriginErrorPageHTML)
appendIfChanged("OriginErrorPageGetOnly", fmt.Sprintf("%t", left.OriginErrorPageGetOnly), fmt.Sprintf("%t", right.OriginErrorPageGetOnly))
appendIfChanged("SWOfflineEnabled", fmt.Sprintf("%t", left.SWOfflineEnabled), fmt.Sprintf("%t", right.SWOfflineEnabled))
appendIfChanged("OriginErrorPageGetOnly", strconv.FormatBool(left.OriginErrorPageGetOnly), strconv.FormatBool(right.OriginErrorPageGetOnly))
appendIfChanged("SWOfflineEnabled", strconv.FormatBool(left.SWOfflineEnabled), strconv.FormatBool(right.SWOfflineEnabled))
appendIfChanged("SWOfflineHTML", left.SWOfflineHTML, right.SWOfflineHTML)
appendIfChanged("SWOfflineDomains", encodeSWOfflineDomains(left.SWOfflineDomains), encodeSWOfflineDomains(right.SWOfflineDomains))
return changes
@@ -478,7 +478,7 @@ func decodeIPList(raw string) ([]string, error) {
}
var items []string
if err := json.Unmarshal([]byte(text), &items); err != nil {
return nil, fmt.Errorf("ip_list payload is invalid")
return nil, errors.New("ip_list payload is invalid")
}
return items, nil
}
+2 -2
View File
@@ -28,7 +28,7 @@ const (
// Heartbeat processes an OpenFlared heartbeat and returns runtime settings.
func Heartbeat(ctx context.Context, node *model.OpenFlareNode, payload HeartbeatPayload) (*HeartbeatResponse, error) {
if node == nil {
return nil, fmt.Errorf("tunnel client node is nil")
return nil, errors.New("tunnel client node is nil")
}
if node.NodeType != "tunnel_client" {
return nil, fmt.Errorf("node %s is not a tunnel_client", node.NodeID)
@@ -95,7 +95,7 @@ func Heartbeat(ctx context.Context, node *model.OpenFlareNode, payload Heartbeat
// GetTunnelConfig builds the full tunnel routing config for an OpenFlared client.
func GetTunnelConfig(ctx context.Context, node *model.OpenFlareNode) (*TunnelConfigResponse, error) {
if node == nil {
return nil, fmt.Errorf("node is nil")
return nil, errors.New("node is nil")
}
activeVersion, err := getActiveConfigMeta(ctx)
+8 -7
View File
@@ -8,6 +8,7 @@ import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net"
@@ -317,7 +318,7 @@ func fetchLatestStableGitHubRelease(ctx context.Context, repo string) (*githubRe
url := fmt.Sprintf(githubReleasesAPIBase+"/latest", strings.TrimSpace(repo))
req, err := newGitHubReleaseRequest(ctx, url)
if err != nil {
return nil, fmt.Errorf("创建更新请求失败")
return nil, errors.New("创建更新请求失败")
}
resp, err := releaseHTTPClient.Do(req)
if err != nil {
@@ -334,7 +335,7 @@ func fetchLatestPreviewGitHubRelease(ctx context.Context, repo string) (*githubR
url := fmt.Sprintf(githubReleasesAPIBase+"?per_page=20", strings.TrimSpace(repo))
req, err := newGitHubReleaseRequest(ctx, url)
if err != nil {
return nil, fmt.Errorf("创建更新请求失败")
return nil, errors.New("创建更新请求失败")
}
resp, err := releaseHTTPClient.Do(req)
if err != nil {
@@ -346,7 +347,7 @@ func fetchLatestPreviewGitHubRelease(ctx context.Context, repo string) (*githubR
}
var releases []githubReleaseResponse
if err = json.NewDecoder(resp.Body).Decode(&releases); err != nil {
return nil, fmt.Errorf("解析 preview 版本信息失败")
return nil, errors.New("解析 preview 版本信息失败")
}
for _, release := range releases {
if release.Draft || !release.Prerelease {
@@ -355,18 +356,18 @@ func fetchLatestPreviewGitHubRelease(ctx context.Context, repo string) (*githubR
releaseCopy := release
return &releaseCopy, nil
}
return nil, fmt.Errorf("当前没有可用的 preview 发布")
return nil, errors.New("当前没有可用的 preview 发布")
}
func fetchGitHubReleaseByTag(ctx context.Context, repo string, tag string) (*githubReleaseResponse, error) {
tag = strings.TrimSpace(tag)
if tag == "" {
return nil, fmt.Errorf("缺少发布版本号")
return nil, errors.New("缺少发布版本号")
}
url := fmt.Sprintf(githubReleasesAPIBase+"/tags/%s", strings.TrimSpace(repo), tag)
req, err := newGitHubReleaseRequest(ctx, url)
if err != nil {
return nil, fmt.Errorf("创建更新请求失败")
return nil, errors.New("创建更新请求失败")
}
resp, err := releaseHTTPClient.Do(req)
if err != nil {
@@ -395,7 +396,7 @@ func newGitHubReleaseRequest(ctx context.Context, url string) (*http.Request, er
func decodeGitHubRelease(reader io.Reader) (*githubReleaseResponse, error) {
var release githubReleaseResponse
if err := json.NewDecoder(reader).Decode(&release); err != nil {
return nil, fmt.Errorf("解析版本信息失败")
return nil, errors.New("解析版本信息失败")
}
return &release, nil
}
+2 -2
View File
@@ -414,14 +414,14 @@ type forceSyncConfigPayload struct {
func ValidateDiscoveryToken(ctx context.Context, token string) error {
token = strings.TrimSpace(token)
if token == "" {
return fmt.Errorf("缺少 Discovery Token")
return errors.New("缺少 Discovery Token")
}
discoveryToken, err := ensureGlobalDiscoveryToken(ctx)
if err != nil {
return err
}
if token != discoveryToken {
return fmt.Errorf("discovery Token 无效") // error 消息首字母小写
return errors.New("discovery Token 无效") // error 消息首字母小写
}
return nil
}
+6 -6
View File
@@ -176,16 +176,16 @@ func validateUptimeKumaEnabled(ctx context.Context, key, trimmed string, state m
username := strings.TrimSpace(state[model.ConfigKeyUptimeKumaUsername])
password := strings.TrimSpace(state[model.ConfigKeyUptimeKumaPassword])
if url == "" {
return fmt.Errorf("启用 Uptime Kuma 时地址不能为空")
return errors.New("启用 Uptime Kuma 时地址不能为空")
}
if username == "" {
return fmt.Errorf("启用 Uptime Kuma 时用户名不能为空")
return errors.New("启用 Uptime Kuma 时用户名不能为空")
}
// 如果待验证的密码为空,且当前配置中也没有密码,则报错
if password == "" {
existingPwd, _ := repository.GetSystemConfigByKey(ctx, model.ConfigKeyUptimeKumaPassword)
if strings.TrimSpace(existingPwd.Value) == "" {
return fmt.Errorf("启用 Uptime Kuma 时密码不能为空")
return errors.New("启用 Uptime Kuma 时密码不能为空")
}
}
return nil
@@ -193,21 +193,21 @@ func validateUptimeKumaEnabled(ctx context.Context, key, trimmed string, state m
func validateUptimeKumaUsername(trimmed string, state map[string]string) error {
if trimmed == "" && state[model.ConfigKeyUptimeKumaEnabled] == optionValueTrue {
return fmt.Errorf("启用 Uptime Kuma 时用户名不能为空")
return errors.New("启用 Uptime Kuma 时用户名不能为空")
}
return nil
}
func validateUptimeKumaURL(trimmed string) error {
if trimmed != "" && !strings.HasPrefix(trimmed, "http://") && !strings.HasPrefix(trimmed, "https://") {
return fmt.Errorf("uptime Kuma 地址必须以 http:// 或 https:// 开头")
return errors.New("uptime Kuma 地址必须以 http:// 或 https:// 开头")
}
return nil
}
func validateUptimeKumaMonitorScope(trimmed string) error {
if trimmed != "all" && trimmed != "selected" {
return fmt.Errorf("监控范围必须为全部站点 (all) 或选择站点 (selected)")
return errors.New("监控范围必须为全部站点 (all) 或选择站点 (selected)")
}
return nil
}
+2 -1
View File
@@ -6,6 +6,7 @@ package pages
import (
"context"
"encoding/json"
"errors"
"fmt"
"path"
"strings"
@@ -151,7 +152,7 @@ func resolveProjectIDFromRouteMap(route map[string]json.RawMessage) (uint, error
return deployment.ProjectID, nil
}
}
return 0, fmt.Errorf("pages 配置无效: 缺少 pages_project_id")
return 0, errors.New("pages 配置无效: 缺少 pages_project_id")
}
func loadActivePagesProject(ctx context.Context, projectID uint, siteName string) (*model.PagesProject, *model.PagesDeployment, error) {
+2 -1
View File
@@ -5,6 +5,7 @@ package relay
import (
"context"
"errors"
"fmt"
"strings"
"time"
@@ -20,7 +21,7 @@ const nodeStatusOnline = "online"
// Heartbeat processes a relay heartbeat, updates node status, and returns config.
func Heartbeat(ctx context.Context, node *model.OpenFlareNode, payload HeartbeatPayload) (*HeartbeatResponse, error) {
if node == nil {
return nil, fmt.Errorf("relay node is nil")
return nil, errors.New("relay node is nil")
}
payload.Version = strings.TrimSpace(payload.Version)
+1 -1
View File
@@ -89,7 +89,7 @@ func NewSocketIOClient(baseURL string) *SocketIOClient {
// Connect performs the Engine.IO handshake and starts the polling loop.
func (c *SocketIOClient) Connect() error {
slog.Debug("Uptime Kuma client starting handshake", "baseURL", c.baseURL)
u := fmt.Sprintf("%s/socket.io/?EIO=4&transport=polling", c.baseURL)
u := c.baseURL + "/socket.io/?EIO=4&transport=polling"
reqHandshake, err := http.NewRequestWithContext(c.ctx, http.MethodGet, u, nil)
if err != nil {
return fmt.Errorf("create handshake request failed: %w", err)
+4 -3
View File
@@ -5,6 +5,7 @@ package uptimekuma
import (
"context"
"errors"
"fmt"
"log/slog"
"strings"
@@ -75,11 +76,11 @@ func SyncToUptimeKuma(ctx context.Context) error {
// 检查是否启用
enabled, _ := repository.GetBoolByKey(ctx, model.ConfigKeyUptimeKumaEnabled)
if !enabled {
return fmt.Errorf("uptime Kuma integration is disabled")
return errors.New("uptime Kuma integration is disabled")
}
if !isSyncing.CompareAndSwap(false, true) {
return fmt.Errorf("sync task is already in progress, please try again later")
return errors.New("sync task is already in progress, please try again later")
}
defer isSyncing.Store(false)
@@ -225,7 +226,7 @@ func filterOpenFlareMonitors(monitors map[string]Monitor, openFlareTagID int) ma
func routeMonitorURL(ctx context.Context, route *model.ProxyRoute) (string, error) {
if route == nil {
return "", fmt.Errorf("proxy route is nil")
return "", errors.New("proxy route is nil")
}
domains, err := repository.ListZoneDomainsByRouteID(ctx, route.ID)
if err != nil {
@@ -5,6 +5,7 @@ package uptimekuma
import (
"context"
"errors"
"fmt"
"log/slog"
"strings"
@@ -18,13 +19,13 @@ const monitorListWaitTimeout = 5 * time.Second
// validateKumaConfig 验证 kumaConfig 配置完整性
func validateKumaConfig(config *kumaConfig) error {
if strings.TrimSpace(config.URL) == "" {
return fmt.Errorf("uptime Kuma URL is not configured")
return errors.New("uptime Kuma URL is not configured")
}
if strings.TrimSpace(config.Username) == "" {
return fmt.Errorf("uptime Kuma username is not configured")
return errors.New("uptime Kuma username is not configured")
}
if strings.TrimSpace(config.Password) == "" {
return fmt.Errorf("uptime Kuma password is not configured")
return errors.New("uptime Kuma password is not configured")
}
return nil
}
@@ -65,7 +66,7 @@ func connectAndLoginUptimeKuma(kumaURL, kumaUsername, kumaPassword string) (*Soc
case <-time.After(monitorListWaitTimeout):
client.Close()
slog.Error("Timeout waiting for Uptime Kuma monitorList push event")
return nil, fmt.Errorf("timeout waiting for monitorList event from Uptime Kuma")
return nil, errors.New("timeout waiting for monitorList event from Uptime Kuma")
}
return client, nil
}
+3 -2
View File
@@ -4,6 +4,7 @@
package waf
import (
"errors"
"fmt"
"slices"
"sort"
@@ -35,14 +36,14 @@ func CompileRuleGraph(graph RuleGraph) (RuntimeRuleGraph, error) {
}
if node.Type == RuleNodeStart {
if runtime.Entry != "" {
return RuntimeRuleGraph{}, fmt.Errorf("规则图包含多个开始节点")
return RuntimeRuleGraph{}, errors.New("规则图包含多个开始节点")
}
runtime.Entry = node.ID
}
runtime.Nodes[node.ID] = RuntimeRuleNode{Type: node.Type, Config: config}
}
if runtime.Entry == "" {
return RuntimeRuleGraph{}, fmt.Errorf("规则图缺少开始节点")
return RuntimeRuleGraph{}, errors.New("规则图缺少开始节点")
}
for _, edge := range graph.Edges {
node, ok := runtime.Nodes[edge.Source]
@@ -68,7 +68,7 @@ func validateRuleGraphLimits(graph RuleGraph) error {
if raw, err := json.Marshal(graph); err != nil {
return fmt.Errorf("规则图无法序列化: %w", err)
} else if len(raw) > maxRuleGraphBytes {
return fmt.Errorf("规则图大小不能超过 256 KiB")
return errors.New("规则图大小不能超过 256 KiB")
}
return nil
}
@@ -103,7 +103,7 @@ func ImportLegacyTx(ctx context.Context, tx *sql.Tx, postgres bool) (report Impo
`), domain).Scan(&existingID, &existingZoneDomain)
if scanErr == nil {
if existingZoneDomain != root {
report.Conflicts = append(report.Conflicts, fmt.Sprintf("%s: global domain conflict", domain))
report.Conflicts = append(report.Conflicts, domain+": global domain conflict")
} else if item.ProxyRouteID != nil {
if _, bindErr := tx.ExecContext(ctx, q(`
UPDATE of_zone_domains
@@ -147,7 +147,7 @@ func ImportLegacyTx(ctx context.Context, tx *sql.Tx, postgres bool) (report Impo
}
if len(report.Conflicts) > 0 {
return report, fmt.Errorf("legacy data has conflicts")
return report, errors.New("legacy data has conflicts")
}
return report, nil
}
+1 -1
View File
@@ -204,7 +204,7 @@ func DownloadFile(c *gin.Context) {
}
}
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename*=UTF-8''%s", url.PathEscape(fileName)))
c.Header("Content-Disposition", "attachment; filename*=UTF-8''"+url.PathEscape(fileName))
filesrv.ServeUpload(c, upload)
}
@@ -69,7 +69,7 @@ func (h *MigrationHandler) ValidatePayload(payload []byte) ([]byte, error) {
return payload, err
}
if active {
return payload, fmt.Errorf("storage migration task is already unresolved")
return payload, errors.New("storage migration task is already unresolved")
}
return normalized, nil
}
+1 -1
View File
@@ -152,7 +152,7 @@ func (h *SendEmailHandler) Execute(ctx context.Context, payload []byte) (*task.T
return nil, fmt.Errorf(errSendMailFailed, err)
}
msg := fmt.Sprintf("邮件成功发送至: %s", req.To)
msg := "邮件成功发送至: " + req.To
task.AppendLog(ctx, "%s", msg)
return &task.TaskResult{
+7 -7
View File
@@ -34,18 +34,18 @@ func formatStartupBanner(state startupState) string {
"/ /_/ / /_/ / __/ / / / __/ / / /_/ / / / __/",
"\\____/ .___/\\___/_/ /_/_/ /_/\\__,_/_/ \\___/ ",
" /_/ ",
fmt.Sprintf(" OpenFlare %s", buildinfo.Version),
" OpenFlare " + buildinfo.Version,
"",
fmt.Sprintf(" Environment: %s", config.Config.App.Env),
" Environment: " + config.Config.App.Env,
fmt.Sprintf(" Runtime: %s/%s (%s)", runtime.GOOS, runtime.GOARCH, runtime.Version()),
fmt.Sprintf(" Build time: %s", buildTime()),
fmt.Sprintf(" Database: %s", formatMigration(state.relationalDB)),
fmt.Sprintf(" Analytics: %s", formatMigration(state.clickHouseDB)),
" Build time: " + buildTime(),
" Database: " + formatMigration(state.relationalDB),
" Analytics: " + formatMigration(state.clickHouseDB),
}
if state.listensForHTTP {
lines = append(lines, fmt.Sprintf(" Listening: http://%s", config.Config.App.Addr))
lines = append(lines, " Listening: http://"+config.Config.App.Addr)
}
lines = append(lines, fmt.Sprintf(" Mode: %s", state.mode), "")
lines = append(lines, " Mode: "+state.mode, "")
return strings.Join(lines, "\n")
}
+4 -3
View File
@@ -5,6 +5,7 @@ package objectstore
import (
"context"
"errors"
"fmt"
"io"
"mime"
@@ -20,7 +21,7 @@ type localBackend struct {
func newLocalBackend(cfg LocalConfig) (*localBackend, error) {
root := filepath.Clean(cfg.Root)
if root == "" {
return nil, fmt.Errorf("local root is required")
return nil, errors.New("local root is required")
}
return &localBackend{root: root}, nil
}
@@ -103,7 +104,7 @@ func (b *localBackend) path(key string) (string, error) {
}
rel, err := filepath.Rel(absRoot, absPath)
if err != nil || strings.HasPrefix(rel, "..") {
return "", fmt.Errorf("storage key escapes local root")
return "", errors.New("storage key escapes local root")
}
return cleanPath, nil
}
@@ -114,7 +115,7 @@ func (b *localBackend) path(key string) (string, error) {
path := filepath.Join(b.root, cleanKey)
rel, err := filepath.Rel(b.root, path)
if err != nil || strings.HasPrefix(rel, "..") {
return "", fmt.Errorf("storage key escapes local root")
return "", errors.New("storage key escapes local root")
}
return path, nil
}
@@ -4,7 +4,7 @@
package batchwriter
import (
"fmt"
"errors"
"time"
)
@@ -51,19 +51,19 @@ func DefaultConfig() Config {
func (c Config) validate() error {
if c.QueueSize <= 0 {
return fmt.Errorf("batchwriter: queue size must be positive")
return errors.New("batchwriter: queue size must be positive")
}
if c.MaxBatchSize <= 0 {
return fmt.Errorf("batchwriter: max batch size must be positive")
return errors.New("batchwriter: max batch size must be positive")
}
if c.MinBatchSize < 0 {
return fmt.Errorf("batchwriter: min batch size must be non-negative")
return errors.New("batchwriter: min batch size must be non-negative")
}
if c.FlushInterval <= 0 {
return fmt.Errorf("batchwriter: flush interval must be positive")
return errors.New("batchwriter: flush interval must be positive")
}
if c.MaxFlushWait < 0 {
return fmt.Errorf("batchwriter: max flush wait must be non-negative")
return errors.New("batchwriter: max flush wait must be non-negative")
}
return nil
}
+2 -1
View File
@@ -9,6 +9,7 @@ import (
"encoding/json"
"fmt"
"log"
"strconv"
"strings"
"time"
@@ -83,7 +84,7 @@ func init() {
if err := redisotel.InstrumentTracing(
Redis,
redisotel.WithAttributes(
attribute.String("db.instance", fmt.Sprintf("%v", cfg.DB)),
attribute.String("db.instance", strconv.Itoa(cfg.DB)),
attribute.String("db.ip", strings.Join(cfg.Addrs, ",")),
attribute.String("db.system", "Redis"),
),
+1 -1
View File
@@ -41,7 +41,7 @@ func GenerateTokenString() (string, error) {
if _, err := rand.Read(bytes); err != nil {
return "", err
}
return fmt.Sprintf("at_%s", hex.EncodeToString(bytes)), nil
return "at_" + hex.EncodeToString(bytes), nil
}
// HashToken 计算 Token 的 SHA-256 哈希值用于数据库存储与查询
+2 -1
View File
@@ -6,6 +6,7 @@ package analytics
import (
"context"
"errors"
"fmt"
"time"
@@ -15,7 +16,7 @@ import (
func userAccessLogConn() error {
if db.ChConn == nil {
return fmt.Errorf("clickhouse native connection is not initialized")
return errors.New("clickhouse native connection is not initialized")
}
return nil
}
@@ -5,6 +5,7 @@ package analytics
import (
"context"
"errors"
"fmt"
db "github.com/Rain-kl/Wavelet/internal/infra/persistence"
@@ -17,7 +18,7 @@ func BatchInsert(ctx context.Context, logs []analyticsmodel.UserAccessLog) error
return nil
}
if db.ChConn == nil {
return fmt.Errorf("clickhouse connection is not initialized")
return errors.New("clickhouse connection is not initialized")
}
batch, err := db.ChConn.PrepareBatch(ctx, analyticsmodel.UserAccessLog{}.BatchInsertSQL())
@@ -5,6 +5,7 @@ package analytics
import (
"context"
"errors"
"fmt"
"github.com/Rain-kl/Wavelet/internal/infra/config"
@@ -19,7 +20,7 @@ type ClickHouseOperationalStats = analyticsmodel.ClickHouseOperationalStats
// GetClickHouseOperationalStats returns operational metrics for the configured database.
func GetClickHouseOperationalStats(ctx context.Context) (*ClickHouseOperationalStats, error) {
if db.ChConn == nil {
return nil, fmt.Errorf("clickhouse native connection is not initialized")
return nil, errors.New("clickhouse native connection is not initialized")
}
database := config.Config.ClickHouse.Database
stats := &ClickHouseOperationalStats{Database: database}
@@ -5,6 +5,7 @@ package analytics
import (
"context"
"errors"
"fmt"
"strings"
"time"
@@ -19,7 +20,7 @@ type NodeAccessLogRegionCount = analyticsmodel.NodeAccessLogRegionCount
func nodeAccessLogConn() (driver.Conn, error) {
if db.ChConn == nil {
return nil, fmt.Errorf("clickhouse connection is not initialized")
return nil, errors.New("clickhouse connection is not initialized")
}
return db.ChConn, nil
}
@@ -5,6 +5,7 @@ package analytics
import (
"context"
"errors"
"fmt"
"strings"
"time"
@@ -20,7 +21,7 @@ func BatchInsertNodeAccessLogs(ctx context.Context, logs []analyticsmodel.NodeAc
return nil
}
if db.ChConn == nil {
return fmt.Errorf("clickhouse connection is not initialized")
return errors.New("clickhouse connection is not initialized")
}
batch, err := db.ChConn.PrepareBatch(ctx, analyticsmodel.NodeAccessLog{}.BatchInsertSQL())
@@ -5,6 +5,7 @@ package analytics
import (
"context"
"errors"
"fmt"
"slices"
"time"
@@ -16,7 +17,7 @@ import (
func observabilityConn() (driver.Conn, error) {
if db.ChConn == nil {
return nil, fmt.Errorf("clickhouse connection is not initialized")
return nil, errors.New("clickhouse connection is not initialized")
}
return db.ChConn, nil
}
@@ -5,6 +5,7 @@ package analytics
import (
"context"
"errors"
"fmt"
"strings"
"time"
@@ -30,7 +31,7 @@ func BatchInsertNodeMetricSnapshots(ctx context.Context, snapshots []analyticsmo
return nil
}
if db.ChConn == nil {
return fmt.Errorf("clickhouse connection is not initialized")
return errors.New("clickhouse connection is not initialized")
}
batch, err := db.ChConn.PrepareBatch(ctx, analyticsmodel.NodeMetricSnapshot{}.BatchInsertSQL())
@@ -102,7 +103,7 @@ func BatchInsertNodeEdgeHealth(ctx context.Context, rows []analyticsmodel.NodeEd
return nil
}
if db.ChConn == nil {
return fmt.Errorf("clickhouse connection is not initialized")
return errors.New("clickhouse connection is not initialized")
}
batch, err := db.ChConn.PrepareBatch(ctx, analyticsmodel.NodeEdgeHealth{}.BatchInsertSQL())
if err != nil {
@@ -160,7 +161,7 @@ func BatchInsertNodeObsFrps(ctx context.Context, observations []analyticsmodel.N
return nil
}
if db.ChConn == nil {
return fmt.Errorf("clickhouse connection is not initialized")
return errors.New("clickhouse connection is not initialized")
}
batch, err := db.ChConn.PrepareBatch(ctx, analyticsmodel.NodeObsFrps{}.BatchInsertSQL())
@@ -223,7 +224,7 @@ func BatchInsertNodeObsFrpc(ctx context.Context, observations []analyticsmodel.N
return nil
}
if db.ChConn == nil {
return fmt.Errorf("clickhouse connection is not initialized")
return errors.New("clickhouse connection is not initialized")
}
batch, err := db.ChConn.PrepareBatch(ctx, analyticsmodel.NodeObsFrpc{}.BatchInsertSQL())
+1 -2
View File
@@ -3,7 +3,6 @@ package repository
import (
"context"
"errors"
"fmt"
"gorm.io/gorm"
@@ -124,7 +123,7 @@ func ListZoneDomainsByIDs(ctx context.Context, domainIDs []uint) ([]model.ZoneDo
for _, id := range domainIDs {
domain, ok := byID[id]
if !ok {
return nil, fmt.Errorf("one or more zone domains do not exist")
return nil, errors.New("one or more zone domains do not exist")
}
ordered = append(ordered, domain)
}
+3 -3
View File
@@ -1,7 +1,7 @@
package geoip
import (
"fmt"
"errors"
"net"
)
@@ -20,12 +20,12 @@ func (e *EmptyProvider) Initialize() error {
// GetGeoInfo reports that no GeoIP provider has been configured.
func (e *EmptyProvider) GetGeoInfo(_ net.IP) (*GeoInfo, error) {
return nil, fmt.Errorf("you are using an empty GeoIP provider, please set a valid provider")
return nil, errors.New("you are using an empty GeoIP provider, please set a valid provider")
}
// UpdateDatabase reports that no GeoIP provider has been configured.
func (e *EmptyProvider) UpdateDatabase() error {
return fmt.Errorf("you are using an empty GeoIP provider, please set a valid provider")
return errors.New("you are using an empty GeoIP provider, please set a valid provider")
}
// Close releases resources held by the empty provider.
+3 -2
View File
@@ -2,6 +2,7 @@
package geoip
import (
"errors"
"fmt"
"log/slog"
"net"
@@ -138,7 +139,7 @@ func InitGeoIP(provider string) {
// GetGeoInfo looks up geographic information for ip using the active provider.
func GetGeoInfo(ip net.IP) (*GeoInfo, error) {
if ip == nil {
return nil, fmt.Errorf("IP address cannot be nil")
return nil, errors.New("IP address cannot be nil")
}
provider := getProvider()
cacheKey := provider.Name() + ":" + ip.String()
@@ -157,7 +158,7 @@ func GetGeoInfo(ip net.IP) (*GeoInfo, error) {
// LookupGeoInfoWithProvider looks up geographic information using a temporary provider.
func LookupGeoInfoWithProvider(providerName string, ip net.IP) (*GeoInfo, error) {
if ip == nil {
return nil, fmt.Errorf("IP address cannot be nil")
return nil, errors.New("IP address cannot be nil")
}
provider, err := providerFactory(normalizeProvider(providerName))
+3 -2
View File
@@ -2,6 +2,7 @@ package geoip
import (
"context"
"errors"
"fmt"
"io"
"net"
@@ -96,10 +97,10 @@ func (s *MaxMindGeoIPService) GetGeoInfo(ip net.IP) (*GeoInfo, error) {
defer s.mu.RUnlock()
if s.maxMindDBReader == nil {
return nil, fmt.Errorf("MaxMind database is not initialized or failed to open")
return nil, errors.New("MaxMind database is not initialized or failed to open")
}
if ip == nil {
return nil, fmt.Errorf("IP address cannot be nil")
return nil, errors.New("IP address cannot be nil")
}
var record Record
+2 -2
View File
@@ -72,14 +72,14 @@ func copyLimited(dst io.Writer, src io.Reader, maxBytes int64) (int64, error) {
return written, err
}
if written > maxBytes {
return written, fmt.Errorf("pages file size out of bounds")
return written, errors.New("pages file size out of bounds")
}
return written, nil
}
func copyAndVerifySize(dst io.Writer, src io.Reader, declaredSize uint64, maxBytes int64) (int64, error) {
if declaredSize > uint64(math.MaxInt64) {
return 0, fmt.Errorf("pages file size out of bounds")
return 0, errors.New("pages file size out of bounds")
}
written, err := copyLimited(dst, src, maxBytes)
if err != nil {
+3 -3
View File
@@ -124,7 +124,7 @@ func extractEntries(entries []Entry, destDir string, opts ExtractOptions) error
appendMeasuredFile(measured, normalizedPath, actual)
}
if measured.fileCount == 0 {
return fmt.Errorf("pages package is empty")
return errors.New("pages package is empty")
}
return nil
}
@@ -139,7 +139,7 @@ func extractTarFamilyAt(ra io.ReaderAt, size int64, format Format, destDir strin
return err
}
if firstPass.fileCount == 0 {
return fmt.Errorf("pages package is empty")
return errors.New("pages package is empty")
}
commonPrefix := ""
if opts.StripCommonRoot {
@@ -162,7 +162,7 @@ func extractTarFamilyAt(ra io.ReaderAt, size int64, format Format, destDir strin
return extractErr
}
if secondPass.fileCount != firstPass.fileCount || secondPass.totalSize != firstPass.totalSize {
return fmt.Errorf("pages tar package changed between validation and extraction")
return errors.New("pages tar package changed between validation and extraction")
}
return nil
}
+2 -2
View File
@@ -7,7 +7,7 @@ package pagesarchive
import (
"bytes"
"fmt"
"errors"
"path/filepath"
"strings"
)
@@ -87,7 +87,7 @@ func DetectFormat(fileName string, data []byte) (Format, error) {
if format, ok := DetectFormatFromBytes(data); ok {
return format, nil
}
return "", fmt.Errorf("unsupported pages package format")
return "", errors.New("unsupported pages package format")
}
// Extension returns the canonical file extension for a format (without leading dot).
+3 -3
View File
@@ -137,7 +137,7 @@ func scanTarFamilyAt(
enforceLimits bool,
) (*measuredArchive, error) {
if size < 0 {
return nil, fmt.Errorf("invalid pages package size")
return nil, errors.New("invalid pages package size")
}
tarReader, closeReader, err := openTarFamilyReader(io.NewSectionReader(ra, 0, size), format)
if err != nil {
@@ -183,7 +183,7 @@ func scanTarReader(tarReader *tar.Reader, limits Limits, enforceLimits bool) (*m
func buildMeasuredManifest(measured *measuredArchive, opts InspectOptions) (*Manifest, error) {
if measured == nil || measured.fileCount == 0 {
return nil, fmt.Errorf("pages package is empty")
return nil, errors.New("pages package is empty")
}
targetEntryPath, err := resolveTargetEntryPath(opts.RootDir, opts.EntryFile)
if err != nil {
@@ -231,7 +231,7 @@ func prepareMeasuredFile(measured *measuredArchive, normalizedPath string, decla
}
remaining := limits.MaxTotalBytes - measured.totalSize
if remaining < 0 || declaredSize > uint64(remaining) { //nolint:gosec // remaining is checked non-negative
return fmt.Errorf("pages extracted size exceeds limit")
return errors.New("pages extracted size exceeds limit")
}
return nil
}
+2 -1
View File
@@ -8,6 +8,7 @@ import (
"archive/zip"
"compress/bzip2"
"compress/gzip"
"errors"
"fmt"
"io"
"os"
@@ -52,7 +53,7 @@ func (z sevenZipArchiveFile) Open() (io.ReadCloser, error) {
// Tar-family archives use the sequential streaming paths in inspect.go/extract.go.
func listRandomAccessEntriesAt(ra io.ReaderAt, size int64, format Format) ([]Entry, error) {
if size < 0 {
return nil, fmt.Errorf("invalid pages package size")
return nil, errors.New("invalid pages package size")
}
switch format {
case FormatZip:
+5 -4
View File
@@ -4,6 +4,7 @@
package pagesarchive
import (
"errors"
"fmt"
"path"
"strings"
@@ -18,7 +19,7 @@ func NormalizeLogicalPath(raw string, allowEmpty bool) (string, error) {
if allowEmpty {
return "", nil
}
return "", fmt.Errorf("pages path is required")
return "", errors.New("pages path is required")
}
if err := validateLogicalPathText(raw); err != nil {
return "", err
@@ -29,7 +30,7 @@ func NormalizeLogicalPath(raw string, allowEmpty bool) (string, error) {
if allowEmpty {
return "", nil
}
return "", fmt.Errorf("pages path is required")
return "", errors.New("pages path is required")
}
if strings.HasPrefix(cleaned, "/") || cleaned == ".." || strings.HasPrefix(cleaned, "../") {
return "", fmt.Errorf("pages path escapes directory: %s", raw)
@@ -39,7 +40,7 @@ func NormalizeLogicalPath(raw string, allowEmpty bool) (string, error) {
func validateLogicalPathText(raw string) error {
if !utf8.ValidString(raw) {
return fmt.Errorf("pages path is not valid UTF-8")
return errors.New("pages path is not valid UTF-8")
}
if strings.Contains(raw, "\\") {
return fmt.Errorf("pages path must use POSIX separators: %s", raw)
@@ -56,7 +57,7 @@ func validateLogicalPathText(raw string) error {
func validateLogicalPathRunes(raw string) error {
for _, r := range raw {
if r == 0 || unicode.IsControl(r) {
return fmt.Errorf("pages path contains a control character")
return errors.New("pages path contains a control character")
}
if r == '\'' || r == '"' || r == ';' {
return fmt.Errorf("pages path contains an unsupported character: %s", raw)
+1 -1
View File
@@ -265,7 +265,7 @@ func (p *LarkPusher) ValidateConfig(cfg Config) error {
}
func larkSign(secret string, timestamp int64) (string, error) {
stringToSign := fmt.Sprintf("%v", timestamp) + "\n" + secret
stringToSign := strconv.FormatInt(timestamp, 10) + "\n" + secret
h := hmac.New(sha256.New, []byte(stringToSign))
_, err := h.Write(nil)
if err != nil {
+15 -14
View File
@@ -14,6 +14,7 @@ import (
"path"
"regexp"
"sort"
"strconv"
"strings"
)
@@ -168,32 +169,32 @@ func DedupeSupportFiles(files []SupportFile) []SupportFile {
func renderMainConfigTemplate(templateText string, cfg ConfigSnapshot, limitReqRates []string) string {
replacer := strings.NewReplacer(
"{{OpenRestyWorkerProcesses}}", cfg.WorkerProcesses,
"{{OpenRestyWorkerConnections}}", fmt.Sprintf("%d", cfg.WorkerConnections),
"{{OpenRestyWorkerRlimitNofile}}", fmt.Sprintf("%d", cfg.WorkerRlimitNofile),
"{{OpenRestyWorkerConnections}}", strconv.Itoa(cfg.WorkerConnections),
"{{OpenRestyWorkerRlimitNofile}}", strconv.Itoa(cfg.WorkerRlimitNofile),
"{{OpenRestyConnectionUpgradeMap}}", renderConnectionUpgradeMap(),
"{{OpenRestyDefaultServerBlock}}", renderDefaultServerBlock(cfg.DefaultServerReturnStatus, cfg.HTTP3Enabled),
"{{OpenRestyAccessLogPath}}", AccessLogPlaceholder,
"{{OpenRestyErrorLogPath}}", ErrorLogPlaceholder,
"{{OpenRestyEventsUseDirective}}", renderTemplateDirective(cfg.EventsUse != "", fmt.Sprintf("use %s;", cfg.EventsUse)),
"{{OpenRestyEventsMultiAcceptDirective}}", renderTemplateDirective(cfg.EventsMultiAcceptEnabled, "multi_accept on;"),
"{{OpenRestyKeepaliveTimeout}}", fmt.Sprintf("%d", cfg.KeepaliveTimeout),
"{{OpenRestyKeepaliveRequests}}", fmt.Sprintf("%d", cfg.KeepaliveRequests),
"{{OpenRestyClientHeaderTimeout}}", fmt.Sprintf("%d", cfg.ClientHeaderTimeout),
"{{OpenRestyClientBodyTimeout}}", fmt.Sprintf("%d", cfg.ClientBodyTimeout),
"{{OpenRestyKeepaliveTimeout}}", strconv.Itoa(cfg.KeepaliveTimeout),
"{{OpenRestyKeepaliveRequests}}", strconv.Itoa(cfg.KeepaliveRequests),
"{{OpenRestyClientHeaderTimeout}}", strconv.Itoa(cfg.ClientHeaderTimeout),
"{{OpenRestyClientBodyTimeout}}", strconv.Itoa(cfg.ClientBodyTimeout),
"{{OpenRestyClientMaxBodySize}}", cfg.ClientMaxBodySize,
"{{OpenRestyLargeClientHeaderBuffers}}", cfg.LargeClientHeaderBuffers,
"{{OpenRestySendTimeout}}", fmt.Sprintf("%d", cfg.SendTimeout),
"{{OpenRestyProxyConnectTimeout}}", fmt.Sprintf("%d", cfg.ProxyConnectTimeout),
"{{OpenRestyProxySendTimeout}}", fmt.Sprintf("%d", cfg.ProxySendTimeout),
"{{OpenRestyProxyReadTimeout}}", fmt.Sprintf("%d", cfg.ProxyReadTimeout),
"{{OpenRestySendTimeout}}", strconv.Itoa(cfg.SendTimeout),
"{{OpenRestyProxyConnectTimeout}}", strconv.Itoa(cfg.ProxyConnectTimeout),
"{{OpenRestyProxySendTimeout}}", strconv.Itoa(cfg.ProxySendTimeout),
"{{OpenRestyProxyReadTimeout}}", strconv.Itoa(cfg.ProxyReadTimeout),
"{{OpenRestyProxyRequestBuffering}}", onOff(cfg.ProxyRequestBuffering),
"{{OpenRestyProxyBuffering}}", onOff(cfg.ProxyBufferingEnabled),
"{{OpenRestyProxyBuffers}}", cfg.ProxyBuffers,
"{{OpenRestyProxyBufferSize}}", cfg.ProxyBufferSize,
"{{OpenRestyProxyBusyBuffersSize}}", cfg.ProxyBusyBuffersSize,
"{{OpenRestyGzip}}", onOff(cfg.GzipEnabled),
"{{OpenRestyGzipMinLength}}", fmt.Sprintf("%d", cfg.GzipMinLength),
"{{OpenRestyGzipCompLevel}}", fmt.Sprintf("%d", cfg.GzipCompLevel),
"{{OpenRestyGzipMinLength}}", strconv.Itoa(cfg.GzipMinLength),
"{{OpenRestyGzipCompLevel}}", strconv.Itoa(cfg.GzipCompLevel),
"{{OpenRestyResolverDirective}}", renderTemplateDirective(cfg.Resolvers != "", fmt.Sprintf("resolver %s;", cfg.Resolvers)),
"{{OpenRestyCacheBlock}}", renderOpenRestyCacheTemplateBlock(cfg, limitReqRates),
"{{OpenRestyRouteConfigInclude}}", RouteConfigPlaceholder,
@@ -765,7 +766,7 @@ func renderDefaultServerBlock(statusCode int, http3Enabled bool) string {
" }",
"",
" server {",
fmt.Sprintf(" listen 443 ssl default_server;%s", h3Default),
" listen 443 ssl default_server;" + h3Default,
" server_name _;",
"",
" ssl_reject_handshake on;",
@@ -946,7 +947,7 @@ func buildPathPrefixMatchPattern(rules []string) string {
parts = append(parts, "/")
continue
}
parts = append(parts, fmt.Sprintf("%s(?:/|$)", regexp.QuoteMeta(trimmed)))
parts = append(parts, regexp.QuoteMeta(trimmed)+"(?:/|$)")
}
return fmt.Sprintf("^(?:%s)", strings.Join(parts, "|"))
}
+2 -1
View File
@@ -4,6 +4,7 @@
package openresty
import (
"errors"
"fmt"
"sort"
"strconv"
@@ -22,7 +23,7 @@ const (
func ParseStatusCodeTag(tag string) (lo, hi int, err error) {
tag = strings.TrimSpace(tag)
if tag == "" {
return 0, 0, fmt.Errorf("状态码标签不能为空")
return 0, 0, errors.New("状态码标签不能为空")
}
if before, after, ok := strings.Cut(tag, "-"); ok {
lo, err = strconv.Atoi(before)
+3 -3
View File
@@ -29,13 +29,13 @@ func Bytes2Size(num int64) string {
numStr = fmt.Sprintf("%.2f", float64(num)/float64(sizeGB))
unit = "GB"
case num/int64(sizeMB) >= 1:
numStr = fmt.Sprintf("%d", int(float64(num)/float64(sizeMB)))
numStr = strconv.Itoa(int(float64(num) / float64(sizeMB)))
unit = "MB"
case num/int64(sizeKB) >= 1:
numStr = fmt.Sprintf("%d", int(float64(num)/float64(sizeKB)))
numStr = strconv.Itoa(int(float64(num) / float64(sizeKB)))
unit = "KB"
default:
numStr = fmt.Sprintf("%d", num)
numStr = strconv.FormatInt(num, 10)
}
return numStr + " " + unit
}
+5 -2
View File
@@ -1,6 +1,9 @@
package util
import "fmt"
import (
"fmt"
"strconv"
)
// Interface2String converts a string, int, or float64 value to its string representation.
func Interface2String(inter any) string {
@@ -8,7 +11,7 @@ func Interface2String(inter any) string {
case string:
return v
case int:
return fmt.Sprintf("%d", v)
return strconv.Itoa(v)
case float64:
return fmt.Sprintf("%f", v)
}
+3 -2
View File
@@ -6,6 +6,7 @@ package main
import (
"context"
"errors"
"fmt"
"os"
"time"
@@ -32,7 +33,7 @@ func main() {
func run() error {
if !db.ChConnReady() {
return fmt.Errorf("ChConn not ready — check config.yaml clickhouse.enabled")
return errors.New("ChConn not ready — check config.yaml clickhouse.enabled")
}
ctx := context.Background()
chwriter.Init(ctx)
@@ -76,7 +77,7 @@ func waitForSnapshot(ctx context.Context, nodeID string, now time.Time) error {
}
time.Sleep(pollInterval)
}
return fmt.Errorf("not flushed within timeout")
return errors.New("not flushed within timeout")
}
func assertLatestIncludes(ctx context.Context, nodeID string, now time.Time) error {