fix(plugins): silence plugin warnings and folder creation when plugins disabled (#4297)

* fix(plugins): silence repeated “Plugin not found” spam for inactive Spotify/Last.fm plugins

Navidrome was emitting a warning when the optional Spotify or
Last.fm agents weren’t enabled, filling the journal with entries like:

    level=warning msg="Plugin not found" capability=MetadataAgent name=spotify

Fixed by completely disable the plugin system when Plugins.Enabled = false.

Signed-off-by: Deluan <deluan@navidrome.org>

* style: update test description for clarity

Signed-off-by: Deluan <deluan@navidrome.org>

* fix: ensure plugin folder is created only if plugins are enabled

Signed-off-by: Deluan <deluan@navidrome.org>

---------

Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Deluan Quintão
2025-07-02 13:17:59 -04:00
committed by GitHub
parent 82f490d066
commit a3d1a9dbe5
18 changed files with 102 additions and 64 deletions
+3 -3
View File
@@ -175,7 +175,7 @@ func GetPlaybackServer() playback.PlaybackServer {
return playbackServer return playbackServer
} }
func getPluginManager() *plugins.Manager { func getPluginManager() plugins.Manager {
sqlDB := db.Db() sqlDB := db.Db()
dataStore := persistence.New(sqlDB) dataStore := persistence.New(sqlDB)
metricsMetrics := metrics.GetPrometheusInstance(dataStore) metricsMetrics := metrics.GetPrometheusInstance(dataStore)
@@ -185,9 +185,9 @@ func getPluginManager() *plugins.Manager {
// wire_injectors.go: // wire_injectors.go:
var allProviders = wire.NewSet(core.Set, artwork.Set, server.New, subsonic.New, nativeapi.New, public.New, persistence.New, lastfm.NewRouter, listenbrainz.NewRouter, events.GetBroker, scanner.New, scanner.NewWatcher, plugins.GetManager, metrics.GetPrometheusInstance, db.Db, wire.Bind(new(agents.PluginLoader), new(*plugins.Manager)), wire.Bind(new(scrobbler.PluginLoader), new(*plugins.Manager))) var allProviders = wire.NewSet(core.Set, artwork.Set, server.New, subsonic.New, nativeapi.New, public.New, persistence.New, lastfm.NewRouter, listenbrainz.NewRouter, events.GetBroker, scanner.New, scanner.NewWatcher, plugins.GetManager, metrics.GetPrometheusInstance, db.Db, wire.Bind(new(agents.PluginLoader), new(plugins.Manager)), wire.Bind(new(scrobbler.PluginLoader), new(plugins.Manager)))
func GetPluginManager(ctx context.Context) *plugins.Manager { func GetPluginManager(ctx context.Context) plugins.Manager {
manager := getPluginManager() manager := getPluginManager()
manager.SetSubsonicRouter(CreateSubsonicAPIRouter(ctx)) manager.SetSubsonicRouter(CreateSubsonicAPIRouter(ctx))
return manager return manager
+4 -4
View File
@@ -42,8 +42,8 @@ var allProviders = wire.NewSet(
plugins.GetManager, plugins.GetManager,
metrics.GetPrometheusInstance, metrics.GetPrometheusInstance,
db.Db, db.Db,
wire.Bind(new(agents.PluginLoader), new(*plugins.Manager)), wire.Bind(new(agents.PluginLoader), new(plugins.Manager)),
wire.Bind(new(scrobbler.PluginLoader), new(*plugins.Manager)), wire.Bind(new(scrobbler.PluginLoader), new(plugins.Manager)),
) )
func CreateDataStore() model.DataStore { func CreateDataStore() model.DataStore {
@@ -118,13 +118,13 @@ func GetPlaybackServer() playback.PlaybackServer {
)) ))
} }
func getPluginManager() *plugins.Manager { func getPluginManager() plugins.Manager {
panic(wire.Build( panic(wire.Build(
allProviders, allProviders,
)) ))
} }
func GetPluginManager(ctx context.Context) *plugins.Manager { func GetPluginManager(ctx context.Context) plugins.Manager {
manager := getPluginManager() manager := getPluginManager()
manager.SetSubsonicRouter(CreateSubsonicAPIRouter(ctx)) manager.SetSubsonicRouter(CreateSubsonicAPIRouter(ctx))
return manager return manager
+9 -7
View File
@@ -264,13 +264,15 @@ func Load(noConfigDump bool) {
os.Exit(1) os.Exit(1)
} }
if Server.Plugins.Folder == "" { if Server.Plugins.Enabled {
Server.Plugins.Folder = filepath.Join(Server.DataFolder, "plugins") if Server.Plugins.Folder == "" {
} Server.Plugins.Folder = filepath.Join(Server.DataFolder, "plugins")
err = os.MkdirAll(Server.Plugins.Folder, 0700) }
if err != nil { err = os.MkdirAll(Server.Plugins.Folder, 0700)
_, _ = fmt.Fprintln(os.Stderr, "FATAL: Error creating plugins path:", err) if err != nil {
os.Exit(1) _, _ = fmt.Fprintln(os.Stderr, "FATAL: Error creating plugins path:", err)
os.Exit(1)
}
} }
Server.ConfigFile = viper.GetViper().ConfigFileUsed() Server.ConfigFile = viper.GetViper().ConfigFileUsed()
+1 -1
View File
@@ -10,7 +10,7 @@ import (
) )
// NewWasmMediaAgent creates a new adapter for a MetadataAgent plugin // NewWasmMediaAgent creates a new adapter for a MetadataAgent plugin
func newWasmMediaAgent(wasmPath, pluginID string, m *Manager, runtime api.WazeroNewRuntime, mc wazero.ModuleConfig) WasmPlugin { func newWasmMediaAgent(wasmPath, pluginID string, m *managerImpl, runtime api.WazeroNewRuntime, mc wazero.ModuleConfig) WasmPlugin {
loader, err := api.NewMetadataAgentPlugin(context.Background(), api.WazeroRuntime(runtime), api.WazeroModuleConfig(mc)) loader, err := api.NewMetadataAgentPlugin(context.Background(), api.WazeroRuntime(runtime), api.WazeroModuleConfig(mc))
if err != nil { if err != nil {
log.Error("Error creating media metadata service plugin", "plugin", pluginID, "path", wasmPath, err) log.Error("Error creating media metadata service plugin", "plugin", pluginID, "path", wasmPath, err)
+1 -1
View File
@@ -14,7 +14,7 @@ import (
var _ = Describe("Adapter Media Agent", func() { var _ = Describe("Adapter Media Agent", func() {
var ctx context.Context var ctx context.Context
var mgr *Manager var mgr *managerImpl
BeforeEach(func() { BeforeEach(func() {
ctx = GinkgoT().Context() ctx = GinkgoT().Context()
+1 -1
View File
@@ -9,7 +9,7 @@ import (
) )
// newWasmSchedulerCallback creates a new adapter for a SchedulerCallback plugin // newWasmSchedulerCallback creates a new adapter for a SchedulerCallback plugin
func newWasmSchedulerCallback(wasmPath, pluginID string, m *Manager, runtime api.WazeroNewRuntime, mc wazero.ModuleConfig) WasmPlugin { func newWasmSchedulerCallback(wasmPath, pluginID string, m *managerImpl, runtime api.WazeroNewRuntime, mc wazero.ModuleConfig) WasmPlugin {
loader, err := api.NewSchedulerCallbackPlugin(context.Background(), api.WazeroRuntime(runtime), api.WazeroModuleConfig(mc)) loader, err := api.NewSchedulerCallbackPlugin(context.Background(), api.WazeroRuntime(runtime), api.WazeroModuleConfig(mc))
if err != nil { if err != nil {
log.Error("Error creating scheduler callback plugin", "plugin", pluginID, "path", wasmPath, err) log.Error("Error creating scheduler callback plugin", "plugin", pluginID, "path", wasmPath, err)
+1 -1
View File
@@ -12,7 +12,7 @@ import (
"github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero"
) )
func newWasmScrobblerPlugin(wasmPath, pluginID string, m *Manager, runtime api.WazeroNewRuntime, mc wazero.ModuleConfig) WasmPlugin { func newWasmScrobblerPlugin(wasmPath, pluginID string, m *managerImpl, runtime api.WazeroNewRuntime, mc wazero.ModuleConfig) WasmPlugin {
loader, err := api.NewScrobblerPlugin(context.Background(), api.WazeroRuntime(runtime), api.WazeroModuleConfig(mc)) loader, err := api.NewScrobblerPlugin(context.Background(), api.WazeroRuntime(runtime), api.WazeroModuleConfig(mc))
if err != nil { if err != nil {
log.Error("Error creating scrobbler service plugin", "plugin", pluginID, "path", wasmPath, err) log.Error("Error creating scrobbler service plugin", "plugin", pluginID, "path", wasmPath, err)
+1 -1
View File
@@ -9,7 +9,7 @@ import (
) )
// newWasmWebSocketCallback creates a new adapter for a WebSocketCallback plugin // newWasmWebSocketCallback creates a new adapter for a WebSocketCallback plugin
func newWasmWebSocketCallback(wasmPath, pluginID string, m *Manager, runtime api.WazeroNewRuntime, mc wazero.ModuleConfig) WasmPlugin { func newWasmWebSocketCallback(wasmPath, pluginID string, m *managerImpl, runtime api.WazeroNewRuntime, mc wazero.ModuleConfig) WasmPlugin {
loader, err := api.NewWebSocketCallbackPlugin(context.Background(), api.WazeroRuntime(runtime), api.WazeroModuleConfig(mc)) loader, err := api.NewWebSocketCallbackPlugin(context.Background(), api.WazeroRuntime(runtime), api.WazeroModuleConfig(mc))
if err != nil { if err != nil {
log.Error("Error creating WebSocket callback plugin", "plugin", pluginID, "path", wasmPath, err) log.Error("Error creating WebSocket callback plugin", "plugin", pluginID, "path", wasmPath, err)
+2 -2
View File
@@ -49,13 +49,13 @@ func (s SchedulerHostFunctions) CancelSchedule(ctx context.Context, req *schedul
type schedulerService struct { type schedulerService struct {
// Map of schedule IDs to their callback info // Map of schedule IDs to their callback info
schedules map[string]*ScheduledCallback schedules map[string]*ScheduledCallback
manager *Manager manager *managerImpl
navidSched navidsched.Scheduler // Navidrome scheduler for recurring jobs navidSched navidsched.Scheduler // Navidrome scheduler for recurring jobs
mu sync.Mutex mu sync.Mutex
} }
// newSchedulerService creates a new schedulerService instance // newSchedulerService creates a new schedulerService instance
func newSchedulerService(manager *Manager) *schedulerService { func newSchedulerService(manager *managerImpl) *schedulerService {
return &schedulerService{ return &schedulerService{
schedules: make(map[string]*ScheduledCallback), schedules: make(map[string]*ScheduledCallback),
manager: manager, manager: manager,
+1 -1
View File
@@ -11,7 +11,7 @@ import (
var _ = Describe("SchedulerService", func() { var _ = Describe("SchedulerService", func() {
var ( var (
ss *schedulerService ss *schedulerService
manager *Manager manager *managerImpl
pluginName = "test_plugin" pluginName = "test_plugin"
) )
+2 -2
View File
@@ -50,12 +50,12 @@ func (s WebSocketHostFunctions) Close(ctx context.Context, req *websocket.CloseR
// websocketService implements the WebSocket service functionality // websocketService implements the WebSocket service functionality
type websocketService struct { type websocketService struct {
connections map[string]*WebSocketConnection connections map[string]*WebSocketConnection
manager *Manager manager *managerImpl
mu sync.RWMutex mu sync.RWMutex
} }
// newWebsocketService creates a new websocketService instance // newWebsocketService creates a new websocketService instance
func newWebsocketService(manager *Manager) *websocketService { func newWebsocketService(manager *managerImpl) *websocketService {
return &websocketService{ return &websocketService{
connections: make(map[string]*WebSocketConnection), connections: make(map[string]*WebSocketConnection),
manager: manager, manager: manager,
+1 -1
View File
@@ -17,7 +17,7 @@ import (
var _ = Describe("WebSocket Host Service", func() { var _ = Describe("WebSocket Host Service", func() {
var ( var (
wsService *websocketService wsService *websocketService
manager *Manager manager *managerImpl
ctx context.Context ctx context.Context
server *httptest.Server server *httptest.Server
upgrader gorillaws.Upgrader upgrader gorillaws.Upgrader
+67 -31
View File
@@ -40,7 +40,7 @@ const (
) )
// pluginCreators maps capability types to their respective creator functions // pluginCreators maps capability types to their respective creator functions
type pluginConstructor func(wasmPath, pluginID string, m *Manager, runtime api.WazeroNewRuntime, mc wazero.ModuleConfig) WasmPlugin type pluginConstructor func(wasmPath, pluginID string, m *managerImpl, runtime api.WazeroNewRuntime, mc wazero.ModuleConfig) WasmPlugin
var pluginCreators = map[string]pluginConstructor{ var pluginCreators = map[string]pluginConstructor{
CapabilityMetadataAgent: newWasmMediaAgent, CapabilityMetadataAgent: newWasmMediaAgent,
@@ -86,8 +86,21 @@ func (p *plugin) waitForCompilation() error {
type SubsonicRouter http.Handler type SubsonicRouter http.Handler
// Manager is a singleton that manages plugins type Manager interface {
type Manager struct { SetSubsonicRouter(router SubsonicRouter)
EnsureCompiled(name string) error
PluginNames(serviceName string) []string
LoadPlugin(name string, capability string) WasmPlugin
LoadAllPlugins(capability string) []WasmPlugin
LoadMediaAgent(name string) (agents.Interface, bool)
LoadAllMediaAgents() []agents.Interface
LoadScrobbler(name string) (scrobbler.Scrobbler, bool)
LoadAllScrobblers() []scrobbler.Scrobbler
ScanPlugins()
}
// managerImpl is a singleton that manages plugins
type managerImpl struct {
plugins map[string]*plugin // Map of plugin folder name to plugin info plugins map[string]*plugin // Map of plugin folder name to plugin info
mu sync.RWMutex // Protects plugins map mu sync.RWMutex // Protects plugins map
subsonicRouter atomic.Pointer[SubsonicRouter] // Subsonic API router subsonicRouter atomic.Pointer[SubsonicRouter] // Subsonic API router
@@ -99,16 +112,19 @@ type Manager struct {
metrics metrics.Metrics metrics metrics.Metrics
} }
// GetManager returns the singleton instance of Manager // GetManager returns the singleton instance of managerImpl
func GetManager(ds model.DataStore, metrics metrics.Metrics) *Manager { func GetManager(ds model.DataStore, metrics metrics.Metrics) Manager {
return singleton.GetInstance(func() *Manager { if !conf.Server.Plugins.Enabled {
return &noopManager{}
}
return singleton.GetInstance(func() *managerImpl {
return createManager(ds, metrics) return createManager(ds, metrics)
}) })
} }
// createManager creates a new Manager instance. Used in tests // createManager creates a new managerImpl instance. Used in tests
func createManager(ds model.DataStore, metrics metrics.Metrics) *Manager { func createManager(ds model.DataStore, metrics metrics.Metrics) *managerImpl {
m := &Manager{ m := &managerImpl{
plugins: make(map[string]*plugin), plugins: make(map[string]*plugin),
lifecycle: newPluginLifecycleManager(), lifecycle: newPluginLifecycleManager(),
ds: ds, ds: ds,
@@ -122,14 +138,14 @@ func createManager(ds model.DataStore, metrics metrics.Metrics) *Manager {
return m return m
} }
// SetSubsonicRouter sets the SubsonicRouter after Manager initialization // SetSubsonicRouter sets the SubsonicRouter after managerImpl initialization
func (m *Manager) SetSubsonicRouter(router SubsonicRouter) { func (m *managerImpl) SetSubsonicRouter(router SubsonicRouter) {
m.subsonicRouter.Store(&router) m.subsonicRouter.Store(&router)
} }
// registerPlugin adds a plugin to the registry with the given parameters // registerPlugin adds a plugin to the registry with the given parameters
// Used internally by ScanPlugins to register plugins // Used internally by ScanPlugins to register plugins
func (m *Manager) registerPlugin(pluginID, pluginDir, wasmPath string, manifest *schema.PluginManifest) *plugin { func (m *managerImpl) registerPlugin(pluginID, pluginDir, wasmPath string, manifest *schema.PluginManifest) *plugin {
// Create custom runtime function // Create custom runtime function
customRuntime := m.createRuntime(pluginID, manifest.Permissions) customRuntime := m.createRuntime(pluginID, manifest.Permissions)
@@ -190,7 +206,7 @@ func (m *Manager) registerPlugin(pluginID, pluginDir, wasmPath string, manifest
} }
// initializePluginIfNeeded calls OnInit on plugins that implement LifecycleManagement // initializePluginIfNeeded calls OnInit on plugins that implement LifecycleManagement
func (m *Manager) initializePluginIfNeeded(plugin *plugin) { func (m *managerImpl) initializePluginIfNeeded(plugin *plugin) {
// Skip if already initialized // Skip if already initialized
if m.lifecycle.isInitialized(plugin) { if m.lifecycle.isInitialized(plugin) {
return return
@@ -207,7 +223,7 @@ func (m *Manager) initializePluginIfNeeded(plugin *plugin) {
} }
// ScanPlugins scans the plugins directory, discovers all valid plugins, and registers them for use. // ScanPlugins scans the plugins directory, discovers all valid plugins, and registers them for use.
func (m *Manager) ScanPlugins() { func (m *managerImpl) ScanPlugins() {
// Clear existing plugins // Clear existing plugins
m.mu.Lock() m.mu.Lock()
m.plugins = make(map[string]*plugin) m.plugins = make(map[string]*plugin)
@@ -259,7 +275,7 @@ func (m *Manager) ScanPlugins() {
} }
// PluginNames returns the folder names of all plugins that implement the specified capability // PluginNames returns the folder names of all plugins that implement the specified capability
func (m *Manager) PluginNames(capability string) []string { func (m *managerImpl) PluginNames(capability string) []string {
m.mu.RLock() m.mu.RLock()
defer m.mu.RUnlock() defer m.mu.RUnlock()
@@ -275,28 +291,26 @@ func (m *Manager) PluginNames(capability string) []string {
return names return names
} }
func (m *Manager) getPlugin(name string, capability string) (*plugin, WasmPlugin) { func (m *managerImpl) getPlugin(name string, capability string) (*plugin, WasmPlugin, error) {
m.mu.RLock() m.mu.RLock()
defer m.mu.RUnlock() defer m.mu.RUnlock()
info, infoOk := m.plugins[name] info, infoOk := m.plugins[name]
adapter, adapterOk := m.adapters[name+"_"+capability] adapter, adapterOk := m.adapters[name+"_"+capability]
if !infoOk { if !infoOk {
log.Warn("Plugin not found", "name", name) return nil, nil, fmt.Errorf("plugin not registered: %s", name)
return nil, nil
} }
if !adapterOk { if !adapterOk {
log.Warn("Plugin adapter not found", "name", name, "capability", capability) return nil, nil, fmt.Errorf("plugin adapter not registered: %s, capability: %s", name, capability)
return nil, nil
} }
return info, adapter return info, adapter, nil
} }
// LoadPlugin instantiates and returns a plugin by folder name // LoadPlugin instantiates and returns a plugin by folder name
func (m *Manager) LoadPlugin(name string, capability string) WasmPlugin { func (m *managerImpl) LoadPlugin(name string, capability string) WasmPlugin {
info, adapter := m.getPlugin(name, capability) info, adapter, err := m.getPlugin(name, capability)
if info == nil { if err != nil {
log.Warn("Plugin not found", "name", name, "capability", capability) log.Warn("Error loading plugin", err)
return nil return nil
} }
@@ -318,7 +332,7 @@ func (m *Manager) LoadPlugin(name string, capability string) WasmPlugin {
// EnsureCompiled waits for a plugin to finish compilation and returns any compilation error. // EnsureCompiled waits for a plugin to finish compilation and returns any compilation error.
// This is useful when you need to wait for compilation without loading a specific capability, // This is useful when you need to wait for compilation without loading a specific capability,
// such as during plugin refresh operations or health checks. // such as during plugin refresh operations or health checks.
func (m *Manager) EnsureCompiled(name string) error { func (m *managerImpl) EnsureCompiled(name string) error {
m.mu.RLock() m.mu.RLock()
plugin, ok := m.plugins[name] plugin, ok := m.plugins[name]
m.mu.RUnlock() m.mu.RUnlock()
@@ -331,7 +345,7 @@ func (m *Manager) EnsureCompiled(name string) error {
} }
// LoadAllPlugins instantiates and returns all plugins that implement the specified capability // LoadAllPlugins instantiates and returns all plugins that implement the specified capability
func (m *Manager) LoadAllPlugins(capability string) []WasmPlugin { func (m *managerImpl) LoadAllPlugins(capability string) []WasmPlugin {
names := m.PluginNames(capability) names := m.PluginNames(capability)
if len(names) == 0 { if len(names) == 0 {
return nil return nil
@@ -348,7 +362,7 @@ func (m *Manager) LoadAllPlugins(capability string) []WasmPlugin {
} }
// LoadMediaAgent instantiates and returns a media agent plugin by folder name // LoadMediaAgent instantiates and returns a media agent plugin by folder name
func (m *Manager) LoadMediaAgent(name string) (agents.Interface, bool) { func (m *managerImpl) LoadMediaAgent(name string) (agents.Interface, bool) {
plugin := m.LoadPlugin(name, CapabilityMetadataAgent) plugin := m.LoadPlugin(name, CapabilityMetadataAgent)
if plugin == nil { if plugin == nil {
return nil, false return nil, false
@@ -358,7 +372,7 @@ func (m *Manager) LoadMediaAgent(name string) (agents.Interface, bool) {
} }
// LoadAllMediaAgents instantiates and returns all media agent plugins // LoadAllMediaAgents instantiates and returns all media agent plugins
func (m *Manager) LoadAllMediaAgents() []agents.Interface { func (m *managerImpl) LoadAllMediaAgents() []agents.Interface {
plugins := m.LoadAllPlugins(CapabilityMetadataAgent) plugins := m.LoadAllPlugins(CapabilityMetadataAgent)
return slice.Map(plugins, func(p WasmPlugin) agents.Interface { return slice.Map(plugins, func(p WasmPlugin) agents.Interface {
@@ -367,7 +381,7 @@ func (m *Manager) LoadAllMediaAgents() []agents.Interface {
} }
// LoadScrobbler instantiates and returns a scrobbler plugin by folder name // LoadScrobbler instantiates and returns a scrobbler plugin by folder name
func (m *Manager) LoadScrobbler(name string) (scrobbler.Scrobbler, bool) { func (m *managerImpl) LoadScrobbler(name string) (scrobbler.Scrobbler, bool) {
plugin := m.LoadPlugin(name, CapabilityScrobbler) plugin := m.LoadPlugin(name, CapabilityScrobbler)
if plugin == nil { if plugin == nil {
return nil, false return nil, false
@@ -377,10 +391,32 @@ func (m *Manager) LoadScrobbler(name string) (scrobbler.Scrobbler, bool) {
} }
// LoadAllScrobblers instantiates and returns all scrobbler plugins // LoadAllScrobblers instantiates and returns all scrobbler plugins
func (m *Manager) LoadAllScrobblers() []scrobbler.Scrobbler { func (m *managerImpl) LoadAllScrobblers() []scrobbler.Scrobbler {
plugins := m.LoadAllPlugins(CapabilityScrobbler) plugins := m.LoadAllPlugins(CapabilityScrobbler)
return slice.Map(plugins, func(p WasmPlugin) scrobbler.Scrobbler { return slice.Map(plugins, func(p WasmPlugin) scrobbler.Scrobbler {
return p.(scrobbler.Scrobbler) return p.(scrobbler.Scrobbler)
}) })
} }
type noopManager struct{}
func (n noopManager) SetSubsonicRouter(router SubsonicRouter) {}
func (n noopManager) EnsureCompiled(name string) error { return nil }
func (n noopManager) PluginNames(serviceName string) []string { return nil }
func (n noopManager) LoadPlugin(name string, capability string) WasmPlugin { return nil }
func (n noopManager) LoadAllPlugins(capability string) []WasmPlugin { return nil }
func (n noopManager) LoadMediaAgent(name string) (agents.Interface, bool) { return nil, false }
func (n noopManager) LoadAllMediaAgents() []agents.Interface { return nil }
func (n noopManager) LoadScrobbler(name string) (scrobbler.Scrobbler, bool) { return nil, false }
func (n noopManager) LoadAllScrobblers() []scrobbler.Scrobbler { return nil }
func (n noopManager) ScanPlugins() {}
+2 -2
View File
@@ -12,7 +12,7 @@ import (
) )
var _ = Describe("Plugin Manager", func() { var _ = Describe("Plugin Manager", func() {
var mgr *Manager var mgr *managerImpl
var ctx context.Context var ctx context.Context
BeforeEach(func() { BeforeEach(func() {
@@ -76,7 +76,7 @@ var _ = Describe("Plugin Manager", func() {
Describe("ScanPlugins", func() { Describe("ScanPlugins", func() {
var tempPluginsDir string var tempPluginsDir string
var m *Manager var m *managerImpl
BeforeEach(func() { BeforeEach(func() {
tempPluginsDir, _ = os.MkdirTemp("", "navidrome-plugins-test-*") tempPluginsDir, _ = os.MkdirTemp("", "navidrome-plugins-test-*")
+1 -1
View File
@@ -47,7 +47,7 @@ func createTestPlugin(tempDir, name string, permissions schema.PluginManifestPer
var _ = Describe("Plugin Permissions", func() { var _ = Describe("Plugin Permissions", func() {
var ( var (
mgr *Manager mgr *managerImpl
tempDir string tempDir string
ctx context.Context ctx context.Context
) )
+1 -1
View File
@@ -18,7 +18,7 @@ func hasInitService(info *plugin) bool {
} }
var _ = Describe("LifecycleManagement", func() { var _ = Describe("LifecycleManagement", func() {
Describe("Plugin Lifecycle Manager", func() { Describe("Plugin Lifecycle managerImpl", func() {
var lifecycleManager *pluginLifecycleManager var lifecycleManager *pluginLifecycleManager
BeforeEach(func() { BeforeEach(func() {
+3 -3
View File
@@ -41,7 +41,7 @@ var (
// createRuntime returns a function that creates a new wazero runtime and instantiates the required host functions // createRuntime returns a function that creates a new wazero runtime and instantiates the required host functions
// based on the given plugin permissions // based on the given plugin permissions
func (m *Manager) createRuntime(pluginID string, permissions schema.PluginManifestPermissions) api.WazeroNewRuntime { func (m *managerImpl) createRuntime(pluginID string, permissions schema.PluginManifestPermissions) api.WazeroNewRuntime {
return func(ctx context.Context) (wazero.Runtime, error) { return func(ctx context.Context) (wazero.Runtime, error) {
// Check if runtime already exists // Check if runtime already exists
if rt, ok := runtimePool.Load(pluginID); ok { if rt, ok := runtimePool.Load(pluginID); ok {
@@ -70,7 +70,7 @@ func (m *Manager) createRuntime(pluginID string, permissions schema.PluginManife
} }
// createCachingRuntime handles the complex logic of setting up a new cachingRuntime // createCachingRuntime handles the complex logic of setting up a new cachingRuntime
func (m *Manager) createCachingRuntime(ctx context.Context, pluginID string, permissions schema.PluginManifestPermissions) (*cachingRuntime, error) { func (m *managerImpl) createCachingRuntime(ctx context.Context, pluginID string, permissions schema.PluginManifestPermissions) (*cachingRuntime, error) {
// Get compilation cache // Get compilation cache
compCache, err := getCompilationCache() compCache, err := getCompilationCache()
if err != nil { if err != nil {
@@ -94,7 +94,7 @@ func (m *Manager) createCachingRuntime(ctx context.Context, pluginID string, per
} }
// setupHostServices configures all the permitted host services for a plugin // setupHostServices configures all the permitted host services for a plugin
func (m *Manager) setupHostServices(ctx context.Context, r wazero.Runtime, pluginID string, permissions schema.PluginManifestPermissions) error { func (m *managerImpl) setupHostServices(ctx context.Context, r wazero.Runtime, pluginID string, permissions schema.PluginManifestPermissions) error {
// Define all available host services // Define all available host services
type hostService struct { type hostService struct {
name string name string
+1 -1
View File
@@ -34,7 +34,7 @@ var _ = Describe("Runtime", func() {
var _ = Describe("CachingRuntime", func() { var _ = Describe("CachingRuntime", func() {
var ( var (
ctx context.Context ctx context.Context
mgr *Manager mgr *managerImpl
plugin *wasmScrobblerPlugin plugin *wasmScrobblerPlugin
) )