From 03a36c5bddc74726a7b8d8002ac6678784999342 Mon Sep 17 00:00:00 2001 From: Deluan Date: Thu, 5 Mar 2026 16:03:06 -0500 Subject: [PATCH] refactor: inject matcher.Matcher via Wire instead of creating it inline Replaced inline matcher.New(ds) calls in external.provider and PlaylistGenerator orchestrator with proper dependency injection via Google Wire. Added matcher.New to the Wire provider set, updated NewProvider and GetManager signatures to accept *matcher.Matcher, and deleted the trivial provider_matching.go wrapper. This eliminates tight coupling where each caller knew how to construct a Matcher, following the same DI pattern used by other core services. Signed-off-by: Deluan --- cmd/wire_gen.go | 23 ++++++++++++----------- core/metrics/insights.go | 2 +- plugins/manager.go | 5 ++++- plugins/manager_loader.go | 2 +- plugins/playlist_generator.go | 4 ++-- plugins/plugins_suite_test.go | 2 ++ 6 files changed, 22 insertions(+), 16 deletions(-) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index b25b4c100..890f9c60b 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -71,9 +71,9 @@ func CreateNativeAPIRouter(ctx context.Context) *nativeapi.Router { fFmpeg := ffmpeg.New() broker := events.GetBroker() metricsMetrics := metrics.GetPrometheusInstance(dataStore) - manager := plugins.GetManager(dataStore, broker, metricsMetrics) - agentsAgents := agents.GetAgents(dataStore, manager) matcherMatcher := matcher.New(dataStore) + manager := plugins.GetManager(dataStore, broker, metricsMetrics, matcherMatcher) + agentsAgents := agents.GetAgents(dataStore, manager) provider := external.NewProvider(dataStore, agentsAgents, matcherMatcher) artworkArtwork := artwork.NewArtwork(dataStore, fileCache, fFmpeg, provider) cacheWarmer := artwork.NewCacheWarmer(artworkArtwork, fileCache) @@ -93,9 +93,9 @@ func CreateSubsonicAPIRouter(ctx context.Context) *subsonic.Router { fFmpeg := ffmpeg.New() broker := events.GetBroker() metricsMetrics := metrics.GetPrometheusInstance(dataStore) - manager := plugins.GetManager(dataStore, broker, metricsMetrics) - agentsAgents := agents.GetAgents(dataStore, manager) matcherMatcher := matcher.New(dataStore) + manager := plugins.GetManager(dataStore, broker, metricsMetrics, matcherMatcher) + agentsAgents := agents.GetAgents(dataStore, manager) provider := external.NewProvider(dataStore, agentsAgents, matcherMatcher) artworkArtwork := artwork.NewArtwork(dataStore, fileCache, fFmpeg, provider) transcodingCache := stream.GetTranscodingCache() @@ -122,9 +122,9 @@ func CreatePublicRouter() *public.Router { fFmpeg := ffmpeg.New() broker := events.GetBroker() metricsMetrics := metrics.GetPrometheusInstance(dataStore) - manager := plugins.GetManager(dataStore, broker, metricsMetrics) - agentsAgents := agents.GetAgents(dataStore, manager) matcherMatcher := matcher.New(dataStore) + manager := plugins.GetManager(dataStore, broker, metricsMetrics, matcherMatcher) + agentsAgents := agents.GetAgents(dataStore, manager) provider := external.NewProvider(dataStore, agentsAgents, matcherMatcher) artworkArtwork := artwork.NewArtwork(dataStore, fileCache, fFmpeg, provider) transcodingCache := stream.GetTranscodingCache() @@ -170,9 +170,9 @@ func CreateScanner(ctx context.Context) model.Scanner { fFmpeg := ffmpeg.New() broker := events.GetBroker() metricsMetrics := metrics.GetPrometheusInstance(dataStore) - manager := plugins.GetManager(dataStore, broker, metricsMetrics) - agentsAgents := agents.GetAgents(dataStore, manager) matcherMatcher := matcher.New(dataStore) + manager := plugins.GetManager(dataStore, broker, metricsMetrics, matcherMatcher) + agentsAgents := agents.GetAgents(dataStore, manager) provider := external.NewProvider(dataStore, agentsAgents, matcherMatcher) artworkArtwork := artwork.NewArtwork(dataStore, fileCache, fFmpeg, provider) cacheWarmer := artwork.NewCacheWarmer(artworkArtwork, fileCache) @@ -189,9 +189,9 @@ func CreateScanWatcher(ctx context.Context) scanner.Watcher { fFmpeg := ffmpeg.New() broker := events.GetBroker() metricsMetrics := metrics.GetPrometheusInstance(dataStore) - manager := plugins.GetManager(dataStore, broker, metricsMetrics) - agentsAgents := agents.GetAgents(dataStore, manager) matcherMatcher := matcher.New(dataStore) + manager := plugins.GetManager(dataStore, broker, metricsMetrics, matcherMatcher) + agentsAgents := agents.GetAgents(dataStore, manager) provider := external.NewProvider(dataStore, agentsAgents, matcherMatcher) artworkArtwork := artwork.NewArtwork(dataStore, fileCache, fFmpeg, provider) cacheWarmer := artwork.NewCacheWarmer(artworkArtwork, fileCache) @@ -214,7 +214,8 @@ func getPluginManager() *plugins.Manager { dataStore := persistence.New(sqlDB) broker := events.GetBroker() metricsMetrics := metrics.GetPrometheusInstance(dataStore) - manager := plugins.GetManager(dataStore, broker, metricsMetrics) + matcherMatcher := matcher.New(dataStore) + manager := plugins.GetManager(dataStore, broker, metricsMetrics, matcherMatcher) return manager } diff --git a/core/metrics/insights.go b/core/metrics/insights.go index f069d3fb6..db835bb42 100644 --- a/core/metrics/insights.go +++ b/core/metrics/insights.go @@ -324,7 +324,7 @@ func (c *insightsCollector) hasSmartPlaylists(ctx context.Context) (bool, error) // collectPlugins collects information about installed plugins func (c *insightsCollector) collectPlugins(_ context.Context) map[string]insights.PluginInfo { // TODO Fix import/inject cycles - manager := plugins.GetManager(c.ds, events.GetBroker(), nil) + manager := plugins.GetManager(c.ds, events.GetBroker(), nil, nil) info := manager.GetPluginInfo() result := make(map[string]insights.PluginInfo, len(info)) diff --git a/plugins/manager.go b/plugins/manager.go index 0c7c91ed8..3e6cc75fe 100644 --- a/plugins/manager.go +++ b/plugins/manager.go @@ -17,6 +17,7 @@ import ( "github.com/navidrome/navidrome/conf" "github.com/navidrome/navidrome/core/agents" "github.com/navidrome/navidrome/core/lyrics" + "github.com/navidrome/navidrome/core/matcher" "github.com/navidrome/navidrome/core/scrobbler" "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" @@ -66,16 +67,18 @@ type Manager struct { ds model.DataStore broker events.Broker metrics PluginMetricsRecorder + matcher *matcher.Matcher } // GetManager returns a singleton instance of the plugin manager. // The manager is not started automatically; call Start() to begin loading plugins. -func GetManager(ds model.DataStore, broker events.Broker, m PluginMetricsRecorder) *Manager { +func GetManager(ds model.DataStore, broker events.Broker, m PluginMetricsRecorder, mt *matcher.Matcher) *Manager { return singleton.GetInstance(func() *Manager { return &Manager{ ds: ds, broker: broker, metrics: m, + matcher: mt, plugins: make(map[string]*plugin), } }) diff --git a/plugins/manager_loader.go b/plugins/manager_loader.go index e394911f7..406c2f183 100644 --- a/plugins/manager_loader.go +++ b/plugins/manager_loader.go @@ -394,7 +394,7 @@ func (m *Manager) loadPluginWithConfig(p *model.Plugin) error { // Start PlaylistGenerator orchestrator if capability is detected loadedPlugin := m.plugins[p.ID] if hasCapability(loadedPlugin.capabilities, CapabilityPlaylistGenerator) { - orch := newPlaylistGeneratorOrchestrator(m.ctx, p.ID, loadedPlugin, m.ds) + orch := newPlaylistGeneratorOrchestrator(m.ctx, p.ID, loadedPlugin, m.ds, m.matcher) loadedPlugin.closers = append(loadedPlugin.closers, orch) go orch.run() } diff --git a/plugins/playlist_generator.go b/plugins/playlist_generator.go index 64766bb3a..a2a684228 100644 --- a/plugins/playlist_generator.go +++ b/plugins/playlist_generator.go @@ -68,13 +68,13 @@ type playlistGeneratorOrchestrator struct { done chan struct{} // closed when worker exits } -func newPlaylistGeneratorOrchestrator(parentCtx context.Context, pluginName string, p *plugin, ds model.DataStore) *playlistGeneratorOrchestrator { +func newPlaylistGeneratorOrchestrator(parentCtx context.Context, pluginName string, p *plugin, ds model.DataStore, m *matcher.Matcher) *playlistGeneratorOrchestrator { ctx, cancel := context.WithCancel(parentCtx) return &playlistGeneratorOrchestrator{ pluginName: pluginName, plugin: p, ds: ds, - matcher: matcher.New(ds), + matcher: m, ctx: ctx, cancel: cancel, workCh: make(chan workItem, workChCapacity), diff --git a/plugins/plugins_suite_test.go b/plugins/plugins_suite_test.go index 41adbc133..42bf64e5b 100644 --- a/plugins/plugins_suite_test.go +++ b/plugins/plugins_suite_test.go @@ -17,6 +17,7 @@ import ( "github.com/navidrome/navidrome/conf" "github.com/navidrome/navidrome/conf/configtest" + "github.com/navidrome/navidrome/core/matcher" "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" "github.com/navidrome/navidrome/tests" @@ -145,6 +146,7 @@ func createTestManagerWithPluginsAndMetrics(pluginConfig map[string]map[string]s manager := &Manager{ plugins: make(map[string]*plugin), ds: dataStore, + matcher: matcher.New(dataStore), metrics: metrics, subsonicRouter: http.NotFoundHandler(), // Stub router for tests }