mirror of
https://github.com/navidrome/navidrome.git
synced 2026-10-10 03:17:27 +02:00
fix(plugins): share lyrics coalescing state
This commit is contained in:
parent
944ba23390
commit
f1b5660532
3 changed files with 14 additions and 10 deletions
|
|
@ -9,7 +9,6 @@ import (
|
|||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/model"
|
||||
"github.com/navidrome/navidrome/plugins/capabilities"
|
||||
"golang.org/x/sync/singleflight"
|
||||
)
|
||||
|
||||
const CapabilityLyrics Capability = "Lyrics"
|
||||
|
|
@ -41,7 +40,6 @@ func newLyricsPlugin(p *plugin) *LyricsPlugin {
|
|||
type LyricsPlugin struct {
|
||||
name string
|
||||
plugin *plugin
|
||||
calls singleflight.Group
|
||||
}
|
||||
|
||||
// GetLyrics coalesces concurrent lookups for the same track. The shared call is
|
||||
|
|
@ -60,7 +58,7 @@ func (l *LyricsPlugin) GetLyrics(ctx context.Context, mf *model.MediaFile) (mode
|
|||
return nil, err
|
||||
}
|
||||
|
||||
result := l.calls.DoChan(key, func() (any, error) {
|
||||
result := l.plugin.lyricsCalls.DoChan(key, func() (any, error) {
|
||||
callCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), lyricsPluginCallTimeout)
|
||||
defer cancel()
|
||||
return l.getLyrics(callCtx, mf, req)
|
||||
|
|
|
|||
|
|
@ -66,11 +66,15 @@ var _ = Describe("LyricsPlugin", Ordered, func() {
|
|||
"test-lyrics"+PackageExtension,
|
||||
)
|
||||
|
||||
p, ok := manager.LoadLyricsProvider("test-lyrics")
|
||||
first, ok := manager.LoadLyricsProvider("test-lyrics")
|
||||
Expect(ok).To(BeTrue())
|
||||
coalescingProvider := p.(*LyricsPlugin)
|
||||
second, ok := manager.LoadLyricsProvider("test-lyrics")
|
||||
Expect(ok).To(BeTrue())
|
||||
firstProvider := first.(*LyricsPlugin)
|
||||
secondProvider := second.(*LyricsPlugin)
|
||||
Expect(firstProvider).ToNot(BeIdenticalTo(secondProvider))
|
||||
|
||||
sem := coalescingProvider.plugin.lyricsSem
|
||||
sem := firstProvider.plugin.lyricsSem
|
||||
for range cap(sem) {
|
||||
sem <- struct{}{}
|
||||
}
|
||||
|
|
@ -87,10 +91,10 @@ var _ = Describe("LyricsPlugin", Ordered, func() {
|
|||
start := make(chan struct{})
|
||||
results := make(chan callResult, 2)
|
||||
track := &model.MediaFile{ID: "shared-track", Title: "Test Song", Artist: "Test Artist"}
|
||||
for range 2 {
|
||||
for _, provider := range []*LyricsPlugin{firstProvider, secondProvider} {
|
||||
go func() {
|
||||
<-start
|
||||
lyrics, err := coalescingProvider.GetLyrics(GinkgoT().Context(), track)
|
||||
lyrics, err := provider.GetLyrics(GinkgoT().Context(), track)
|
||||
results <- callResult{lyrics: lyrics, err: err}
|
||||
}()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
extism "github.com/extism/go-sdk"
|
||||
"github.com/navidrome/navidrome/model"
|
||||
"github.com/tetratelabs/wazero"
|
||||
"golang.org/x/sync/singleflight"
|
||||
)
|
||||
|
||||
// plugin represents a loaded plugin
|
||||
|
|
@ -24,8 +25,9 @@ type plugin struct {
|
|||
allowedUserIDs []string // User IDs this plugin can access (from DB configuration)
|
||||
allUsers bool // If true, plugin can access all users
|
||||
libraries libraryAccess
|
||||
lyricsSem chan struct{} // Caps concurrent lyrics calls (see LyricsPlugin.GetLyrics)
|
||||
fsConfig wazero.FSConfig // Sandboxed library mounts, nil if no filesystem permission
|
||||
lyricsSem chan struct{} // Caps concurrent lyrics calls (see LyricsPlugin.GetLyrics)
|
||||
lyricsCalls singleflight.Group // Shared by the transient LyricsPlugin adapters
|
||||
fsConfig wazero.FSConfig // Sandboxed library mounts, nil if no filesystem permission
|
||||
}
|
||||
|
||||
// instanceConfig is used by every call site, so all instances get the sandboxed mounts.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue