From f3d2c1931cd1601159a517aac79ec81bd08eddb8 Mon Sep 17 00:00:00 2001 From: erio Date: Sun, 12 Apr 2026 00:28:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(lint):=20resolve=20depguard=20violation=20?= =?UTF-8?q?=E2=80=94=20remove=20redis=20import=20from=20service=20layer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Service layer must not import redis directly (depguard rule). Replace *redis.Client field with WebSearchManagerBuilder callback injected by the infra layer. Also fix remaining errcheck in manager_test.go. --- .../internal/pkg/websearch/manager_test.go | 4 +- backend/internal/service/setting_service.go | 16 ++++---- backend/internal/service/websearch_config.go | 38 +++++++------------ 3 files changed, 25 insertions(+), 33 deletions(-) diff --git a/backend/internal/pkg/websearch/manager_test.go b/backend/internal/pkg/websearch/manager_test.go index 4387a2eea7..859c3e9dd3 100644 --- a/backend/internal/pkg/websearch/manager_test.go +++ b/backend/internal/pkg/websearch/manager_test.go @@ -50,7 +50,7 @@ func TestManager_SearchWithBestProvider_PriorityOrder(t *testing.T) { srvBrave := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { resp := braveResponse{} resp.Web.Results = []braveResult{{URL: "https://brave.com", Title: "Brave", Description: "from brave"}} - json.NewEncoder(w).Encode(resp) + _ = json.NewEncoder(w).Encode(resp) })) defer srvBrave.Close() @@ -80,7 +80,7 @@ func TestManager_SearchWithBestProvider_NilRedis(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { resp := braveResponse{} resp.Web.Results = []braveResult{{URL: "https://test.com", Title: "Test", Description: "result"}} - json.NewEncoder(w).Encode(resp) + _ = json.NewEncoder(w).Encode(resp) })) defer srv.Close() diff --git a/backend/internal/service/setting_service.go b/backend/internal/service/setting_service.go index b7e886934c..7a9023bcb2 100644 --- a/backend/internal/service/setting_service.go +++ b/backend/internal/service/setting_service.go @@ -18,7 +18,6 @@ import ( "github.com/Wei-Shaw/sub2api/internal/config" infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" "github.com/imroc/req/v3" - "github.com/redis/go-redis/v9" "golang.org/x/sync/singleflight" ) @@ -100,14 +99,17 @@ type DefaultSubscriptionGroupReader interface { GetByID(ctx context.Context, id int64) (*Group, error) } +// WebSearchManagerBuilder creates a websearch.Manager from config (injected by infra layer). +type WebSearchManagerBuilder func(cfg *WebSearchEmulationConfig) + // SettingService 系统设置服务 type SettingService struct { - settingRepo SettingRepository - defaultSubGroupReader DefaultSubscriptionGroupReader - cfg *config.Config - onUpdate func() // Callback when settings are updated (for cache invalidation) - version string // Application version - webSearchRedis *redis.Client // optional: Redis client for web search quota tracking + settingRepo SettingRepository + defaultSubGroupReader DefaultSubscriptionGroupReader + cfg *config.Config + onUpdate func() // Callback when settings are updated (for cache invalidation) + version string // Application version + webSearchManagerBuilder WebSearchManagerBuilder } // NewSettingService 创建系统设置服务实例 diff --git a/backend/internal/service/websearch_config.go b/backend/internal/service/websearch_config.go index d59a5a7555..338604af9f 100644 --- a/backend/internal/service/websearch_config.go +++ b/backend/internal/service/websearch_config.go @@ -10,7 +10,6 @@ import ( infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" "github.com/Wei-Shaw/sub2api/internal/pkg/websearch" - "github.com/redis/go-redis/v9" "golang.org/x/sync/singleflight" ) @@ -167,7 +166,7 @@ func (s *SettingService) SaveWebSearchEmulationConfig(ctx context.Context, cfg * }) // Hot-reload: rebuild the global Manager with new config - s.RebuildWebSearchManager(ctx) + s.rebuildWebSearchManager(ctx) return nil } @@ -209,34 +208,25 @@ func (s *SettingService) IsWebSearchEmulationEnabled(ctx context.Context) bool { return cfg.Enabled && len(cfg.Providers) > 0 } -// SetWebSearchRedisClient injects the Redis client used for quota tracking. -// Call after construction, before first use. Triggers initial Manager build. -func (s *SettingService) SetWebSearchRedisClient(ctx context.Context, redisClient *redis.Client) { - s.webSearchRedis = redisClient - s.RebuildWebSearchManager(ctx) +// SetWebSearchManagerBuilder injects a callback that creates and wires a websearch.Manager. +// The infra layer (main/wire) provides this builder, keeping redis out of the service layer. +// Triggers initial build. +func (s *SettingService) SetWebSearchManagerBuilder(ctx context.Context, builder WebSearchManagerBuilder) { + s.webSearchManagerBuilder = builder + s.rebuildWebSearchManager(ctx) } -// RebuildWebSearchManager reads the current config and (re)creates the global websearch.Manager. -// Called on startup and after SaveWebSearchEmulationConfig. -func (s *SettingService) RebuildWebSearchManager(ctx context.Context) { +// rebuildWebSearchManager reads the current config and invokes the builder. +func (s *SettingService) rebuildWebSearchManager(ctx context.Context) { + if s.webSearchManagerBuilder == nil { + return + } cfg, err := s.GetWebSearchEmulationConfig(ctx) - if err != nil || !cfg.Enabled || len(cfg.Providers) == 0 { + if err != nil { SetWebSearchManager(nil) return } - providerConfigs := make([]websearch.ProviderConfig, 0, len(cfg.Providers)) - for _, p := range cfg.Providers { - providerConfigs = append(providerConfigs, websearch.ProviderConfig{ - Type: p.Type, - APIKey: p.APIKey, - Priority: p.Priority, - QuotaLimit: p.QuotaLimit, - QuotaRefreshInterval: p.QuotaRefreshInterval, - ExpiresAt: p.ExpiresAt, - }) - } - SetWebSearchManager(websearch.NewManager(providerConfigs, s.webSearchRedis)) - slog.Info("websearch: manager rebuilt", "provider_count", len(providerConfigs)) + s.webSearchManagerBuilder(cfg) } // SanitizeWebSearchConfig returns a copy with api_key fields masked for API responses.