diff --git a/Makefile b/Makefile index bee1967..4b78c5c 100644 --- a/Makefile +++ b/Makefile @@ -289,6 +289,26 @@ lint: go vet ./...; \ fi +# 现代化检查(检测可使用新 Go 特性的代码) +modernize: + @echo "Running modernize analyzer..." + @if command -v modernize >/dev/null 2>&1; then \ + modernize ./internal/...; \ + else \ + echo "modernize not installed. Run: go install golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest"; \ + exit 1; \ + fi + +# 现代化检查并自动修复 +modernize-fix: + @echo "Running modernize analyzer with auto-fix..." + @if command -v modernize >/dev/null 2>&1; then \ + modernize -fix ./internal/...; \ + else \ + echo "modernize not installed. Run: go install golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest"; \ + exit 1; \ + fi + # 代码检查 check: fmt lint test-all @echo "All checks passed." @@ -405,6 +425,8 @@ help: @echo "Quality:" @echo " make fmt - Format code" @echo " make lint - Run linter" + @echo " make modernize - Check for modern Go patterns" + @echo " make modernize-fix - Auto-fix modern Go patterns" @echo " make check - Format + lint + test" @echo "" @echo "Dependencies:" diff --git a/internal/adapter/common.go b/internal/adapter/common.go index ecf77b5..0341627 100644 --- a/internal/adapter/common.go +++ b/internal/adapter/common.go @@ -36,7 +36,7 @@ const DefaultBodyThreshold = 64 * 1024 // 64KB // 使用 singleton 模式避免多个适配器实例创建多个 pool, // 提高内存复用效率。该 pool 被 HTTP/2 和 HTTP/3 适配器共享。 var bufferPoolInstance = &sync.Pool{ - New: func() interface{} { + New: func() any { buf := make([]byte, 4096) // 4KB 初始缓冲区 return &buf }, @@ -73,7 +73,7 @@ type CommonAdapter struct { func NewCommonAdapter() *CommonAdapter { return &CommonAdapter{ CtxPool: sync.Pool{ - New: func() interface{} { + New: func() any { return &fasthttp.RequestCtx{} }, }, diff --git a/internal/benchmark/tools/benchmark_context.go b/internal/benchmark/tools/benchmark_context.go index 394bbbd..b63e3b7 100644 --- a/internal/benchmark/tools/benchmark_context.go +++ b/internal/benchmark/tools/benchmark_context.go @@ -327,7 +327,7 @@ func NewBenchmarkContextPool(size int) *BenchmarkContextPool { pool: make(chan *BenchmarkContext, size), } // 预填充池 - for i := 0; i < size; i++ { + for range size { p.pool <- DefaultBenchmarkContext() } return p diff --git a/internal/benchmark/tools/loadgen.go b/internal/benchmark/tools/loadgen.go index 59ab7a9..424f87b 100644 --- a/internal/benchmark/tools/loadgen.go +++ b/internal/benchmark/tools/loadgen.go @@ -3,7 +3,7 @@ package tools import ( "math" - "sort" + "slices" "sync" "testing" "time" @@ -61,16 +61,14 @@ func (lg *FasthttpLoadGenerator) Run(n int, concurrency int) *LoadGenStats { start := time.Now() - for i := 0; i < concurrency; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range concurrency { + wg.Go(func() { req := fasthttp.AcquireRequest() resp := fasthttp.AcquireResponse() defer fasthttp.ReleaseRequest(req) defer fasthttp.ReleaseResponse(resp) - for j := 0; j < requestsPerWorker; j++ { + for range requestsPerWorker { req.SetRequestURI("http://" + lg.addr + "/") req.Header.SetMethod("GET") @@ -83,7 +81,7 @@ func (lg *FasthttpLoadGenerator) Run(n int, concurrency int) *LoadGenStats { errorChan <- err } } - }() + }) } wg.Wait() @@ -118,9 +116,7 @@ func (lg *FasthttpLoadGenerator) Run(n int, concurrency int) *LoadGenStats { // Calculate latency distribution if len(latencies) > 0 { - sort.Slice(latencies, func(i, j int) bool { - return latencies[i] < latencies[j] - }) + slices.Sort(latencies) lg.stats.MinLatency = latencies[0] lg.stats.MaxLatency = latencies[len(latencies)-1] diff --git a/internal/benchmark/tools/testdata.go b/internal/benchmark/tools/testdata.go index 235c1bf..37af25b 100644 --- a/internal/benchmark/tools/testdata.go +++ b/internal/benchmark/tools/testdata.go @@ -50,7 +50,7 @@ func createTestTargets(n int) ([]TestTarget, func()) { targets := make([]TestTarget, n) cleanups := make([]func(), n) - for i := 0; i < n; i++ { + for i := range n { body := GenerateTestData(Size1KB) addr, cleanup := SimpleMockBackend(200, body) targets[i] = TestTarget{ @@ -83,7 +83,7 @@ func CreateWeightedTestTargets(n int) ([]TestTarget, func()) { targets := make([]TestTarget, n) cleanups := make([]func(), n) - for i := 0; i < n; i++ { + for i := range n { body := GenerateTestData(Size1KB) addr, cleanup := SimpleMockBackend(200, body) // Vary weights: 1, 2, 3, etc. @@ -111,7 +111,7 @@ func CreateDelayedTestTargets(n int, baseDelay time.Duration) ([]TestTarget, fun targets := make([]TestTarget, n) cleanups := make([]func(), n) - for i := 0; i < n; i++ { + for i := range n { body := GenerateTestData(Size1KB) // Each target has increasing delay delay := baseDelay * time.Duration(i+1) @@ -140,7 +140,7 @@ func CreateErrorTestTargets(n int, baseErrorRate float64) ([]TestTarget, func()) targets := make([]TestTarget, n) cleanups := make([]func(), n) - for i := 0; i < n; i++ { + for i := range n { body := GenerateTestData(Size1KB) // Vary error rates slightly per target errorRate := baseErrorRate + float64(i)*0.05 diff --git a/internal/cache/cache_bench_test.go b/internal/cache/cache_bench_test.go index 93bf554..56b67f9 100644 --- a/internal/cache/cache_bench_test.go +++ b/internal/cache/cache_bench_test.go @@ -32,7 +32,7 @@ func BenchmarkFileCacheGet(b *testing.B) { fc := NewFileCache(int64(size), 0, 1*time.Hour) // 预填充缓存 - for i := 0; i < size; i++ { + for i := range size { path := fmt.Sprintf("/file%d.txt", i) data := []byte("cached data content") _ = fc.Set(path, data, int64(len(data)), time.Now()) @@ -62,7 +62,7 @@ func BenchmarkFileCacheSet(b *testing.B) { fc := NewFileCache(int64(size), 0, 1*time.Hour) // 预填充到容量上限 - for i := 0; i < size; i++ { + for i := range size { path := fmt.Sprintf("/file%d.txt", i) data := []byte("cached data content") _ = fc.Set(path, data, int64(len(data)), time.Now()) @@ -88,7 +88,7 @@ func BenchmarkFileCacheSet_Pooled(b *testing.B) { fc := NewFileCache(int64(size), 0, 1*time.Hour) // 预填充到容量上限,触发淘汰和 entry 复用 - for i := 0; i < size; i++ { + for i := range size { path := fmt.Sprintf("/file%d.txt", i) data := []byte("cached data content") _ = fc.Set(path, data, int64(len(data)), time.Now()) @@ -128,7 +128,7 @@ func BenchmarkFileCacheConcurrent(b *testing.B) { fc := NewFileCache(int64(size), 0, 1*time.Hour) // 预填充缓存 - for i := 0; i < size; i++ { + for i := range size { path := fmt.Sprintf("/file%d.txt", i) data := []byte("cached data content") _ = fc.Set(path, data, int64(len(data)), time.Now()) @@ -160,7 +160,7 @@ func BenchmarkFileCacheGetOnly(b *testing.B) { fc := NewFileCache(1000, 0, 1*time.Hour) // 预填充缓存 - for i := 0; i < 1000; i++ { + for i := range 1000 { path := fmt.Sprintf("/static/file%d.css", i) data := make([]byte, 1024) // 1KB 数据 _ = fc.Set(path, data, int64(len(data)), time.Now()) @@ -186,7 +186,7 @@ func BenchmarkFileCacheSizeEviction(b *testing.B) { // 预填充到接近容量上限 data := make([]byte, 1024) // 1KB 每条 - for i := 0; i < 1000; i++ { + for i := range 1000 { path := fmt.Sprintf("/file%d.txt", i) _ = fc.Set(path, data, int64(len(data)), time.Now()) } @@ -205,7 +205,7 @@ func BenchmarkFileCacheLRUTouch(b *testing.B) { fc := NewFileCache(100, 0, 1*time.Hour) // 预填充缓存 - for i := 0; i < 100; i++ { + for i := range 100 { path := fmt.Sprintf("/file%d.txt", i) data := []byte("cached data") _ = fc.Set(path, data, int64(len(data)), time.Now()) @@ -224,7 +224,7 @@ func BenchmarkProxyCacheGet(b *testing.B) { pc := NewProxyCache(nil, false, 0, 0, 0) // 预填充缓存 - for i := 0; i < 1000; i++ { + for i := range 1000 { origKey := fmt.Sprintf("key%d", i) hashKey := hashKeyBench(origKey) data := []byte("response body") @@ -264,7 +264,7 @@ func BenchmarkProxyCacheConcurrent(b *testing.B) { pc := NewProxyCache(nil, false, 0, 0, 0) // 预填充缓存 - for i := 0; i < 1000; i++ { + for i := range 1000 { origKey := fmt.Sprintf("key%d", i) hashKey := hashKeyBench(origKey) data := []byte("response body") @@ -301,7 +301,7 @@ func BenchmarkFileCacheSharded(b *testing.B) { // 单锁缓存 b.Run(fmt.Sprintf("SingleLock_Size%d", size), func(b *testing.B) { fc := NewFileCache(int64(size), 0, 1*time.Hour) - for i := 0; i < size; i++ { + for i := range size { path := fmt.Sprintf("/file%d.txt", i) data := []byte("cached data") _ = fc.Set(path, data, int64(len(data)), time.Now()) @@ -322,7 +322,7 @@ func BenchmarkFileCacheSharded(b *testing.B) { // 分片缓存 b.Run(fmt.Sprintf("Sharded_Size%d", size), func(b *testing.B) { sc := NewShardedFileCache(int64(size), 0, 1*time.Hour) - for i := 0; i < size; i++ { + for i := range size { path := fmt.Sprintf("/file%d.txt", i) data := []byte("cached data") _ = sc.Set(path, data, int64(len(data)), time.Now()) diff --git a/internal/cache/file_cache_allocation_test.go b/internal/cache/file_cache_allocation_test.go index 98f239c..50c5dc0 100644 --- a/internal/cache/file_cache_allocation_test.go +++ b/internal/cache/file_cache_allocation_test.go @@ -50,7 +50,7 @@ func BenchmarkFileCacheSetAllocation_Update(b *testing.B) { // 预填充缓存 data := []byte("test data content for benchmark") size := int64(len(data)) - for i := 0; i < 1000; i++ { + for i := range 1000 { path := fmt.Sprintf("/update/file%d.txt", i) fc.Set(path, data, size, time.Now()) } @@ -78,7 +78,7 @@ func BenchmarkFileCacheSetAllocation_Eviction(b *testing.B) { // 预填充到容量上限 data := []byte("test data content for benchmark") size := int64(len(data)) - for i := 0; i < 100; i++ { + for i := range 100 { path := fmt.Sprintf("/evict/file%d.txt", i) fc.Set(path, data, size, time.Now()) } @@ -103,7 +103,7 @@ func BenchmarkFileCacheSetAllocation_EvictionWithPool(b *testing.B) { size := int64(len(data)) // 预填充 - for i := 0; i < 100; i++ { + for i := range 100 { path := fmt.Sprintf("/pool/file%d.txt", i) fc.Set(path, data, size, time.Now()) } @@ -128,7 +128,7 @@ func BenchmarkFileCacheSetAllocation_MemoryLimit(b *testing.B) { size := int64(len(data)) // 预填充到接近上限 - for i := 0; i < 900; i++ { + for i := range 900 { path := fmt.Sprintf("/mem/file%d.txt", i) fc.Set(path, data, size, time.Now()) } @@ -172,7 +172,7 @@ func BenchmarkFileCacheSetAllocation_ConcurrentEviction(b *testing.B) { size := int64(len(data)) // 预填充 - for i := 0; i < 100; i++ { + for i := range 100 { path := fmt.Sprintf("/concevict/file%d.txt", i) fc.Set(path, data, size, time.Now()) } @@ -201,7 +201,7 @@ func BenchmarkFileCacheEntryPool_GetPut(b *testing.B) { } // 预填充池 - for i := 0; i < 100; i++ { + for range 100 { pool.Put(&FileEntry{}) } @@ -235,4 +235,4 @@ func BenchmarkFileCacheLRUList_PushFront(b *testing.B) { lruList.Remove(old) } } -} \ No newline at end of file +} diff --git a/internal/cache/sharded_cache.go b/internal/cache/sharded_cache.go index c511f38..50d853b 100644 --- a/internal/cache/sharded_cache.go +++ b/internal/cache/sharded_cache.go @@ -26,19 +26,19 @@ const shardCount = 16 // FileCacheShard 单个缓存分片。 type FileCacheShard struct { - entries map[string]*FileEntry - lruList *list.List - maxEntries int64 - maxSize int64 - inactive time.Duration + entries map[string]*FileEntry + lruList *list.List + maxEntries int64 + maxSize int64 + inactive time.Duration currentSize int64 - mu sync.RWMutex - entryPool sync.Pool + mu sync.RWMutex + entryPool sync.Pool } // ShardedFileCache 分片文件缓存。 type ShardedFileCache struct { - shards [shardCount]*FileCacheShard + shards [shardCount]*FileCacheShard maxEntries int64 maxSize int64 inactive time.Duration @@ -61,7 +61,7 @@ func NewShardedFileCache(maxEntries, maxSize int64, inactive time.Duration) *Sha perShardSize = maxSize } - for i := 0; i < shardCount; i++ { + for i := range shardCount { shard := &FileCacheShard{ maxEntries: perShardEntries, maxSize: perShardSize, @@ -83,7 +83,7 @@ func NewShardedFileCache(maxEntries, maxSize int64, inactive time.Duration) *Sha func (s *ShardedFileCache) getShard(path string) *FileCacheShard { h := fnv.New64a() h.Write([]byte(path)) - return s.shards[h.Sum64() % shardCount] + return s.shards[h.Sum64()%shardCount] } // Get 获取缓存的文件。 @@ -262,4 +262,4 @@ func (sh *FileCacheShard) evictLRU() { return } sh.removeEntry(entry) -} \ No newline at end of file +} diff --git a/internal/config/defaults_test.go b/internal/config/defaults_test.go index 594880e..ea54f77 100644 --- a/internal/config/defaults_test.go +++ b/internal/config/defaults_test.go @@ -89,22 +89,22 @@ func TestGenerateConfigYAMLFieldsCoverage(t *testing.T) { typ reflect.Type name string }{ - {reflect.TypeOf(GeoIPConfig{}), "GeoIPConfig"}, - {reflect.TypeOf(AuthRequestConfig{}), "AuthRequestConfig"}, - {reflect.TypeOf(LuaGlobalSettings{}), "LuaGlobalSettings"}, - {reflect.TypeOf(LimitRateConfig{}), "LimitRateConfig"}, - {reflect.TypeOf(TypesConfig{}), "TypesConfig"}, + {reflect.TypeFor[GeoIPConfig](), "GeoIPConfig"}, + {reflect.TypeFor[AuthRequestConfig](), "AuthRequestConfig"}, + {reflect.TypeFor[LuaGlobalSettings](), "LuaGlobalSettings"}, + {reflect.TypeFor[LimitRateConfig](), "LimitRateConfig"}, + {reflect.TypeFor[TypesConfig](), "TypesConfig"}, } for _, c := range checks { - for i := 0; i < c.typ.NumField(); i++ { - tag := c.typ.Field(i).Tag.Get("yaml") + for field := range c.typ.Fields() { + tag := field.Tag.Get("yaml") fieldName := strings.Split(tag, ",")[0] if fieldName == "" || fieldName == "-" { continue } if !strings.Contains(yamlStr, fieldName) { - t.Errorf("%s.%s (yaml:%q) not found in GenerateConfigYAML output", c.name, c.typ.Field(i).Name, fieldName) + t.Errorf("%s.%s (yaml:%q) not found in GenerateConfigYAML output", c.name, field.Name, fieldName) } } } diff --git a/internal/handler/errorpage_test.go b/internal/handler/errorpage_test.go index 64ef4fe..d016e2e 100644 --- a/internal/handler/errorpage_test.go +++ b/internal/handler/errorpage_test.go @@ -615,7 +615,7 @@ func TestErrorPageManager_SuccessfulLoad(t *testing.T) { defaultPage := filepath.Join(tmpDir, "default.html") for code, path := range pages { - content := []byte(fmt.Sprintf("Error %d page", code)) + content := fmt.Appendf(nil, "Error %d page", code) if err := os.WriteFile(path, content, 0o644); err != nil { t.Fatalf("创建页面 %d 失败: %v", code, err) } diff --git a/internal/handler/sendfile_test.go b/internal/handler/sendfile_test.go index d951e67..cb7a0fd 100644 --- a/internal/handler/sendfile_test.go +++ b/internal/handler/sendfile_test.go @@ -669,15 +669,13 @@ func TestLinuxSendfile_WithTCPConn(t *testing.T) { var serverConn net.Conn var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { serverConn, _ = ln.Accept() // 读取所有数据 buf := make([]byte, len(content)) _, _ = io.ReadFull(serverConn, buf) serverConn.Close() - }() + }) clientConn, err := net.Dial("tcp", ln.Addr().String()) if err != nil { @@ -827,15 +825,13 @@ func TestLinuxSendfile_PartialTransfer(t *testing.T) { var serverConn net.Conn var received []byte var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { serverConn, _ = ln.Accept() buf := make([]byte, len(content)) n, _ := serverConn.Read(buf) received = buf[:n] serverConn.Close() - }() + }) clientConn, err := net.Dial("tcp", ln.Addr().String()) if err != nil { @@ -888,14 +884,12 @@ func TestLinuxSendfile_WithOffset(t *testing.T) { var serverConn net.Conn var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { serverConn, _ = ln.Accept() buf := make([]byte, 8*1024) _, _ = serverConn.Read(buf) serverConn.Close() - }() + }) clientConn, err := net.Dial("tcp", ln.Addr().String()) if err != nil { diff --git a/internal/http2/adapter_test.go b/internal/http2/adapter_test.go index 3b54fae..2ce7268 100644 --- a/internal/http2/adapter_test.go +++ b/internal/http2/adapter_test.go @@ -439,7 +439,7 @@ func TestAdapterConcurrentRequests(t *testing.T) { concurrency := 10 done := make(chan bool, concurrency) - for i := 0; i < concurrency; i++ { + for range concurrency { go func() { req := httptest.NewRequest(http.MethodGet, "/test", nil) rec := httptest.NewRecorder() @@ -453,7 +453,7 @@ func TestAdapterConcurrentRequests(t *testing.T) { } // 等待所有请求完成 - for i := 0; i < concurrency; i++ { + for range concurrency { <-done } } diff --git a/internal/http2/integration_test.go b/internal/http2/integration_test.go index b164c5c..90d467f 100644 --- a/internal/http2/integration_test.go +++ b/internal/http2/integration_test.go @@ -16,6 +16,7 @@ import ( "net" "net/http" "net/http/httptest" + "slices" "testing" "time" @@ -101,13 +102,7 @@ func TestIntegrationALPN(t *testing.T) { } // 验证协议列表 - foundH2 := false - for _, proto := range tlsConfig.NextProtos { - if proto == "h2" { - foundH2 = true - break - } - } + foundH2 := slices.Contains(tlsConfig.NextProtos, "h2") if !foundH2 { t.Error("ALPN config should include h2 protocol") } diff --git a/internal/http2/integration_tls_test.go b/internal/http2/integration_tls_test.go index adaf99a..5342948 100644 --- a/internal/http2/integration_tls_test.go +++ b/internal/http2/integration_tls_test.go @@ -18,6 +18,7 @@ import ( "math/big" "net" "net/http" + "slices" "sync" "testing" "time" @@ -232,13 +233,7 @@ func TestALPNNegotiationH2(t *testing.T) { t.Fatal("ALPN config should not be nil") } - foundH2 := false - for _, proto := range alpnConfig.NextProtos { - if proto == "h2" { - foundH2 = true - break - } - } + foundH2 := slices.Contains(alpnConfig.NextProtos, "h2") if !foundH2 { t.Error("ALPN config should include h2 protocol") } @@ -397,11 +392,9 @@ func TestServeHTTP1Fallback(t *testing.T) { }() var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { server.serveHTTP1(serverConn) - }() + }) // 发送 HTTP/1.1 请求 request := "GET /test HTTP/1.1\r\nHost: localhost\r\n\r\n" diff --git a/internal/http2/server.go b/internal/http2/server.go index 30006db..7890455 100644 --- a/internal/http2/server.go +++ b/internal/http2/server.go @@ -23,6 +23,7 @@ import ( "net" "net/http" "net/textproto" + "slices" "sync" "time" @@ -330,13 +331,7 @@ func WrapTLSListener(ln net.Listener, tlsConfig *tls.Config) net.Listener { originalGetConfig := tlsConfig.GetConfigForClient tlsConfig.GetConfigForClient = func(hello *tls.ClientHelloInfo) (*tls.Config, error) { // 检查客户端是否支持 h2 - supportsH2 := false - for _, proto := range hello.SupportedProtos { - if proto == "h2" { - supportsH2 = true - break - } - } + supportsH2 := slices.Contains(hello.SupportedProtos, "h2") // 如果有原始回调,先调用它 var cfg *tls.Config diff --git a/internal/http3/server_test.go b/internal/http3/server_test.go index 445e7d0..655c0e1 100644 --- a/internal/http3/server_test.go +++ b/internal/http3/server_test.go @@ -339,7 +339,7 @@ func TestServer_MultipleStop(t *testing.T) { server, _ := NewServer(cfg, handler, &tls.Config{}) // 多次调用 Stop 应该都是安全的 - for i := 0; i < 3; i++ { + for i := range 3 { err := server.Stop() if err != nil { t.Errorf("Stop call %d returned error: %v", i+1, err) @@ -358,7 +358,7 @@ func TestServer_MultipleGracefulStop(t *testing.T) { server, _ := NewServer(cfg, handler, &tls.Config{}) // 多次调用 GracefulStop 应该都是安全的 - for i := 0; i < 3; i++ { + for i := range 3 { err := server.GracefulStop(1 * time.Second) if err != nil { t.Errorf("GracefulStop call %d returned error: %v", i+1, err) diff --git a/internal/integration/e2e_bench_test.go b/internal/integration/e2e_bench_test.go index a6d51f1..17fc0d1 100644 --- a/internal/integration/e2e_bench_test.go +++ b/internal/integration/e2e_bench_test.go @@ -249,7 +249,7 @@ func createTestProxy(backendAddr, path string) (*proxy.Proxy, error) { // - path: 请求路径 // - count: 预热请求数量 func warmupProxy(p *proxy.Proxy, path string, count int) { - for i := 0; i < count; i++ { + for range count { ctx := &fasthttp.RequestCtx{} ctx.Request.SetRequestURI(path) ctx.Request.Header.SetMethod(fasthttp.MethodGet) @@ -299,11 +299,11 @@ func BenchmarkE2EStaticFile(b *testing.B) { b.ReportAllocs() paths := []string{"/small.css", "/medium.json", "/assets/app.js", "/index.html"} - var counter uint64 + var counter atomic.Uint64 b.RunParallel(func(pb *testing.PB) { for pb.Next() { - idx := atomic.AddUint64(&counter, 1) + idx := counter.Add(1) ctx := &fasthttp.RequestCtx{} ctx.Request.SetRequestURI(paths[idx%uint64(len(paths))]) ctx.Request.Header.SetMethod(fasthttp.MethodGet) @@ -336,11 +336,11 @@ func BenchmarkE2EStaticFileCacheHit(b *testing.B) { b.ReportAllocs() paths := []string{"/small.css", "/medium.json", "/assets/app.js", "/index.html"} - var counter uint64 + var counter atomic.Uint64 b.RunParallel(func(pb *testing.PB) { for pb.Next() { - idx := atomic.AddUint64(&counter, 1) + idx := counter.Add(1) ctx := &fasthttp.RequestCtx{} ctx.Request.SetRequestURI(paths[idx%uint64(len(paths))]) ctx.Request.Header.SetMethod(fasthttp.MethodGet) @@ -568,7 +568,7 @@ ngx.header["X-Lua-Processed"] = "true"` finalHandler := chain.Apply(wrappedByLua) // 预热 Lua 引擎(字节码缓存) - for i := 0; i < 5; i++ { + for range 5 { ctx := &fasthttp.RequestCtx{} ctx.Request.SetRequestURI("/api/test") ctx.Request.Header.SetMethod(fasthttp.MethodGet) @@ -638,7 +638,7 @@ func BenchmarkE2EMultiLuaPhase(b *testing.B) { finalHandler := baseChain.Apply(wrappedByLua) // 预热 - for i := 0; i < 5; i++ { + for range 5 { ctx := &fasthttp.RequestCtx{} ctx.Request.SetRequestURI("/api/test") ctx.Request.Header.SetMethod(fasthttp.MethodGet) @@ -884,7 +884,7 @@ func BenchmarkE2EMultipleRoutes(b *testing.B) { b.ReportAllocs() // 使用原子计数器轮询不同路径 - var counter uint64 + var counter atomic.Uint64 paths := []string{ "/api/v1/users", "/api/v2/items", @@ -899,7 +899,7 @@ func BenchmarkE2EMultipleRoutes(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { - idx := atomic.AddUint64(&counter, 1) + idx := counter.Add(1) ctx := &fasthttp.RequestCtx{} ctx.Request.SetRequestURI(paths[idx%uint64(len(paths))]) ctx.Request.Header.SetMethod(fasthttp.MethodGet) @@ -955,7 +955,7 @@ func BenchmarkE2EMultipleRoutesWithMiddleware(b *testing.B) { b.ResetTimer() b.ReportAllocs() - var counter uint64 + var counter atomic.Uint64 testPaths := []string{ "/api/users", "/api/users/42", @@ -968,7 +968,7 @@ func BenchmarkE2EMultipleRoutesWithMiddleware(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { - idx := atomic.AddUint64(&counter, 1) + idx := counter.Add(1) ctx := &fasthttp.RequestCtx{} ctx.Request.SetRequestURI(testPaths[idx%uint64(len(testPaths))]) ctx.Request.Header.SetMethod(fasthttp.MethodGet) @@ -1152,7 +1152,7 @@ func BenchmarkE2EInmemoryServer(b *testing.B) { b.ResetTimer() b.ReportAllocs() - var counter uint64 + var counter atomic.Uint64 paths := []string{"/api/test", "/static/small.css", "/static/medium.json", "/health", "/api/data"} b.RunParallel(func(pb *testing.PB) { @@ -1162,7 +1162,7 @@ func BenchmarkE2EInmemoryServer(b *testing.B) { defer fasthttp.ReleaseResponse(resp) for pb.Next() { - idx := atomic.AddUint64(&counter, 1) + idx := counter.Add(1) req.SetRequestURI("http://localhost" + paths[idx%uint64(len(paths))]) req.Header.SetMethod(fasthttp.MethodGet) req.Header.Set("Host", "example.com") @@ -1316,11 +1316,11 @@ func BenchmarkE2ERewriteMiddleware(b *testing.B) { "/old-api/settings", "/v1/data/123", } - var counter uint64 + var counter atomic.Uint64 b.RunParallel(func(pb *testing.PB) { for pb.Next() { - idx := atomic.AddUint64(&counter, 1) + idx := counter.Add(1) ctx := &fasthttp.RequestCtx{} ctx.Request.SetRequestURI(paths[idx%uint64(len(paths))]) ctx.Request.Header.SetMethod(fasthttp.MethodGet) @@ -1365,11 +1365,11 @@ func BenchmarkE2EAccessControl(b *testing.B) { allowedIPs := []string{"192.168.1.50", "192.168.1.200", "10.0.0.1", "10.1.2.3"} deniedIPs := []string{"192.168.1.100", "172.16.0.1", "8.8.8.8"} allIPs := append(allowedIPs, deniedIPs...) - var counter uint64 + var counter atomic.Uint64 b.RunParallel(func(pb *testing.PB) { for pb.Next() { - idx := atomic.AddUint64(&counter, 1) + idx := counter.Add(1) clientIP := allIPs[idx%uint64(len(allIPs))] ctx := &fasthttp.RequestCtx{} ctx.Request.SetRequestURI("/api/test") @@ -1416,11 +1416,11 @@ func BenchmarkE2ERateLimiter(b *testing.B) { b.ResetTimer() b.ReportAllocs() - var counter uint64 + var counter atomic.Uint64 b.RunParallel(func(pb *testing.PB) { for pb.Next() { - idx := atomic.AddUint64(&counter, 1) + idx := counter.Add(1) ctx := &fasthttp.RequestCtx{} ctx.Request.SetRequestURI("/api/test") ctx.Request.Header.SetMethod(fasthttp.MethodGet) @@ -1470,7 +1470,7 @@ func BenchmarkE2EBasicAuth(b *testing.B) { b.ReportAllocs() // 预热认证(缓存 bcrypt 结果) - for i := 0; i < 3; i++ { + for range 3 { ctx := &fasthttp.RequestCtx{} ctx.Request.SetRequestURI("/api/test") ctx.Request.Header.SetMethod(fasthttp.MethodGet) diff --git a/internal/integration/e2e_failover_bench_test.go b/internal/integration/e2e_failover_bench_test.go index 3b4d64f..9851f09 100644 --- a/internal/integration/e2e_failover_bench_test.go +++ b/internal/integration/e2e_failover_bench_test.go @@ -37,7 +37,7 @@ func setupFailoverBackends(b *testing.B, count, healthyCount int) ([]*loadbalanc targets := make([]*loadbalance.Target, count) cleanups := make([]func(), count) - for i := 0; i < count; i++ { + for i := range count { addr, cleanup := setupNetworkBackend(b, fasthttp.StatusOK, []byte(`{"backend":`+strconv.Itoa(i)+`}`)) cleanups[i] = cleanup targets[i] = &loadbalance.Target{ @@ -215,8 +215,8 @@ func BenchmarkE2EFailover_DynamicToggle(b *testing.B) { for pb.Next() { // 每 100 次请求切换一个后端的健康状态 count := toggleCounter.Add(1) - if count % 100 == 0 { - targetIdx := int(count / 100) % len(targets) + if count%100 == 0 { + targetIdx := int(count/100) % len(targets) current := targets[targetIdx].Healthy.Load() targets[targetIdx].Healthy.Store(!current) } @@ -271,7 +271,7 @@ func BenchmarkE2EFailover_AllUnhealthy(b *testing.B) { // 验证负载均衡器选择逻辑的分配。 func BenchmarkE2EFailover_SelectOnly(b *testing.B) { targets := make([]*loadbalance.Target, 5) - for i := 0; i < 5; i++ { + for i := range 5 { targets[i] = &loadbalance.Target{ URL: "http://backend" + strconv.Itoa(i) + ":8080", Weight: 1, @@ -287,4 +287,4 @@ func BenchmarkE2EFailover_SelectOnly(b *testing.B) { for b.Loop() { _ = rr.Select(targets) } -} \ No newline at end of file +} diff --git a/internal/integration/variable_test.go b/internal/integration/variable_test.go index 761e1a7..66a6113 100644 --- a/internal/integration/variable_test.go +++ b/internal/integration/variable_test.go @@ -199,7 +199,7 @@ func TestVariablePerformance(t *testing.T) { // 执行多次展开 start := time.Now() iterations := 10000 - for i := 0; i < iterations; i++ { + for range iterations { _ = vc.Expand(template) } elapsed := time.Since(start) diff --git a/internal/loadbalance/balancer.go b/internal/loadbalance/balancer.go index fcf2a8e..832949d 100644 --- a/internal/loadbalance/balancer.go +++ b/internal/loadbalance/balancer.go @@ -105,7 +105,7 @@ type Balancer interface { // 并发安全:counter 使用 atomic 操作,支持多 goroutine 并发调用。 type RoundRobin struct { // counter 请求计数器,原子递增,用于确定轮询位置 - counter uint64 + counter atomic.Uint64 } // NewRoundRobin 创建一个新的轮询负载均衡器。 @@ -128,7 +128,7 @@ func (r *RoundRobin) Select(targets []*Target) *Target { } // 原子地递增并获取计数器值 - idx := atomic.AddUint64(&r.counter, 1) - 1 + idx := r.counter.Add(1) - 1 return healthy[idx%uint64(len(healthy))] } @@ -139,7 +139,7 @@ func (r *RoundRobin) Select(targets []*Target) *Target { // 并发安全:counter 使用 atomic 操作,支持多 goroutine 并发调用。 type WeightedRoundRobin struct { // counter 请求计数器,原子递增,用于确定权重分布位置 - counter uint64 + counter atomic.Uint64 } // NewWeightedRoundRobin 创建一个新的权重轮询负载均衡器。 @@ -176,7 +176,7 @@ func (w *WeightedRoundRobin) Select(targets []*Target) *Target { } // 使用原子计数器确定权重分布中的位置 - idx := atomic.AddUint64(&w.counter, 1) - 1 + idx := w.counter.Add(1) - 1 pos := int(idx % uint64(totalWeight)) // 找到计算位置处的目标 @@ -430,7 +430,7 @@ func (r *RoundRobin) SelectExcluding(targets []*Target, excluded []*Target) *Tar } // 原子地递增并获取计数器值 - idx := atomic.AddUint64(&r.counter, 1) - 1 + idx := r.counter.Add(1) - 1 return available[idx%uint64(len(available))] } @@ -457,7 +457,7 @@ func (w *WeightedRoundRobin) SelectExcluding(targets []*Target, excluded []*Targ } // 使用原子计数器确定权重分布中的位置 - idx := atomic.AddUint64(&w.counter, 1) - 1 + idx := w.counter.Add(1) - 1 pos := int(idx % uint64(totalWeight)) // 找到计算位置处的目标 diff --git a/internal/loadbalance/balancer_bench_test.go b/internal/loadbalance/balancer_bench_test.go index afcab34..2e4e201 100644 --- a/internal/loadbalance/balancer_bench_test.go +++ b/internal/loadbalance/balancer_bench_test.go @@ -34,7 +34,7 @@ import ( // - 包含 count 个健康目标的切片,权重均为 1 func generateTargets(count int) []*Target { targets := make([]*Target, count) - for i := 0; i < count; i++ { + for i := range count { targets[i] = &Target{ URL: fmt.Sprintf("http://backend%d:8080", i), Weight: 1, @@ -54,7 +54,7 @@ func generateTargets(count int) []*Target { // - 包含 count 个健康目标的切片,按 weights 分配权重 func generateWeightedTargets(count int, weights []int) []*Target { targets := make([]*Target, count) - for i := 0; i < count; i++ { + for i := range count { weight := 1 if i < len(weights) { weight = weights[i] @@ -160,7 +160,7 @@ func BenchmarkConsistentHashSelect(b *testing.B) { ch.Rebuild(targets) keys := make([]string, 100) - for i := 0; i < 100; i++ { + for i := range 100 { keys[i] = fmt.Sprintf("192.168.1.%d", i) } @@ -284,7 +284,7 @@ func BenchmarkIPHashSelect(b *testing.B) { iph := NewIPHash() ips := make([]string, 100) - for i := 0; i < 100; i++ { + for i := range 100 { ips[i] = fmt.Sprintf("192.168.1.%d", i) } diff --git a/internal/loadbalance/balancer_test.go b/internal/loadbalance/balancer_test.go index 94f0567..9f31be9 100644 --- a/internal/loadbalance/balancer_test.go +++ b/internal/loadbalance/balancer_test.go @@ -124,12 +124,10 @@ func TestRoundRobin_Select(t *testing.T) { } var wg sync.WaitGroup - for i := 0; i < 100; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 100 { + wg.Go(func() { _ = rr.Select(targets) - }() + }) } wg.Wait() }) @@ -148,7 +146,7 @@ func TestWeightedRoundRobin_Select(t *testing.T) { // 统计选择次数 counts := make(map[string]int) - for i := 0; i < 400; i++ { + for range 400 { got := wrr.Select(targets) if got == nil { t.Fatal("Select() = nil, want non-nil") @@ -175,7 +173,7 @@ func TestWeightedRoundRobin_Select(t *testing.T) { // 权重为0的目标应该被当作权重为1处理 counts := make(map[string]int) - for i := 0; i < 100; i++ { + for range 100 { got := wrr.Select(targets) if got == nil { t.Fatal("Select() = nil, want non-nil") @@ -225,7 +223,7 @@ func TestWeightedRoundRobin_Select(t *testing.T) { targets[1].Healthy.Store(true) // 所有选择都应该落在健康目标上 - for i := 0; i < 50; i++ { + for range 50 { got := wrr.Select(targets) if got == nil { t.Fatal("Select() = nil, want non-nil") @@ -331,7 +329,7 @@ func TestIPHash_Select(t *testing.T) { // 使用相同的IP地址多次选择 clientIP := "192.168.1.100" var firstSelection *Target - for i := 0; i < 10; i++ { + for range 10 { got := ih.SelectByIP(targets, clientIP) if got == nil { t.Fatal("SelectByIP() = nil, want non-nil") @@ -447,12 +445,10 @@ func TestConnectionsAtomic(t *testing.T) { target.Healthy.Store(true) var wg sync.WaitGroup - for i := 0; i < 1000; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 1000 { + wg.Go(func() { IncrementConnections(target) - }() + }) } wg.Wait() @@ -466,12 +462,10 @@ func TestConnectionsAtomic(t *testing.T) { target.Healthy.Store(true) var wg sync.WaitGroup - for i := 0; i < 1000; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 1000 { + wg.Go(func() { DecrementConnections(target) - }() + }) } wg.Wait() @@ -486,20 +480,16 @@ func TestConnectionsAtomic(t *testing.T) { var wg sync.WaitGroup // 500个增加 - for i := 0; i < 500; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 500 { + wg.Go(func() { IncrementConnections(target) - }() + }) } // 300个减少 - for i := 0; i < 300; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 300 { + wg.Go(func() { DecrementConnections(target) - }() + }) } wg.Wait() @@ -727,7 +717,7 @@ func TestConsistentHash(t *testing.T) { // 相同的键应该选择相同的目标 key := "192.168.1.100" first := ch.SelectByKey(targets, key) - for i := 0; i < 10; i++ { + for range 10 { got := ch.SelectByKey(targets, key) if got == nil { t.Fatal("SelectByKey() = nil") @@ -814,7 +804,7 @@ func TestConsistentHashSelectExcludingByKey(t *testing.T) { key := "192.168.1.100" // 多次选择,验证不会选中排除的目标 - for i := 0; i < 100; i++ { + for range 100 { got := ch.SelectExcludingByKey(targets, excluded, key) if got == nil { t.Fatal("SelectExcludingByKey() = nil, want non-nil") @@ -877,17 +867,15 @@ func TestConsistentHashSelectExcludingByKey(t *testing.T) { key := "192.168.1.100" var wg sync.WaitGroup - for i := 0; i < 100; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < 100; j++ { + for range 100 { + wg.Go(func() { + for range 100 { got := ch.SelectExcludingByKey(targets, excluded, key) if got != nil && got.URL == targets[0].URL { t.Errorf("并发时选中了被排除的目标: %q", got.URL) } } - }() + }) } wg.Wait() }) @@ -906,7 +894,7 @@ func TestConsistentHashSelectExcludingByKey(t *testing.T) { // 相同键应该始终返回相同的目标 var firstSelection *Target - for i := 0; i < 50; i++ { + for range 50 { got := ch.SelectExcludingByKey(targets, excluded, key) if got == nil { t.Fatal("SelectExcludingByKey() = nil, want non-nil") @@ -1021,15 +1009,13 @@ func TestRoundRobin_SelectExcluding(t *testing.T) { excluded := []*Target{targets[0]} var wg sync.WaitGroup - for i := 0; i < 100; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 100 { + wg.Go(func() { got := rr.SelectExcluding(targets, excluded) if got != nil && got.URL == targets[0].URL { t.Errorf("选中了被排除的目标: %q", got.URL) } - }() + }) } wg.Wait() }) @@ -1066,7 +1052,7 @@ func TestWeightedRoundRobin_SelectExcluding(t *testing.T) { excluded := []*Target{targets[1]} // 排除高权重目标后,只应选低权重目标 - for i := 0; i < 20; i++ { + for range 20 { got := wrr.SelectExcluding(targets, excluded) if got == nil { t.Fatal("SelectExcluding() = nil, want non-nil") @@ -1518,15 +1504,13 @@ func TestLeastConnections_ConcurrentSelection(t *testing.T) { lc := NewLeastConnections() var wg sync.WaitGroup - for i := 0; i < 100; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 100 { + wg.Go(func() { got := lc.Select(targets) if got == nil { t.Error("并发Select() = nil, want non-nil") } - }() + }) } wg.Wait() } @@ -1542,15 +1526,13 @@ func TestWeightedRoundRobin_ConcurrentSelection(t *testing.T) { wrr := NewWeightedRoundRobin() var wg sync.WaitGroup - for i := 0; i < 100; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 100 { + wg.Go(func() { got := wrr.Select(targets) if got == nil { t.Error("并发Select() = nil, want non-nil") } - }() + }) } wg.Wait() } @@ -1564,7 +1546,7 @@ func TestIPHash_ConcurrentSelection(t *testing.T) { ih := NewIPHash() var wg sync.WaitGroup - for i := 0; i < 100; i++ { + for i := range 100 { wg.Add(1) go func(ip string) { defer wg.Done() @@ -1691,7 +1673,7 @@ func TestWeightedRoundRobin_NegativeWeight(t *testing.T) { // 负权重要被当作1处理 counts := make(map[string]int) - for i := 0; i < 100; i++ { + for range 100 { got := wrr.Select(targets) if got == nil { t.Fatal("Select() = nil, want non-nil") @@ -1885,7 +1867,7 @@ func TestConsistentHash_Select(t *testing.T) { // 多次调用应该返回相同结果(空键的一致性) first := ch.Select(targets) - for i := 0; i < 10; i++ { + for range 10 { got := ch.Select(targets) if got == nil { t.Fatal("Select() = nil, want non-nil") @@ -2013,7 +1995,7 @@ func TestRandomBalancer(t *testing.T) { b := NewRandom() // 多次选择,验证总是选择连接数少的目标 - for i := 0; i < 100; i++ { + for range 100 { selected := b.Select(targets) if selected == nil { t.Error("should select a target") @@ -2037,7 +2019,7 @@ func TestRandomBalancer(t *testing.T) { // 连接数相等时,两个目标都应该被选中 counts := make(map[string]int) - for i := 0; i < 100; i++ { + for range 100 { selected := b.Select(targets) if selected != nil { counts[selected.URL]++ diff --git a/internal/loadbalance/consistent_hash.go b/internal/loadbalance/consistent_hash.go index 68317d5..60caea5 100644 --- a/internal/loadbalance/consistent_hash.go +++ b/internal/loadbalance/consistent_hash.go @@ -17,6 +17,7 @@ package loadbalance import ( "fmt" "hash/fnv" + "slices" "sort" "sync" ) @@ -138,9 +139,7 @@ func (c *ConsistentHash) rebuildCircle(targets []*Target) { } // 排序哈希值 - sort.Slice(c.sortedHashes, func(i, j int) bool { - return c.sortedHashes[i] < c.sortedHashes[j] - }) + slices.Sort(c.sortedHashes) } // hashKeyString 计算字符串的哈希值(使用 FNV-64a)。 diff --git a/internal/loadbalance/slow_start.go b/internal/loadbalance/slow_start.go index 7799f05..a8c8d8b 100644 --- a/internal/loadbalance/slow_start.go +++ b/internal/loadbalance/slow_start.go @@ -13,6 +13,7 @@ package loadbalance import ( + "maps" "sync" "sync/atomic" "time" @@ -143,13 +144,7 @@ func (m *SlowStartManager) updateEffectiveWeights() { // 线性增长:从 1 增加到 BaseWeight progress := float64(elapsed) / float64(state.SlowStart) - effectiveWeight := int(1 + progress*float64(state.BaseWeight-1)) - if effectiveWeight < 1 { - effectiveWeight = 1 - } - if effectiveWeight > state.BaseWeight { - effectiveWeight = state.BaseWeight - } + effectiveWeight := min(max(int(1+progress*float64(state.BaseWeight-1)), 1), state.BaseWeight) // 查找目标并更新 EffectiveWeight if m.findTarget != nil { @@ -184,8 +179,6 @@ func (m *SlowStartManager) GetAllStates() map[string]*SlowStartState { defer m.mu.RUnlock() result := make(map[string]*SlowStartState, len(m.targets)) - for k, v := range m.targets { - result[k] = v - } + maps.Copy(result, m.targets) return result } diff --git a/internal/lua/api_location.go b/internal/lua/api_location.go index 95bb8bd..2bade37 100644 --- a/internal/lua/api_location.go +++ b/internal/lua/api_location.go @@ -81,7 +81,7 @@ func (m *LocationManager) Register(location string, handler fasthttp.RequestHand // 返回值: // - *LocationCaptureResult: 子请求响应结果 // - error: 当前实现始终返回 nil -func (m *LocationManager) Capture(parentCtx *fasthttp.RequestCtx, location string, opts map[string]interface{}) (*LocationCaptureResult, error) { +func (m *LocationManager) Capture(parentCtx *fasthttp.RequestCtx, location string, opts map[string]any) (*LocationCaptureResult, error) { m.mu.Lock() handler, ok := m.handlers[location] m.mu.Unlock() @@ -175,7 +175,7 @@ func RegisterLocationAPI(L *glua.LState, manager *LocationManager, ngx *glua.LTa uri := L.CheckString(1) // 解析选项 - opts := make(map[string]interface{}) + opts := make(map[string]any) if L.GetTop() >= 2 { optionsTable := L.CheckTable(2) optionsTable.ForEach(func(key, value glua.LValue) { diff --git a/internal/lua/api_location_test.go b/internal/lua/api_location_test.go index c98c3bc..baa701d 100644 --- a/internal/lua/api_location_test.go +++ b/internal/lua/api_location_test.go @@ -78,7 +78,7 @@ func TestLocationManagerCaptureWithOptions(t *testing.T) { parentCtx.Request.SetRequestURI("/parent") // 使用自定义选项 - opts := map[string]interface{}{ + opts := map[string]any{ "method": "POST", "body": "test body", } diff --git a/internal/lua/api_socket_tcp.go b/internal/lua/api_socket_tcp.go index 1d4b23f..fc8a749 100644 --- a/internal/lua/api_socket_tcp.go +++ b/internal/lua/api_socket_tcp.go @@ -70,7 +70,7 @@ type TCPSocket struct { mu sync.RWMutex // closed 关闭标记(原子操作) - closed int32 + closed atomic.Int32 } // NewTCPSocket 创建新的 TCP socket 实例。 @@ -416,7 +416,7 @@ func (s *TCPSocket) ReceiveUntil(pattern string, inclusive bool) ([]byte, error) // 检查是否匹配模式 if len(result) >= patternLen { matched := true - for i := 0; i < patternLen; i++ { + for i := range patternLen { if result[len(result)-patternLen+i] != patternBytes[i] { matched = false break @@ -442,7 +442,7 @@ func (s *TCPSocket) Close() error { if s == nil { return nil } - if !atomic.CompareAndSwapInt32(&s.closed, 0, 1) { + if !s.closed.CompareAndSwap(0, 1) { return nil // 已经关闭 } @@ -507,7 +507,7 @@ func (s *TCPSocket) setState(state SocketState) { // IsClosed 检查是否已关闭 func (s *TCPSocket) IsClosed() bool { - return atomic.LoadInt32(&s.closed) == 1 + return s.closed.Load() == 1 } // LocalAddr 获取本地地址 diff --git a/internal/lua/api_timer.go b/internal/lua/api_timer.go index b48092e..85cdfdf 100644 --- a/internal/lua/api_timer.go +++ b/internal/lua/api_timer.go @@ -67,7 +67,7 @@ type TimerManager struct { schedulerL *glua.LState // nextID 下一个定时器 ID(原子操作) - nextID uint64 + nextID atomic.Uint64 // mu 定时器映射读写锁 mu sync.Mutex @@ -76,10 +76,10 @@ type TimerManager struct { queueMu sync.Mutex // active 活跃定时器计数(原子操作) - active int32 + active atomic.Int32 // stopping 停止标记(原子操作) - stopping int32 + stopping atomic.Int32 // queueClosed 队列是否已关闭 queueClosed bool @@ -181,14 +181,14 @@ func NewTimerManager(engine *LuaEngine) *TimerManager { // - 回调不能捕获 upvalue(闭包变量),因为它们会在不同 goroutine 中执行 // - 跨协程数据共享应使用 shared dict func (m *TimerManager) At(delay time.Duration, callback *glua.LFunction, args []glua.LValue) (*TimerHandle, error) { - if atomic.LoadInt32(&m.stopping) != 0 { + if m.stopping.Load() != 0 { return nil, nil // 服务器正在关闭,不接受新定时器 } m.mu.Lock() defer m.mu.Unlock() - id := atomic.AddUint64(&m.nextID, 1) + id := m.nextID.Add(1) // 编译回调为 FunctionProto var proto *glua.FunctionProto @@ -216,7 +216,7 @@ func (m *TimerManager) At(delay time.Duration, callback *glua.LFunction, args [] }) m.timers[id] = entry - atomic.AddInt32(&m.active, 1) + m.active.Add(1) return &TimerHandle{id: id, manager: m}, nil } @@ -227,7 +227,7 @@ func (m *TimerManager) At(delay time.Duration, callback *glua.LFunction, args [] // 检查取消信号,清理条目,并在队列满时丢弃回调。 func (m *TimerManager) executeTimer(entry *TimerEntry) { defer func() { - atomic.AddInt32(&m.active, -1) + m.active.Add(-1) close(entry.done) }() @@ -319,7 +319,7 @@ func (m *TimerManager) Cancel(handle *TimerHandle) bool { // 清理 delete(m.timers, entry.id) - atomic.AddInt32(&m.active, -1) + m.active.Add(-1) return true } @@ -336,11 +336,11 @@ func (m *TimerManager) Cancel(handle *TimerHandle) bool { // - bool: true 表示所有定时器已正常完成,false 表示超时 func (m *TimerManager) WaitAll(timeout time.Duration) bool { // 设置停止标志 - atomic.StoreInt32(&m.stopping, 1) + m.stopping.Store(1) // 等待所有定时器完成 start := time.Now() - for atomic.LoadInt32(&m.active) > 0 { + for m.active.Load() > 0 { if time.Since(start) > timeout { // 超时,强制取消所有 m.mu.Lock() @@ -369,12 +369,12 @@ func (m *TimerManager) WaitAll(timeout time.Duration) bool { // // 注意:该方法是幂等的,可安全调用多次。 func (m *TimerManager) Close() { - if m == nil || atomic.LoadInt32(&m.stopping) != 0 { + if m == nil || m.stopping.Load() != 0 { return // 已关闭或 nil } // 1. 停止接受新定时器 - atomic.StoreInt32(&m.stopping, 1) + m.stopping.Store(1) // 2. 优雅关闭:等待回调队列排空 m.gracefulShutdown(5 * time.Second) @@ -415,7 +415,7 @@ func (m *TimerManager) gracefulShutdown(timeout time.Duration) { // 返回值: // - int32: 活跃定时器数量 func (m *TimerManager) ActiveCount() int32 { - return atomic.LoadInt32(&m.active) + return m.active.Load() } // RegisterTimerAPI 注册 ngx.timer API 到 Lua 状态机。 diff --git a/internal/lua/boundary_test.go b/internal/lua/boundary_test.go index adb99ea..c078716 100644 --- a/internal/lua/boundary_test.go +++ b/internal/lua/boundary_test.go @@ -324,11 +324,11 @@ func TestBoundarySharedDictConcurrentAccess(t *testing.T) { concurrency := 10 iterations := 100 - for i := 0; i < concurrency; i++ { + for i := range concurrency { wg.Add(1) go func(id int) { defer wg.Done() - for j := 0; j < iterations; j++ { + for range iterations { key := "key-" + string(rune('0'+id%10)) _, _ = dict.Set(key, "value", 0) _, _, _ = dict.Get(key) diff --git a/internal/lua/cache.go b/internal/lua/cache.go index eefdaef..cc71920 100644 --- a/internal/lua/cache.go +++ b/internal/lua/cache.go @@ -87,10 +87,10 @@ type CodeCache struct { ttl time.Duration // 缓存命中次数 - hits uint64 + hits atomic.Uint64 // 缓存未命中次数 - misses uint64 + misses atomic.Uint64 // 读写锁 mu sync.RWMutex @@ -156,12 +156,12 @@ func (c *CodeCache) GetOrCompileInline(src string) (*glua.FunctionProto, error) c.mu.RUnlock() if ok && !c.isExpired(cached) { - atomic.AddUint64(&c.hits, 1) + c.hits.Add(1) cached.AccessAt.Store(time.Now()) return cached.Proto, nil } - atomic.AddUint64(&c.misses, 1) + c.misses.Add(1) // 编译脚本 chunk, err := parse.Parse(strings.NewReader(src), "") @@ -210,12 +210,12 @@ func (c *CodeCache) GetOrCompileFile(path string) (*glua.FunctionProto, error) { // 检查是否需要重新加载 if ok && !c.isExpired(cached) && !c.isFileChanged(cached) { - atomic.AddUint64(&c.hits, 1) + c.hits.Add(1) cached.AccessAt.Store(time.Now()) return cached.Proto, nil } - atomic.AddUint64(&c.misses, 1) + c.misses.Add(1) // 读取文件 content, err := os.ReadFile(path) @@ -345,13 +345,13 @@ func (c *CodeCache) isFileChanged(cached *CachedProto) bool { func (c *CodeCache) Stats() (hits, misses uint64, size int) { c.mu.RLock() defer c.mu.RUnlock() - return atomic.LoadUint64(&c.hits), atomic.LoadUint64(&c.misses), len(c.protos) + return c.hits.Load(), c.misses.Load(), len(c.protos) } // HitRate 返回缓存命中率 func (c *CodeCache) HitRate() float64 { - hits := atomic.LoadUint64(&c.hits) - misses := atomic.LoadUint64(&c.misses) + hits := c.hits.Load() + misses := c.misses.Load() total := hits + misses if total == 0 { return 0 diff --git a/internal/lua/engine.go b/internal/lua/engine.go index 21b42fa..714cf84 100644 --- a/internal/lua/engine.go +++ b/internal/lua/engine.go @@ -90,7 +90,7 @@ type LuaEngine struct { // 并发控制 maxCoroutines int - activeCount int32 + activeCount atomic.Int32 // 引擎统计 stats EngineStats @@ -181,7 +181,7 @@ func NewEngine(config *Config) (*LuaEngine, error) { cancel: cancel, sharedDictManager: NewSharedDictManager(), coroutinePool: sync.Pool{ - New: func() interface{} { + New: func() any { // 注意:这里只是创建空的协程对象结构 // 实际的协程通过 L.NewThread() 创建 return &LuaCoroutine{} @@ -262,9 +262,9 @@ func (e *LuaEngine) Close() { // - 使用完毕后必须调用 Close() 或 releaseCoroutine() 释放资源 func (e *LuaEngine) NewCoroutine(req *fasthttp.RequestCtx) (*LuaCoroutine, error) { // 步骤1: 检查并发限制 - current := atomic.AddInt32(&e.activeCount, 1) + current := e.activeCount.Add(1) if current > int32(e.maxCoroutines) { - atomic.AddInt32(&e.activeCount, -1) + e.activeCount.Add(-1) return nil, fmt.Errorf("max concurrent coroutines exceeded: %d/%d", current, e.maxCoroutines) } @@ -272,7 +272,7 @@ func (e *LuaEngine) NewCoroutine(req *fasthttp.RequestCtx) (*LuaCoroutine, error // 协程继承主 LState 的全局环境 co, cancel := e.L.NewThread() if co == nil { - atomic.AddInt32(&e.activeCount, -1) + e.activeCount.Add(-1) return nil, fmt.Errorf("failed to create coroutine") } @@ -330,7 +330,7 @@ func (e *LuaEngine) releaseCoroutine(coro *LuaCoroutine) { coro.executionCancel = nil // 步骤4: 更新计数 - atomic.AddInt32(&e.activeCount, -1) + e.activeCount.Add(-1) atomic.AddUint64(&e.stats.CoroutinesClosed, 1) // 步骤5: 放回池中(仅复用 LuaCoroutine 结构体内存) @@ -365,7 +365,7 @@ func (e *LuaEngine) Stats() EngineStats { // 返回值: // - int32: 当前正在执行的协程数 func (e *LuaEngine) ActiveCoroutines() int32 { - return atomic.LoadInt32(&e.activeCount) + return e.activeCount.Load() } // SharedDictManager 返回共享字典管理器实例。 diff --git a/internal/lua/filter_phase_test.go b/internal/lua/filter_phase_test.go index 9be7915..40b8e5e 100644 --- a/internal/lua/filter_phase_test.go +++ b/internal/lua/filter_phase_test.go @@ -244,14 +244,14 @@ func TestDelayedResponseWriter_Pool(t *testing.T) { ctx := mockRequestCtx() // 预热池 - for i := 0; i < 100; i++ { + for range 100 { ri := AcquireResponseInterceptor(ctx) ReleaseResponseInterceptor(ri) } // 测试从池获取的性能 start := time.Now() - for i := 0; i < 10000; i++ { + for range 10000 { ri := AcquireResponseInterceptor(ctx) ri.WriteString("test") ReleaseResponseInterceptor(ri) @@ -270,7 +270,7 @@ func TestConcurrentAccess(t *testing.T) { var wg sync.WaitGroup errors := make(chan error, 100) - for i := 0; i < 100; i++ { + for i := range 100 { wg.Add(1) go func(idx int) { defer wg.Done() @@ -464,7 +464,7 @@ func TestBodyFilterPhase(t *testing.T) { name: "large body", inputBody: strings.Repeat("x", 10000), filterFunc: func(b []byte) []byte { - return append([]byte("size="), []byte(fmt.Sprintf("%d ", len(b)))...) + return append([]byte("size="), fmt.Appendf(nil, "%d ", len(b))...) }, expectedOutput: "size=10000 ", }, @@ -501,7 +501,7 @@ func TestFilterPhaseSuccessRate(t *testing.T) { successCount := 0 var mu sync.Mutex - for i := 0; i < totalRequests; i++ { + for i := range totalRequests { ctx := mockRequestCtx() drw := NewDelayedResponseWriter(ctx) drw.EnableFilterPhase() @@ -537,14 +537,14 @@ func TestPerformanceOverhead(t *testing.T) { // 基准:正常写入 ctx1 := mockRequestCtx() start := time.Now() - for i := 0; i < 10000; i++ { + for range 10000 { ctx1.Response.SetBodyString("Hello, World!") } baselineDuration := time.Since(start) // 测试:延迟写入 start = time.Now() - for i := 0; i < 10000; i++ { + for range 10000 { ctx := mockRequestCtx() drw := NewDelayedResponseWriter(ctx) drw.EnableFilterPhase() @@ -896,7 +896,7 @@ func TestFilterPhaseFeasibility(t *testing.T) { const iterations = 100 success := 0 - for i := 0; i < iterations; i++ { + for range iterations { ctx := mockRequestCtx() drw := NewDelayedResponseWriter(ctx) drw.EnableFilterPhase() @@ -963,7 +963,7 @@ func TestFilterPhaseFeasibility(t *testing.T) { // 基准 start := time.Now() - for i := 0; i < iterations; i++ { + for range iterations { ctx := mockRequestCtx() ctx.Response.SetBodyString("test") } @@ -971,7 +971,7 @@ func TestFilterPhaseFeasibility(t *testing.T) { // 延迟写入 start = time.Now() - for i := 0; i < iterations; i++ { + for range iterations { ctx := mockRequestCtx() drw := NewDelayedResponseWriter(ctx) drw.EnableFilterPhase() @@ -1019,7 +1019,7 @@ func TestFilterPhaseMetrics(t *testing.T) { const iterations = 100 start := time.Now() - for i := 0; i < iterations; i++ { + for i := range iterations { ctx := mockRequestCtx() drw := NewDelayedResponseWriter(ctx) drw.EnableFilterPhase() @@ -1177,13 +1177,11 @@ func BenchmarkFilterPhaseScalability(b *testing.B) { b.Run(fmt.Sprintf("goroutines-%d", goroutines), func(b *testing.B) { var wg sync.WaitGroup errors := make(chan error, b.N) - var completed int32 + var completed atomic.Int32 b.ResetTimer() - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range goroutines { + wg.Go(func() { for j := 0; j < b.N/goroutines; j++ { ctx := mockRequestCtx() drw := NewDelayedResponseWriter(ctx) @@ -1193,10 +1191,10 @@ func BenchmarkFilterPhaseScalability(b *testing.B) { if err := drw.Flush(); err != nil { errors <- err } else { - atomic.AddInt32(&completed, 1) + completed.Add(1) } } - }() + }) } wg.Wait() close(errors) @@ -1373,7 +1371,7 @@ func TestFinalVerification(t *testing.T) { const total = 1000 success := 0 - for i := 0; i < total; i++ { + for range total { ctx := mockRequestCtx() drw := NewDelayedResponseWriter(ctx) drw.EnableFilterPhase() @@ -1439,7 +1437,7 @@ func TestFinalVerification(t *testing.T) { // 基准 start := time.Now() - for i := 0; i < iterations; i++ { + for range iterations { ctx := mockRequestCtx() ctx.Response.SetBodyString("test") ctx.Response.Header.Set("X-Test", "value") @@ -1448,7 +1446,7 @@ func TestFinalVerification(t *testing.T) { // Filter phase start = time.Now() - for i := 0; i < iterations; i++ { + for range iterations { ctx := mockRequestCtx() drw := NewDelayedResponseWriter(ctx) drw.EnableFilterPhase() diff --git a/internal/lua/filter_writer.go b/internal/lua/filter_writer.go index ed5c9da..640a4b2 100644 --- a/internal/lua/filter_writer.go +++ b/internal/lua/filter_writer.go @@ -432,7 +432,7 @@ func (drw *DelayedResponseWriter) DelHeader(key string) { // ResponseInterceptorPool 响应拦截器对象池。 var ResponseInterceptorPool = sync.Pool{ - New: func() interface{} { + New: func() any { return &ResponseInterceptor{} }, } @@ -666,7 +666,7 @@ func (drw *DelayedResponseWriter) Redirect(uri string, statusCode int) { // bufferPool body 缓冲区对象池。 var bufferPool = sync.Pool{ - New: func() interface{} { + New: func() any { buf := make([]byte, 0, 4096) // 4KB 初始容量 return &buf }, @@ -747,10 +747,7 @@ func (bw *BufferedWriter) Write(p []byte) (int, error) { // 检查是否需要扩容 if len(bw.buf)+len(p) > cap(bw.buf) { // 扩容 - newCap := cap(bw.buf) * 2 - if newCap < len(bw.buf)+len(p) { - newCap = len(bw.buf) + len(p) - } + newCap := max(cap(bw.buf)*2, len(bw.buf)+len(p)) newBuf := make([]byte, len(bw.buf), newCap) copy(newBuf, bw.buf) releaseBuffer(bw.buf) diff --git a/internal/lua/lua_bench_test.go b/internal/lua/lua_bench_test.go index 54dee7e..bc193a3 100644 --- a/internal/lua/lua_bench_test.go +++ b/internal/lua/lua_bench_test.go @@ -186,7 +186,7 @@ func BenchmarkTimerGracefulShutdown(b *testing.B) { }) // 创建一些定时器 - for j := 0; j < 10; j++ { + for range 10 { manager.At(1*time.Millisecond, callback, nil) } diff --git a/internal/lua/lua_test.go b/internal/lua/lua_test.go index 0b22d61..f645380 100644 --- a/internal/lua/lua_test.go +++ b/internal/lua/lua_test.go @@ -136,7 +136,7 @@ func TestLuaContextPoolMultipleReuse(t *testing.T) { defer engine.Close() // 循环多次 release/acquire,验证状态始终正确 - for i := 0; i < 100; i++ { + for range 100 { ctx := NewContext(engine, nil) ctx.SetVariable("iter", "val") ctx.Write([]byte("data")) diff --git a/internal/lua/middleware_bench_test.go b/internal/lua/middleware_bench_test.go index af6eac6..7238e70 100644 --- a/internal/lua/middleware_bench_test.go +++ b/internal/lua/middleware_bench_test.go @@ -174,7 +174,7 @@ func TestLuaMiddlewarePerformanceOverhead(t *testing.T) { // 测量 100 次执行的总时间 iterations := 100 start := time.Now() - for i := 0; i < iterations; i++ { + for range iterations { ctx := &fasthttp.RequestCtx{} handler(ctx) } diff --git a/internal/lua/scheduler_test.go b/internal/lua/scheduler_test.go index 68bac3f..68ceb4f 100644 --- a/internal/lua/scheduler_test.go +++ b/internal/lua/scheduler_test.go @@ -460,7 +460,7 @@ func TestSchedulerConcurrentAccess(t *testing.T) { // 创建多个 LState 并发访问 done := make(chan bool, 10) - for i := 0; i < 10; i++ { + for range 10 { go func() { L := glua.NewState() defer L.Close() @@ -477,7 +477,7 @@ func TestSchedulerConcurrentAccess(t *testing.T) { } // 等待所有 goroutine 完成 - for i := 0; i < 10; i++ { + for range 10 { <-done } } diff --git a/internal/lua/socket_manager.go b/internal/lua/socket_manager.go index 115c6d7..371150b 100644 --- a/internal/lua/socket_manager.go +++ b/internal/lua/socket_manager.go @@ -116,7 +116,7 @@ type SocketOperation struct { LastActivity time.Time // Result 操作结果 - Result interface{} + Result any // Error 操作错误 Error error @@ -125,7 +125,7 @@ type SocketOperation struct { Done chan struct{} // completed 原子标记,1=已完成,0=未完成 - completed int32 + completed atomic.Int32 } // IsCompleted 检查操作是否已完成。 @@ -133,7 +133,7 @@ type SocketOperation struct { // 返回值: // - bool: true 表示已完成 func (op *SocketOperation) IsCompleted() bool { - return atomic.LoadInt32(&op.completed) == 1 + return op.completed.Load() == 1 } // Complete 标记操作完成。 @@ -143,8 +143,8 @@ func (op *SocketOperation) IsCompleted() bool { // 参数: // - result: 操作结果 // - err: 操作错误(nil 表示成功) -func (op *SocketOperation) Complete(result interface{}, err error) { - if atomic.CompareAndSwapInt32(&op.completed, 0, 1) { +func (op *SocketOperation) Complete(result any, err error) { + if op.completed.CompareAndSwap(0, 1) { op.Result = result op.Error = err close(op.Done) @@ -161,7 +161,7 @@ func (op *SocketOperation) Complete(result interface{}, err error) { // 返回值: // - interface{}: 操作结果 // - error: 操作错误或上下文取消错误 -func (op *SocketOperation) Wait(ctx context.Context) (interface{}, error) { +func (op *SocketOperation) Wait(ctx context.Context) (any, error) { select { case <-op.Done: return op.Result, op.Error @@ -319,7 +319,7 @@ func (cm *CosocketManager) StartOperation(socket *TCPSocket, opType OperationTyp // - id: 操作 ID // - result: 操作结果 // - err: 操作错误 -func (cm *CosocketManager) CompleteOperation(id uint64, result interface{}, err error) { +func (cm *CosocketManager) CompleteOperation(id uint64, result any, err error) { cm.mu.Lock() op, exists := cm.operations[id] if exists { diff --git a/internal/matcher/conflict.go b/internal/matcher/conflict.go index fe28b06..3b7aefd 100644 --- a/internal/matcher/conflict.go +++ b/internal/matcher/conflict.go @@ -5,6 +5,8 @@ // 作者:xfy package matcher +import "maps" + import "fmt" // ConflictDetector 路径冲突检测器。 @@ -61,9 +63,7 @@ func (cd *ConflictDetector) Exists(path string) bool { // - map[string]string: 路径到 location 类型的映射 func (cd *ConflictDetector) GetRegisteredPaths() map[string]string { result := make(map[string]string, len(cd.registeredPaths)) - for k, v := range cd.registeredPaths { - result[k] = v - } + maps.Copy(result, cd.registeredPaths) return result } diff --git a/internal/middleware/bodylimit/bodylimit_bench_test.go b/internal/middleware/bodylimit/bodylimit_bench_test.go index 0e247fb..dd1d500 100644 --- a/internal/middleware/bodylimit/bodylimit_bench_test.go +++ b/internal/middleware/bodylimit/bodylimit_bench_test.go @@ -91,7 +91,7 @@ func BenchmarkBodyLimitPathMatching(b *testing.B) { } // 添加大量路径配置 - for i := 0; i < 100; i++ { + for i := range 100 { path := "/api/v" + string(rune('0'+i%10)) + "/resource" + string(rune('0'+i%10)) size := "1mb" if i%3 == 0 { diff --git a/internal/middleware/bodylimit/bodylimit_test.go b/internal/middleware/bodylimit/bodylimit_test.go index b6b1c11..5d1114d 100644 --- a/internal/middleware/bodylimit/bodylimit_test.go +++ b/internal/middleware/bodylimit/bodylimit_test.go @@ -260,13 +260,7 @@ func (r *slowReader) Read(p []byte) (n int, err error) { // 每次只读取 chunkSize 字节 remaining := len(r.data) - r.pos - toRead := r.chunkSize - if toRead > remaining { - toRead = remaining - } - if toRead > len(p) { - toRead = len(p) - } + toRead := min(min(r.chunkSize, remaining), len(p)) n = toRead copy(p, r.data[r.pos:r.pos+toRead]) diff --git a/internal/middleware/compression/compression_test.go b/internal/middleware/compression/compression_test.go index 36de580..33bb397 100644 --- a/internal/middleware/compression/compression_test.go +++ b/internal/middleware/compression/compression_test.go @@ -13,6 +13,7 @@ package compression import ( "bytes" "io" + "slices" "testing" "github.com/andybalholm/brotli" @@ -82,13 +83,7 @@ func TestDefaultCompressibleTypes(t *testing.T) { // 检查关键类型 expected := []string{"text/html", "text/css", "application/json"} for _, e := range expected { - found := false - for _, t := range types { - if t == e { - found = true - break - } - } + found := slices.Contains(types, e) if !found { t.Errorf("Expected type %s in default list", e) } diff --git a/internal/middleware/limitrate/limitrate_test.go b/internal/middleware/limitrate/limitrate_test.go index 687b699..7e9b4cc 100644 --- a/internal/middleware/limitrate/limitrate_test.go +++ b/internal/middleware/limitrate/limitrate_test.go @@ -429,14 +429,12 @@ func TestRateLimitedWriter_Concurrent(t *testing.T) { writesPerGoroutine := 10 data := []byte("test") - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < writesPerGoroutine; j++ { + for range goroutines { + wg.Go(func() { + for range writesPerGoroutine { _, _ = w.Write(data) } - }() + }) } wg.Wait() diff --git a/internal/middleware/limitrate/writer.go b/internal/middleware/limitrate/writer.go index 01d13ae..a148c53 100644 --- a/internal/middleware/limitrate/writer.go +++ b/internal/middleware/limitrate/writer.go @@ -65,10 +65,7 @@ func (w *RateLimitedWriter) Write(p []byte) (int, error) { w.bucket = w.rate // 简化:每秒补充 rate 个令牌 } - chunk := int64(n - written) - if chunk > w.bucket { - chunk = w.bucket - } + chunk := min(int64(n-written), w.bucket) nw, err := w.writer.Write(p[written : written+int(chunk)]) written += nw diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go index 09ec659..f3eb4e3 100644 --- a/internal/middleware/middleware.go +++ b/internal/middleware/middleware.go @@ -15,6 +15,8 @@ // 作者:xfy package middleware +import "slices" + import "github.com/valyala/fasthttp" // Middleware 中间件接口,定义中间件的标准方法。 @@ -72,8 +74,8 @@ func NewChain(middlewares ...Middleware) *Chain { // A -> B -> C -> H -> C -> B -> A func (c *Chain) Apply(final fasthttp.RequestHandler) fasthttp.RequestHandler { handler := final - for i := len(c.middlewares) - 1; i >= 0; i-- { - handler = c.middlewares[i].Process(handler) + for _, v := range slices.Backward(c.middlewares) { + handler = v.Process(handler) } return handler } diff --git a/internal/middleware/security/access.go b/internal/middleware/security/access.go index f0d6460..abd3dba 100644 --- a/internal/middleware/security/access.go +++ b/internal/middleware/security/access.go @@ -27,6 +27,7 @@ import ( "errors" "fmt" "net" + "slices" "strings" "sync" "time" @@ -218,10 +219,8 @@ func (ac *AccessControl) Check(ip net.IP) bool { return false } - for _, c := range ac.geoipConfig.DenyCountries { - if country == c { - return false - } + if slices.Contains(ac.geoipConfig.DenyCountries, country) { + return false } } } @@ -238,10 +237,8 @@ checkAllow: if ac.geoip != nil && ac.geoipConfig.Enabled { country, err := ac.geoip.LookupCountry(ip) if err == nil && country != geoPrivateDeny { - for _, c := range ac.geoipConfig.AllowCountries { - if country == c { - return true - } + if slices.Contains(ac.geoipConfig.AllowCountries, country) { + return true } } } @@ -415,8 +412,8 @@ func (ac *AccessControl) getClientIP(ctx *fasthttp.RequestCtx) net.IP { // 使用右侧(最接近客户端)的非可信 IP if xff := ctx.Request.Header.Peek("X-Forwarded-For"); len(xff) > 0 { ips := strings.Split(string(xff), ",") - for i := len(ips) - 1; i >= 0; i-- { - ipStr := strings.TrimSpace(ips[i]) + for _, v := range slices.Backward(ips) { + ipStr := strings.TrimSpace(v) if ip := net.ParseIP(ipStr); ip != nil { // 检查该 IP 是否在可信代理列表中 trusted := false diff --git a/internal/middleware/security/auth.go b/internal/middleware/security/auth.go index 7e759c9..fbf2b61 100644 --- a/internal/middleware/security/auth.go +++ b/internal/middleware/security/auth.go @@ -296,8 +296,8 @@ func parseArgon2idHash(hash string) (argon2Params, []byte, []byte, error) { paramsStr := parts[3] params := defaultArgon2Params - paramParts := strings.Split(paramsStr, ",") - for _, p := range paramParts { + paramParts := strings.SplitSeq(paramsStr, ",") + for p := range paramParts { kv := strings.Split(p, "=") if len(kv) != 2 { continue @@ -362,13 +362,13 @@ func (ba *BasicAuth) extractCredentials(ctx *fasthttp.RequestCtx) (string, strin // 分割用户名:密码 credentials := string(decoded) - idx := strings.Index(credentials, ":") - if idx == -1 { + before, after, ok := strings.Cut(credentials, ":") + if !ok { return "", "", false } - username := credentials[:idx] - password := credentials[idx+1:] + username := before + password := after return username, password, true } diff --git a/internal/middleware/security/auth_request.go b/internal/middleware/security/auth_request.go index ebc8e47..89ef09e 100644 --- a/internal/middleware/security/auth_request.go +++ b/internal/middleware/security/auth_request.go @@ -169,8 +169,8 @@ func parseAuthURL(url string) (string, bool, error) { if strings.HasPrefix(url, "https://") { isTLS = true url = strings.TrimPrefix(url, "https://") - } else if strings.HasPrefix(url, "http://") { - url = strings.TrimPrefix(url, "http://") + } else if after, ok := strings.CutPrefix(url, "http://"); ok { + url = after } // 提取主机部分 diff --git a/internal/middleware/security/geoip_test.go b/internal/middleware/security/geoip_test.go index 433ec2b..7752d37 100644 --- a/internal/middleware/security/geoip_test.go +++ b/internal/middleware/security/geoip_test.go @@ -329,7 +329,7 @@ func TestGeoIPLookup_ConcurrentAccess(t *testing.T) { geoip := setupTestGeoIP(t, "allow") done := make(chan bool, 10) - for i := 0; i < 10; i++ { + for range 10 { go func() { _, err := geoip.LookupCountry(net.ParseIP("2.125.160.216")) assert.NoError(t, err) @@ -337,7 +337,7 @@ func TestGeoIPLookup_ConcurrentAccess(t *testing.T) { }() } - for i := 0; i < 10; i++ { + for range 10 { <-done } } diff --git a/internal/middleware/security/ratelimit.go b/internal/middleware/security/ratelimit.go index 6d154b6..19a13da 100644 --- a/internal/middleware/security/ratelimit.go +++ b/internal/middleware/security/ratelimit.go @@ -142,7 +142,7 @@ func newTokenBucketLimiter(cfg *config.RateLimitConfig) (*RateLimiter, error) { } // 初始化 16 个分段锁桶 - for i := 0; i < 16; i++ { + for i := range 16 { rl.shards[i] = shardedBucket{ buckets: make(map[string]*tokenBucket), } @@ -437,7 +437,7 @@ func (rl *RateLimiter) Reset(key string) { // // 清空所有桶记录,所有客户端将重新开始计数。 func (rl *RateLimiter) ResetAll() { - for i := 0; i < 16; i++ { + for i := range 16 { rl.shards[i].mu.Lock() rl.shards[i].buckets = make(map[string]*tokenBucket) rl.shards[i].mu.Unlock() @@ -453,7 +453,7 @@ func (rl *RateLimiter) ResetAll() { // - maxAge: 未使用桶的最大保留时间 func (rl *RateLimiter) Cleanup(maxAge time.Duration) { now := time.Now() - for i := 0; i < 16; i++ { + for i := range 16 { shard := &rl.shards[i] shard.mu.Lock() for key, bucket := range shard.buckets { @@ -526,7 +526,7 @@ type RateLimitStats struct { // - RateLimitStats: 包含桶数量、速率和容量的统计对象 func (rl *RateLimiter) GetStats() RateLimitStats { totalBuckets := 0 - for i := 0; i < 16; i++ { + for i := range 16 { rl.shards[i].mu.RLock() totalBuckets += len(rl.shards[i].buckets) rl.shards[i].mu.RUnlock() @@ -551,7 +551,7 @@ type ConnLimiter struct { keyFunc KeyFunc counts map[string]int64 max int - current int64 + current atomic.Int64 mu sync.RWMutex perKey bool } @@ -601,9 +601,9 @@ func NewConnLimiter(maxConns int, perKey bool, keyType string) (*ConnLimiter, er func (cl *ConnLimiter) Acquire(ctx *fasthttp.RequestCtx) bool { if !cl.perKey { // 全局限制(原子递增后检查溢出,避免 TOCTOU 竞态) - current := atomic.AddInt64(&cl.current, 1) + current := cl.current.Add(1) if current > int64(cl.max) { - atomic.AddInt64(&cl.current, -1) + cl.current.Add(-1) return false } return true @@ -632,7 +632,7 @@ func (cl *ConnLimiter) Acquire(ctx *fasthttp.RequestCtx) bool { // - ctx: FastHTTP 请求上下文 func (cl *ConnLimiter) Release(ctx *fasthttp.RequestCtx) { if !cl.perKey { - atomic.AddInt64(&cl.current, -1) + cl.current.Add(-1) return } diff --git a/internal/middleware/security/ratelimit_bench_test.go b/internal/middleware/security/ratelimit_bench_test.go index db8068c..307d151 100644 --- a/internal/middleware/security/ratelimit_bench_test.go +++ b/internal/middleware/security/ratelimit_bench_test.go @@ -128,7 +128,7 @@ func BenchmarkRateLimiterCleanup_1000Buckets(b *testing.B) { defer rl.StopCleanup() // 预创建 1000 个桶 - for i := 0; i < 1000; i++ { + for i := range 1000 { rl.Allow("192.168.0." + string(rune(i))) } @@ -136,7 +136,7 @@ func BenchmarkRateLimiterCleanup_1000Buckets(b *testing.B) { for b.Loop() { rl.Cleanup(0) // 清理所有桶 // 重新创建桶以保持测试一致性 - for j := 0; j < 1000; j++ { + for j := range 1000 { rl.Allow("192.168.0." + string(rune(j))) } } @@ -217,7 +217,7 @@ func BenchmarkRateLimiterStats(b *testing.B) { defer rl.StopCleanup() // 预创建一些桶 - for i := 0; i < 100; i++ { + for i := range 100 { rl.Allow("192.168.0." + string(rune(i))) } diff --git a/internal/middleware/security/ratelimit_test.go b/internal/middleware/security/ratelimit_test.go index 5156924..6678bc2 100644 --- a/internal/middleware/security/ratelimit_test.go +++ b/internal/middleware/security/ratelimit_test.go @@ -112,7 +112,7 @@ func TestRateLimiterAllow(t *testing.T) { key := "test-key" // Should allow burst requests - for i := 0; i < 10; i++ { + for i := range 10 { if !rl.Allow(key) { t.Errorf("Expected request %d to be allowed", i+1) } @@ -141,7 +141,7 @@ func TestRateLimiterTokenRefill(t *testing.T) { key := "refill-test" // Exhaust the burst - for i := 0; i < 100; i++ { + for range 100 { rl.Allow(key) } @@ -607,7 +607,7 @@ func TestRateLimiter_GetRetryAfter(t *testing.T) { // 创建一个桶并消耗令牌 key := "test-key" - for i := 0; i < 10; i++ { + for range 10 { rl.Allow(key) } diff --git a/internal/middleware/security/sliding_window.go b/internal/middleware/security/sliding_window.go index f5aafb3..bfc014f 100644 --- a/internal/middleware/security/sliding_window.go +++ b/internal/middleware/security/sliding_window.go @@ -94,7 +94,7 @@ func NewSlidingWindowLimiter(window time.Duration, limit int, precise bool) *Sli precise: precise, } // 初始化16个分段锁桶 - for i := 0; i < 16; i++ { + for i := range 16 { s.buckets[i] = &limiterBucket{ counters: make(map[string]*windowCounter), } @@ -225,7 +225,7 @@ func (s *SlidingWindowLimiter) Reset(key string) { // ResetAll 重置所有计数器。 func (s *SlidingWindowLimiter) ResetAll() { - for i := 0; i < 16; i++ { + for i := range 16 { bucket := s.buckets[i] bucket.mu.Lock() bucket.counters = make(map[string]*windowCounter) @@ -239,7 +239,7 @@ func (s *SlidingWindowLimiter) ResetAll() { // - maxAge: 未使用计数器的最大保留时间 func (s *SlidingWindowLimiter) Cleanup(maxAge time.Duration) { now := time.Now() - for i := 0; i < 16; i++ { + for i := range 16 { bucket := s.buckets[i] bucket.mu.Lock() for key, counter := range bucket.counters { @@ -267,7 +267,7 @@ type SlidingWindowStats struct { // GetStats 返回统计信息。 func (s *SlidingWindowLimiter) GetStats() SlidingWindowStats { totalKeys := 0 - for i := 0; i < 16; i++ { + for i := range 16 { bucket := s.buckets[i] bucket.mu.RLock() totalKeys += len(bucket.counters) diff --git a/internal/middleware/security/sliding_window_bench_test.go b/internal/middleware/security/sliding_window_bench_test.go index 1e479a5..5c0b56d 100644 --- a/internal/middleware/security/sliding_window_bench_test.go +++ b/internal/middleware/security/sliding_window_bench_test.go @@ -73,7 +73,7 @@ func BenchmarkSlidingWindowCleanup(b *testing.B) { sw := NewSlidingWindowLimiter(time.Second, 1000, false) // 预创建 100 个键 - for i := 0; i < 100; i++ { + for i := range 100 { sw.Allow("192.168.0." + string(rune(i))) } @@ -89,7 +89,7 @@ func BenchmarkSlidingWindowGetCount(b *testing.B) { key := "192.168.1.100" // 预先添加一些请求 - for i := 0; i < 100; i++ { + for range 100 { sw.Allow(key) } @@ -131,7 +131,7 @@ func BenchmarkSlidingWindowStats(b *testing.B) { sw := NewSlidingWindowLimiter(time.Second, 10000, false) // 预创建一些键 - for i := 0; i < 50; i++ { + for i := range 50 { sw.Allow("192.168.0." + string(rune(i))) } diff --git a/internal/middleware/security/sliding_window_test.go b/internal/middleware/security/sliding_window_test.go index ebb155a..3dc5ea7 100644 --- a/internal/middleware/security/sliding_window_test.go +++ b/internal/middleware/security/sliding_window_test.go @@ -42,7 +42,7 @@ func TestSlidingWindowLimiter_Allow(t *testing.T) { t.Run("近似模式-允许请求", func(t *testing.T) { limiter := NewSlidingWindowLimiter(time.Second, 10, false) - for i := 0; i < 10; i++ { + for i := range 10 { if !limiter.Allow("test-key") { t.Errorf("请求 %d 应该被允许", i+1) } @@ -53,7 +53,7 @@ func TestSlidingWindowLimiter_Allow(t *testing.T) { limiter := NewSlidingWindowLimiter(time.Second, 5, false) // 发送 5 个请求 - for i := 0; i < 5; i++ { + for range 5 { limiter.Allow("test-key") } @@ -67,7 +67,7 @@ func TestSlidingWindowLimiter_Allow(t *testing.T) { t.Run("精确模式-允许请求", func(t *testing.T) { limiter := NewSlidingWindowLimiter(time.Second, 10, true) - for i := 0; i < 10; i++ { + for i := range 10 { if !limiter.Allow("test-key") { t.Errorf("请求 %d 应该被允许", i+1) } @@ -78,7 +78,7 @@ func TestSlidingWindowLimiter_Allow(t *testing.T) { limiter := NewSlidingWindowLimiter(time.Second, 3, true) // 发送 3 个请求 - for i := 0; i < 3; i++ { + for i := range 3 { if !limiter.Allow("test-key") { t.Errorf("请求 %d 应该被允许", i+1) } @@ -108,7 +108,7 @@ func TestSlidingWindowLimiter_Reset(t *testing.T) { limiter := NewSlidingWindowLimiter(time.Second, 5, true) // 发送一些请求 - for i := 0; i < 5; i++ { + for range 5 { limiter.Allow("test-key") } @@ -173,7 +173,7 @@ func TestSlidingWindowLimiter_GetCount(t *testing.T) { limiter := NewSlidingWindowLimiter(time.Second, 10, true) // 发送 3 个请求 - for i := 0; i < 3; i++ { + for range 3 { limiter.Allow("test-key") } diff --git a/internal/mimeutil/detect_test.go b/internal/mimeutil/detect_test.go index 4dd4c70..f84203f 100644 --- a/internal/mimeutil/detect_test.go +++ b/internal/mimeutil/detect_test.go @@ -165,7 +165,7 @@ func TestConcurrentAccess(t *testing.T) { // 并发调用 DetectContentType wg.Add(numGoroutines) - for i := 0; i < numGoroutines; i++ { + for range numGoroutines { go func() { defer wg.Done() DetectContentType("test.html") @@ -174,7 +174,7 @@ func TestConcurrentAccess(t *testing.T) { // 并发调用 AddTypes wg.Add(numGoroutines) - for i := 0; i < numGoroutines; i++ { + for i := range numGoroutines { go func(i int) { defer wg.Done() AddTypes(map[string]string{".test": "application/x-test"}) @@ -183,7 +183,7 @@ func TestConcurrentAccess(t *testing.T) { // 并发调用 SetDefaultType 和 GetDefaultType wg.Add(numGoroutines) - for i := 0; i < numGoroutines; i++ { + for range numGoroutines { go func() { defer wg.Done() SetDefaultType("text/plain") diff --git a/internal/proxy/connection_pool_bench_test.go b/internal/proxy/connection_pool_bench_test.go index d2e1245..9c2ca48 100644 --- a/internal/proxy/connection_pool_bench_test.go +++ b/internal/proxy/connection_pool_bench_test.go @@ -71,7 +71,7 @@ func BenchmarkConnectionPool_Normal(b *testing.B) { } // 预热连接池 - for i := 0; i < 10; i++ { + for range 10 { ctx := &fasthttp.RequestCtx{} ctx.Request.SetRequestURI("/api/test") ctx.Request.Header.SetMethod(fasthttp.MethodGet) @@ -156,7 +156,7 @@ func BenchmarkConnectionPool_SmallBody(b *testing.B) { } // 预热 - for i := 0; i < 5; i++ { + for range 5 { ctx := &fasthttp.RequestCtx{} ctx.Request.SetRequestURI("/api/test") p.ServeHTTP(ctx) @@ -221,7 +221,7 @@ func BenchmarkConnectionPool_MultiTarget(b *testing.B) { targets := make([]*loadbalance.Target, 3) cleanups := make([]func(), 3) - for i := 0; i < 3; i++ { + for i := range 3 { addr, cleanup := setupInmemoryBackend([]byte("backend" + strconv.Itoa(i))) cleanups[i] = cleanup targets[i] = &loadbalance.Target{ @@ -295,4 +295,4 @@ func BenchmarkHostClient_AcquireRelease(b *testing.B) { fasthttp.ReleaseRequest(req) fasthttp.ReleaseResponse(resp) } -} \ No newline at end of file +} diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go index ad1d951..7ca2568 100644 --- a/internal/proxy/proxy.go +++ b/internal/proxy/proxy.go @@ -74,7 +74,7 @@ const ( // 注意:从 pool 获取的 map 使用后不能 Put 回 pool, // 因为 cache.Set 存储了 map 引用。 var headersPool = sync.Pool{ - New: func() interface{} { + New: func() any { return make(map[string]string, 20) }, } diff --git a/internal/proxy/proxy_bench_test.go b/internal/proxy/proxy_bench_test.go index 746773d..310b44a 100644 --- a/internal/proxy/proxy_bench_test.go +++ b/internal/proxy/proxy_bench_test.go @@ -187,7 +187,7 @@ func BenchmarkProxyForwardMultipleTargets(b *testing.B) { targets := make([]*loadbalance.Target, numTargets) cleanups := make([]func(), numTargets) - for i := 0; i < numTargets; i++ { + for i := range numTargets { addr, cleanup := setupMockBackend(smallBody) cleanups[i] = cleanup targets[i] = &loadbalance.Target{ diff --git a/internal/proxy/proxy_dns.go b/internal/proxy/proxy_dns.go index a7354e4..63a027d 100644 --- a/internal/proxy/proxy_dns.go +++ b/internal/proxy/proxy_dns.go @@ -110,10 +110,7 @@ func (p *Proxy) startDNSRefreshLoop() { } // 刷新间隔为 TTL / 2 - interval := ttl / 2 - if interval < time.Second { - interval = time.Second - } + interval := max(ttl/2, time.Second) ticker := time.NewTicker(interval) defer ticker.Stop() diff --git a/internal/proxy/websocket.go b/internal/proxy/websocket.go index 4404224..edb7a87 100644 --- a/internal/proxy/websocket.go +++ b/internal/proxy/websocket.go @@ -39,7 +39,7 @@ import ( // wsBufPool WebSocket 数据转发 buffer pool。 // 复用 32KB buffer 避免每次 copyData 调用分配。 var wsBufPool = sync.Pool{ - New: func() interface{} { + New: func() any { buf := make([]byte, 32*1024) return &buf }, diff --git a/internal/proxy/websocket_test.go b/internal/proxy/websocket_test.go index 6a86ad0..cd7932c 100644 --- a/internal/proxy/websocket_test.go +++ b/internal/proxy/websocket_test.go @@ -682,7 +682,7 @@ func TestWebSocketBridge_Concurrent(t *testing.T) { var wg sync.WaitGroup errCh := make(chan error, numBridges) - for i := 0; i < numBridges; i++ { + for i := range numBridges { wg.Add(1) go func(id int) { defer wg.Done() diff --git a/internal/resolver/mock_dns_test.go b/internal/resolver/mock_dns_test.go index cbd96b0..e7635fe 100644 --- a/internal/resolver/mock_dns_test.go +++ b/internal/resolver/mock_dns_test.go @@ -395,14 +395,12 @@ func TestMockDNSConcurrentAccess(t *testing.T) { concurrency := 10 iterations := 100 - for i := 0; i < concurrency; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < iterations; j++ { + for range concurrency { + wg.Go(func() { + for range iterations { _, _ = resolver.LookupHostWithCache(context.Background(), "localhost") } - }() + }) } wg.Wait() @@ -492,16 +490,14 @@ func TestMockDNSCacheEntryConcurrency(t *testing.T) { var readCount atomic.Int64 // 并发读取 - for i := 0; i < 100; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 100 { + wg.Go(func() { entry.mu.RLock() _ = entry.IPs _ = entry.ExpiresAt entry.mu.RUnlock() readCount.Add(1) - }() + }) } wg.Wait() diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index 808f4d0..4918235 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -373,10 +373,7 @@ func (r *DNSResolver) Start() error { // refreshLoop 后台刷新循环。 func (r *DNSResolver) refreshLoop() { // 刷新间隔为 TTL / 2 - interval := r.config.TTL() / 2 - if interval < time.Second { - interval = time.Second - } + interval := max(r.config.TTL()/2, time.Second) ticker := time.NewTicker(interval) defer ticker.Stop() diff --git a/internal/resolver/resolver_bench_test.go b/internal/resolver/resolver_bench_test.go index 66be109..3856815 100644 --- a/internal/resolver/resolver_bench_test.go +++ b/internal/resolver/resolver_bench_test.go @@ -27,7 +27,7 @@ func createTestResolver() *DNSResolver { r := New(cfg).(*DNSResolver) // 预填充缓存条目,模拟真实的解析场景 - for i := 0; i < 100; i++ { + for i := range 100 { host := fmt.Sprintf("host%d.example.com", i) r.storeCache(host, &DNSCacheEntry{ IPs: []string{fmt.Sprintf("192.168.1.%d", i%256), fmt.Sprintf("192.168.2.%d", i%256)}, @@ -214,7 +214,7 @@ func BenchmarkDNSResolverMixedWorkload(b *testing.B) { ctx := context.Background() // 预填充一些缓存 - for i := 0; i < 50; i++ { + for i := range 50 { host := fmt.Sprintf("cached%d.example.com", i) r.storeCache(host, &DNSCacheEntry{ IPs: []string{fmt.Sprintf("192.168.1.%d", i%256)}, diff --git a/internal/resolver/resolver_test.go b/internal/resolver/resolver_test.go index bf374ca..c85ed0f 100644 --- a/internal/resolver/resolver_test.go +++ b/internal/resolver/resolver_test.go @@ -203,7 +203,7 @@ func TestCacheHitRate(t *testing.T) { r.mu.Unlock() // 3 次命中 - for i := 0; i < 3; i++ { + for range 3 { _, _ = r.LookupHostWithCache(context.Background(), "test.example.com") } @@ -356,7 +356,7 @@ func TestClearCache(t *testing.T) { r := New(cfg).(*DNSResolver) // 添加多个缓存 - for i := 0; i < 5; i++ { + for i := range 5 { host := fmt.Sprintf("test%d.example.com", i) r.storeCache(host, &DNSCacheEntry{ IPs: []string{fmt.Sprintf("192.168.1.%d", i)}, @@ -397,12 +397,10 @@ func TestConcurrentAccess(t *testing.T) { // 并发读取 var wg sync.WaitGroup - for i := 0; i < 100; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 100 { + wg.Go(func() { _, _ = r.LookupHostWithCache(context.Background(), "test.example.com") - }() + }) } wg.Wait() @@ -578,7 +576,7 @@ func TestCacheSizeLimit(t *testing.T) { r := New(cfg).(*DNSResolver) // 添加 5 个缓存条目,应淘汰 2 个 - for i := 0; i < 5; i++ { + for i := range 5 { host := fmt.Sprintf("host%d.example.com", i) r.storeCache(host, &DNSCacheEntry{ IPs: []string{fmt.Sprintf("192.168.1.%d", i)}, @@ -623,7 +621,7 @@ func TestCacheSizeZero(t *testing.T) { r := New(cfg).(*DNSResolver) // 添加大量缓存条目 - for i := 0; i < 100; i++ { + for i := range 100 { host := fmt.Sprintf("host%d.example.com", i) r.storeCache(host, &DNSCacheEntry{ IPs: []string{fmt.Sprintf("192.168.1.%d", i%256)}, diff --git a/internal/server/pool.go b/internal/server/pool.go index 68f7de5..42f9267 100644 --- a/internal/server/pool.go +++ b/internal/server/pool.go @@ -195,10 +195,8 @@ func (p *GoroutinePool) Submit(ctx *fasthttp.RequestCtx, task Task) error { // worker 从任务队列获取任务执行,空闲超时后自动退出(保持最小数量)。 func (p *GoroutinePool) startWorker() { atomic.AddInt32(&p.workers, 1) - p.wg.Add(1) - go func() { - defer p.wg.Done() + p.wg.Go(func() { defer atomic.AddInt32(&p.workers, -1) idleTimer := time.NewTimer(p.idleTimeout) @@ -233,7 +231,7 @@ func (p *GoroutinePool) startWorker() { return } } - }() + }) } // Stats 返回池的统计信息。 diff --git a/internal/server/pool_bench_test.go b/internal/server/pool_bench_test.go index 92c5788..a8c1e28 100644 --- a/internal/server/pool_bench_test.go +++ b/internal/server/pool_bench_test.go @@ -57,7 +57,7 @@ func BenchmarkGoroutinePoolParallel(b *testing.B) { task := func(_ *fasthttp.RequestCtx) { // 模拟微小工作负载 sum := 0 - for j := 0; j < 100; j++ { + for j := range 100 { sum += j } _ = sum @@ -91,7 +91,7 @@ func BenchmarkGoroutinePoolSubmit_BlockingPath(b *testing.B) { } // 提交任务使队列保持满状态 - for i := 0; i < 5; i++ { + for range 5 { go func() { for { _ = pool.Submit(ctx, slowTask) @@ -136,7 +136,7 @@ func BenchmarkGoroutinePoolQueueFull(b *testing.B) { task := func(_ *fasthttp.RequestCtx) { // 模拟微小工作负载 sum := 0 - for j := 0; j < 10; j++ { + for j := range 10 { sum += j } _ = sum @@ -167,7 +167,7 @@ func BenchmarkGoroutinePoolWorkerRecycle(b *testing.B) { time.Sleep(100 * time.Microsecond) } - for j := 0; j < 30; j++ { + for range 30 { go pool.Submit(ctx, task) } @@ -201,7 +201,7 @@ func BenchmarkGoroutinePoolSubmitWithWork(b *testing.B) { task := func(_ *fasthttp.RequestCtx) { // 模拟中等计算量 sum := 0 - for i := 0; i < 1000; i++ { + for i := range 1000 { sum += i } _ = sum diff --git a/internal/server/pool_test.go b/internal/server/pool_test.go index ae93307..39996a5 100644 --- a/internal/server/pool_test.go +++ b/internal/server/pool_test.go @@ -138,15 +138,13 @@ func TestPoolConcurrentSubmit(t *testing.T) { var counter atomic.Int32 var wg sync.WaitGroup - for i := 0; i < 100; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 100 { + wg.Go(func() { _ = p.Submit(nil, func(_ *fasthttp.RequestCtx) { counter.Add(1) }) - }() + }) } wg.Wait() @@ -395,7 +393,7 @@ func TestPoolSubmit_MultipleQueuedTasks(t *testing.T) { var counter atomic.Int32 // 快速提交多个任务 - for i := 0; i < 5; i++ { + for range 5 { _ = p.Submit(nil, func(*fasthttp.RequestCtx) { counter.Add(1) }) diff --git a/internal/server/pprof_impl_test.go b/internal/server/pprof_impl_test.go index b226270..9ace7b3 100644 --- a/internal/server/pprof_impl_test.go +++ b/internal/server/pprof_impl_test.go @@ -122,12 +122,10 @@ func TestWriteGoroutineProfile(t *testing.T) { // 启动一些 goroutine var wg sync.WaitGroup - for i := 0; i < 5; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 5 { + wg.Go(func() { select {} - }() + }) } writeGoroutineProfile(&buf) @@ -242,7 +240,7 @@ func TestCPUProfileMutex(t *testing.T) { var buf bytes.Buffer // 启动多个 goroutine 同时操作 - for i := 0; i < 10; i++ { + for range 10 { wg.Add(2) go func() { defer wg.Done() diff --git a/internal/server/server_test.go b/internal/server/server_test.go index 1090f02..4bc9776 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -109,7 +109,7 @@ func TestStopAfterStop(t *testing.T) { s := New(cfg) // 多次调用 StopWithTimeout 应该都是安全的 - for i := 0; i < 3; i++ { + for i := range 3 { err := s.StopWithTimeout(5 * time.Second) if err != nil { t.Errorf("StopWithTimeout() call %d returned error: %v", i+1, err) @@ -375,7 +375,7 @@ func TestTrackStats_MultipleRequests(t *testing.T) { wrappedHandler := s.trackStats(handler) // 执行多次请求 - for i := 0; i < 10; i++ { + for range 10 { ctx := &fasthttp.RequestCtx{} ctx.Init(&fasthttp.Request{}, nil, nil) wrappedHandler(ctx) @@ -1508,7 +1508,7 @@ func TestServer_GetProxyCacheStats_AllProxiesWithCache(t *testing.T) { // 创建多个带缓存的代理 proxies := make([]*proxy.Proxy, 3) - for i := 0; i < 3; i++ { + for i := range 3 { proxyCfg := &config.ProxyConfig{ Path: fmt.Sprintf("/api%d", i), LoadBalance: "round_robin", @@ -1552,7 +1552,7 @@ func TestServer_GetProxyCacheStats_AllProxiesNoCache(t *testing.T) { // 创建多个不带缓存的代理 proxies := make([]*proxy.Proxy, 3) - for i := 0; i < 3; i++ { + for i := range 3 { proxyCfg := &config.ProxyConfig{ Path: fmt.Sprintf("/api%d", i), LoadBalance: "round_robin", @@ -2731,7 +2731,7 @@ func TestShutdownServers_RunningServers(t *testing.T) { servers := make([]*fasthttp.Server, 2) listeners := make([]net.Listener, 2) - for i := 0; i < 2; i++ { + for i := range 2 { ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("failed to create listener: %v", err) @@ -2773,7 +2773,7 @@ func TestShutdownServers_ManyServers(t *testing.T) { // 创建大量服务器 count := 50 servers := make([]*fasthttp.Server, count) - for i := 0; i < count; i++ { + for i := range count { servers[i] = &fasthttp.Server{ Handler: func(ctx *fasthttp.RequestCtx) { ctx.SetBodyString("test") }, } @@ -2792,7 +2792,7 @@ func TestShutdownServers_MixedNilAndRealServers(t *testing.T) { count := 20 servers := make([]*fasthttp.Server, count) - for i := 0; i < count; i++ { + for i := range count { if i%2 == 0 { servers[i] = nil } else { @@ -2814,16 +2814,14 @@ func TestShutdownServers_ConcurrentSafety(t *testing.T) { // 并发调用 shutdownServers var wg sync.WaitGroup - for i := 0; i < 10; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 10 { + wg.Go(func() { servers := []*fasthttp.Server{ {Handler: func(ctx *fasthttp.RequestCtx) { ctx.SetBodyString("test") }}, {Handler: func(ctx *fasthttp.RequestCtx) { ctx.SetBodyString("test") }}, } _ = shutdownServers(ctx, servers) - }() + }) } wg.Wait() } diff --git a/internal/server/upgrade.go b/internal/server/upgrade.go index d65e679..9c294c5 100644 --- a/internal/server/upgrade.go +++ b/internal/server/upgrade.go @@ -94,7 +94,7 @@ func (u *UpgradeManager) WritePid() error { } pid := os.Getpid() - return os.WriteFile(u.pidFile, []byte(fmt.Sprintf("%d", pid)), 0o644) + return os.WriteFile(u.pidFile, fmt.Appendf(nil, "%d", pid), 0o644) } // ReadOldPid 读取旧进程 PID。 @@ -223,7 +223,7 @@ func (u *UpgradeManager) GracefulUpgrade(newBinary string) error { // 写入新 PID 到文件 if u.pidFile != "" { - _ = os.WriteFile(u.pidFile, []byte(fmt.Sprintf("%d", newPid)), 0o644) + _ = os.WriteFile(u.pidFile, fmt.Appendf(nil, "%d", newPid), 0o644) } // 启动 goroutine 等待子进程结束,避免产生僵尸进程 diff --git a/internal/ssl/session_tickets_test.go b/internal/ssl/session_tickets_test.go index 9b7ee33..05ad33d 100644 --- a/internal/ssl/session_tickets_test.go +++ b/internal/ssl/session_tickets_test.go @@ -184,7 +184,7 @@ func TestSessionTicketManager_KeyRetention(t *testing.T) { defer mgr.Stop() // 生成多个密钥 - for i := 0; i < 5; i++ { + for i := range 5 { if err := mgr.RotateKey(); err != nil { t.Fatalf("RotateKey() failed at iteration %d: %v", i, err) } @@ -382,7 +382,7 @@ func TestSessionTicketManager_ConcurrentAccess(t *testing.T) { // 协程 1: 持续获取密钥 go func() { - for i := 0; i < 100; i++ { + for range 100 { _ = mgr.GetKeys() time.Sleep(time.Millisecond) } @@ -391,7 +391,7 @@ func TestSessionTicketManager_ConcurrentAccess(t *testing.T) { // 协程 2: 持续获取状态 go func() { - for i := 0; i < 100; i++ { + for range 100 { _ = mgr.GetStatus() time.Sleep(time.Millisecond) } @@ -400,7 +400,7 @@ func TestSessionTicketManager_ConcurrentAccess(t *testing.T) { // 协程 3: 手动轮换 go func() { - for i := 0; i < 20; i++ { + for range 20 { _ = mgr.RotateKey() time.Sleep(5 * time.Millisecond) } @@ -408,7 +408,7 @@ func TestSessionTicketManager_ConcurrentAccess(t *testing.T) { }() // 等待所有协程完成 - for i := 0; i < 3; i++ { + for range 3 { <-done } @@ -442,7 +442,7 @@ func BenchmarkSessionTicketManager_GetKeys(b *testing.B) { defer mgr.Stop() // 预生成多个密钥 - for i := 0; i < 2; i++ { + for range 2 { _ = mgr.RotateKey() } diff --git a/internal/ssl/ssl.go b/internal/ssl/ssl.go index 226ad2a..ee24a9c 100644 --- a/internal/ssl/ssl.go +++ b/internal/ssl/ssl.go @@ -557,7 +557,7 @@ func matchMarker(data []byte, marker []byte) bool { if len(data) < len(marker) { return false } - for i := 0; i < len(marker); i++ { + for i := range marker { if data[i] != marker[i] { return false } diff --git a/internal/ssl/ssl_bench_test.go b/internal/ssl/ssl_bench_test.go index 3aad627..7f73e54 100644 --- a/internal/ssl/ssl_bench_test.go +++ b/internal/ssl/ssl_bench_test.go @@ -368,7 +368,7 @@ func BenchmarkOCSPStapling_GetStatus(b *testing.B) { defer ocspMgr.Stop() // 注册一些模拟状态 - for i := 0; i < 10; i++ { + for i := range 10 { serial := string(rune('0' + i)) ocspMgr.mu.Lock() ocspMgr.responses[serial] = &ocspResponse{ @@ -430,7 +430,7 @@ func BenchmarkSessionResumption(b *testing.B) { defer sessionMgr.Stop() // 预热密钥轮换 - for i := 0; i < 2; i++ { + for range 2 { _ = sessionMgr.RotateKey() } @@ -566,7 +566,7 @@ func BenchmarkSessionTicketManager_ApplyToTLSConfig(b *testing.B) { } defer sessionMgr.Stop() - for i := 0; i < 2; i++ { + for range 2 { _ = sessionMgr.RotateKey() } diff --git a/internal/sslutil/certpool_test.go b/internal/sslutil/certpool_test.go index d6cb627..ac8cf21 100644 --- a/internal/sslutil/certpool_test.go +++ b/internal/sslutil/certpool_test.go @@ -65,7 +65,7 @@ func generateMultipleCerts(t *testing.T, count int) []byte { t.Helper() var pemData []byte - for i := 0; i < count; i++ { + for i := range count { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("Failed to generate private key: %v", err) diff --git a/internal/stream/stream.go b/internal/stream/stream.go index 0b616ac..5ba0942 100644 --- a/internal/stream/stream.go +++ b/internal/stream/stream.go @@ -63,7 +63,7 @@ type Balancer interface { // 使用原子计数器实现线程安全的轮询选择,每次选择后计数器递增, // 确保请求均匀分布到所有健康目标。 type roundRobin struct { - counter uint64 + counter atomic.Uint64 healthyPool sync.Pool } @@ -94,7 +94,7 @@ func (r *roundRobin) Select(targets []*Target) *Target { r.healthyPool.Put(healthyPtr) return nil } - idx := atomic.AddUint64(&r.counter, 1) - 1 + idx := r.counter.Add(1) - 1 result := healthy[idx%uint64(len(healthy))] r.healthyPool.Put(healthyPtr) return result @@ -147,7 +147,7 @@ func (l *leastConn) Select(targets []*Target) *Target { // 根据目标服务器的权重分配请求,权重高的目标获得更多请求。 // 使用原子计数器确保线程安全,支持不同权重的目标混合使用。 type weightedRoundRobin struct { - counter uint64 + counter atomic.Uint64 healthyPool sync.Pool } @@ -194,7 +194,7 @@ func (w *weightedRoundRobin) Select(targets []*Target) *Target { } // 使用原子计数器确定位置 - idx := atomic.AddUint64(&w.counter, 1) - 1 + idx := w.counter.Add(1) - 1 pos := int(idx % uint64(totalWeight)) // 找到对应位置的目标 diff --git a/internal/stream/stream_bench_test.go b/internal/stream/stream_bench_test.go index 755c57a..e5b39a8 100644 --- a/internal/stream/stream_bench_test.go +++ b/internal/stream/stream_bench_test.go @@ -71,7 +71,7 @@ func BenchmarkStreamFilterHealthyPreallocated(b *testing.B) { // 创建目标列表 targets := make([]*Target, targetCount) - for i := 0; i < targetCount; i++ { + for i := range targetCount { targets[i] = &Target{ addr: fmt.Sprintf("backend%d:8080", i), weight: 1, @@ -119,7 +119,7 @@ func BenchmarkUDPSessionAllocations(b *testing.B) { var pool *sync.Pool if tc.poolSize > 0 { pool = &sync.Pool{ - New: func() interface{} { + New: func() any { return make([]byte, tc.bufSize) }, } @@ -168,7 +168,7 @@ func BenchmarkUDPSessionGetOrCreate(b *testing.B) { // 预创建一些客户端地址 clientAddrs := make([]*net.UDPAddr, 100) - for i := 0; i < 100; i++ { + for i := range 100 { clientAddrs[i], _ = net.ResolveUDPAddr("udp", fmt.Sprintf("127.0.0.1:%d", 20000+i)) } @@ -206,7 +206,7 @@ func BenchmarkUDPSessionGetOnly(b *testing.B) { // 预创建会话 clientAddrs := make([]*net.UDPAddr, 100) - for i := 0; i < 100; i++ { + for i := range 100 { clientAddrs[i], _ = net.ResolveUDPAddr("udp", fmt.Sprintf("127.0.0.1:%d", 30000+i)) // 手动创建会话 targetAddr, _ := net.ResolveUDPAddr("udp", upstream.targets[0].addr) diff --git a/internal/stream/stream_coverage_test.go b/internal/stream/stream_coverage_test.go index fc86ccf..5a3e4b4 100644 --- a/internal/stream/stream_coverage_test.go +++ b/internal/stream/stream_coverage_test.go @@ -77,7 +77,7 @@ func TestWeightedRoundRobinZeroWeight(t *testing.T) { wrr := newWeightedRoundRobin().(*weightedRoundRobin) // 权重为 0 或负数应视为权重 1 - for i := 0; i < 4; i++ { + for range 4 { selected := wrr.Select(targets) if selected == nil { t.Error("Select() should return target with zero/negative weight") diff --git a/internal/stream/stream_test.go b/internal/stream/stream_test.go index 399ed38..c809ac4 100644 --- a/internal/stream/stream_test.go +++ b/internal/stream/stream_test.go @@ -77,7 +77,7 @@ func TestRoundRobinBalancer(t *testing.T) { // 测试轮询 results := make(map[string]int) - for i := 0; i < 6; i++ { + for range 6 { selected := rr.Select(targets) if selected == nil { t.Error("Expected non-nil target") @@ -147,7 +147,7 @@ func TestWeightedRoundRobinBalancer(t *testing.T) { // 测试加权分布:3:1 比例 results := make(map[string]int) - for i := 0; i < 8; i++ { + for range 8 { selected := wrr.Select(targets) if selected == nil { t.Error("Expected non-nil target") @@ -306,12 +306,10 @@ func TestConcurrentConnections(t *testing.T) { // 并发增加连接数 var wg sync.WaitGroup - for i := 0; i < 100; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 100 { + wg.Go(func() { atomic.AddInt64(&s.connCount, 1) - }() + }) } wg.Wait() @@ -498,7 +496,7 @@ func TestRoundRobinBalancerWithSingleTarget(t *testing.T) { targets[0].healthy.Store(true) // 测试单个健康目标 - for i := 0; i < 5; i++ { + for range 5 { target := rb.Select(targets) if target == nil { t.Error("Expected non-nil target") diff --git a/internal/variable/integration_test.go b/internal/variable/integration_test.go index da7b1e9..f02a6e4 100644 --- a/internal/variable/integration_test.go +++ b/internal/variable/integration_test.go @@ -138,7 +138,7 @@ func TestVariableExpansionPerformance(t *testing.T) { // 执行多次展开 start := time.Now() iterations := 10000 - for i := 0; i < iterations; i++ { + for range iterations { _ = vc.Expand(template) } elapsed := time.Since(start) diff --git a/internal/variable/ssl_test.go b/internal/variable/ssl_test.go index 397425f..59d74f3 100644 --- a/internal/variable/ssl_test.go +++ b/internal/variable/ssl_test.go @@ -353,7 +353,7 @@ func TestSetSSLClientInfoInContext_WithPeerCert(t *testing.T) { Raw: make([]byte, 25), // 模拟原始数据(25字节) } // 填充可预测的原始数据 - for i := 0; i < 25; i++ { + for i := range 25 { cert.Raw[i] = byte(i + 1) } @@ -367,7 +367,7 @@ func TestSetSSLClientInfoInContext_WithPeerCert(t *testing.T) { tests := []struct { name string key string - expected interface{} + expected any }{ {"verify", VarSSLClientVerify, "SUCCESS"}, {"peer_cert_present", "tls_peer_cert_present", true}, diff --git a/internal/variable/variable.go b/internal/variable/variable.go index f74fbf2..1d63afc 100644 --- a/internal/variable/variable.go +++ b/internal/variable/variable.go @@ -53,7 +53,7 @@ type Context struct { // pool 用于复用 Context var pool = sync.Pool{ - New: func() interface{} { + New: func() any { return &Context{ store: make(map[string]string), cache: make(map[string]string), diff --git a/internal/variable/variable_test.go b/internal/variable/variable_test.go index e6c8fd1..55c3854 100644 --- a/internal/variable/variable_test.go +++ b/internal/variable/variable_test.go @@ -9,6 +9,7 @@ package variable import ( + "slices" "strings" "testing" @@ -455,7 +456,7 @@ func TestPoolReuse(t *testing.T) { ctx := mockRequestCtx(t) // 获取和释放多个 context,确保没有 panic - for i := 0; i < 10; i++ { + for i := range 10 { vc := NewContext(ctx) vc.Set("key", "value") if v, ok := vc.Get("key"); !ok || v != "value" { @@ -813,12 +814,7 @@ func TestBuiltinVarNames(t *testing.T) { // 检查是否包含一些已知变量 hasVar := func(name string) bool { - for _, n := range names { - if n == name { - return true - } - } - return false + return slices.Contains(names, name) } if !hasVar("host") { @@ -1109,9 +1105,9 @@ func TestGlobalVariablesConcurrent(_ *testing.T) { done := make(chan bool) // 并发读取 - for i := 0; i < 10; i++ { + for range 10 { go func() { - for j := 0; j < 100; j++ { + for range 100 { _, _ = GetGlobalVariable("counter") } done <- true @@ -1119,9 +1115,9 @@ func TestGlobalVariablesConcurrent(_ *testing.T) { } // 并发写入 - for i := 0; i < 5; i++ { + for range 5 { go func() { - for j := 0; j < 50; j++ { + for range 50 { SetGlobalVariables(map[string]string{"counter": "updated"}) } done <- true @@ -1129,7 +1125,7 @@ func TestGlobalVariablesConcurrent(_ *testing.T) { } // 等待所有 goroutine 完成 - for i := 0; i < 15; i++ { + for range 15 { <-done } }