Make caches singletons

This commit is contained in:
Deluan 2020-10-27 17:02:20 -04:00
parent 515528ee6d
commit 9b756faef5
6 changed files with 53 additions and 45 deletions

View file

@ -26,7 +26,7 @@ func CreateServer(musicFolder string) *server.Server {
func CreateScanner(musicFolder string) scanner.Scanner { func CreateScanner(musicFolder string) scanner.Scanner {
dataStore := persistence.New() dataStore := persistence.New()
artworkCache := core.NewImageCache() artworkCache := core.GetImageCache()
artwork := core.NewArtwork(dataStore, artworkCache) artwork := core.NewArtwork(dataStore, artworkCache)
cacheWarmer := core.NewCacheWarmer(artwork) cacheWarmer := core.NewCacheWarmer(artwork)
scannerScanner := scanner.New(dataStore, cacheWarmer) scannerScanner := scanner.New(dataStore, cacheWarmer)
@ -41,10 +41,10 @@ func CreateAppRouter() *app.Router {
func CreateSubsonicAPIRouter() *subsonic.Router { func CreateSubsonicAPIRouter() *subsonic.Router {
dataStore := persistence.New() dataStore := persistence.New()
artworkCache := core.NewImageCache() artworkCache := core.GetImageCache()
artwork := core.NewArtwork(dataStore, artworkCache) artwork := core.NewArtwork(dataStore, artworkCache)
transcoderTranscoder := transcoder.New() transcoderTranscoder := transcoder.New()
transcodingCache := core.NewTranscodingCache() transcodingCache := core.GetTranscodingCache()
mediaStreamer := core.NewMediaStreamer(dataStore, transcoderTranscoder, transcodingCache) mediaStreamer := core.NewMediaStreamer(dataStore, transcoderTranscoder, transcodingCache)
archiver := core.NewArchiver(dataStore) archiver := core.NewArchiver(dataStore)
players := core.NewPlayers(dataStore) players := core.NewPlayers(dataStore)

View file

@ -12,6 +12,7 @@ import (
"io" "io"
"os" "os"
"strings" "strings"
"sync"
"time" "time"
"github.com/deluan/navidrome/core/cache" "github.com/deluan/navidrome/core/cache"
@ -205,15 +206,23 @@ func readFromFile(path string) ([]byte, error) {
return buf.Bytes(), nil return buf.Bytes(), nil
} }
func NewImageCache() ArtworkCache { var (
return cache.NewFileCache("Image", conf.Server.ImageCacheSize, consts.ImageCacheDir, consts.DefaultImageCacheMaxItems, onceImageCache sync.Once
func(ctx context.Context, arg cache.Item) (io.Reader, error) { instanceImageCache ArtworkCache
info := arg.(*imageInfo) )
reader, err := info.a.getArtwork(ctx, info.id, info.path, info.size)
if err != nil { func GetImageCache() ArtworkCache {
log.Error(ctx, "Error loading artwork art", "path", info.path, "size", info.size, err) onceImageCache.Do(func() {
return nil, err instanceImageCache = cache.NewFileCache("Image", conf.Server.ImageCacheSize, consts.ImageCacheDir, consts.DefaultImageCacheMaxItems,
} func(ctx context.Context, arg cache.Item) (io.Reader, error) {
return reader, nil info := arg.(*imageInfo)
}) reader, err := info.a.getArtwork(ctx, info.id, info.path, info.size)
if err != nil {
log.Error(ctx, "Error loading artwork art", "path", info.path, "size", info.size, err)
return nil, err
}
return reader, nil
})
})
return instanceImageCache
} }

View file

@ -5,7 +5,6 @@ import (
"context" "context"
"image" "image"
"io/ioutil" "io/ioutil"
"os"
"github.com/deluan/navidrome/conf" "github.com/deluan/navidrome/conf"
"github.com/deluan/navidrome/log" "github.com/deluan/navidrome/log"
@ -37,15 +36,11 @@ var _ = Describe("Artwork", func() {
BeforeEach(func() { BeforeEach(func() {
conf.Server.DataFolder, _ = ioutil.TempDir("", "file_caches") conf.Server.DataFolder, _ = ioutil.TempDir("", "file_caches")
conf.Server.ImageCacheSize = "100MB" conf.Server.ImageCacheSize = "100MB"
cache := NewImageCache() cache := GetImageCache()
Eventually(func() bool { return cache.Ready() }).Should(BeTrue()) Eventually(func() bool { return cache.Ready() }).Should(BeTrue())
artwork = NewArtwork(ds, cache) artwork = NewArtwork(ds, cache)
}) })
AfterEach(func() {
os.RemoveAll(conf.Server.DataFolder)
})
It("retrieves the external artwork art for an album", func() { It("retrieves the external artwork art for an album", func() {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)

View file

@ -6,6 +6,7 @@ import (
"io" "io"
"mime" "mime"
"os" "os"
"sync"
"time" "time"
"github.com/deluan/navidrome/conf" "github.com/deluan/navidrome/conf"
@ -167,21 +168,29 @@ func selectTranscodingOptions(ctx context.Context, ds model.DataStore, mf *model
return return
} }
func NewTranscodingCache() TranscodingCache { var (
return cache.NewFileCache("Transcoding", conf.Server.TranscodingCacheSize, onceTranscodingCache sync.Once
consts.TranscodingCacheDir, consts.DefaultTranscodingCacheMaxItems, instanceTranscodingCache TranscodingCache
func(ctx context.Context, arg cache.Item) (io.Reader, error) { )
job := arg.(*streamJob)
t, err := job.ms.ds.Transcoding(ctx).FindByFormat(job.format) func GetTranscodingCache() TranscodingCache {
if err != nil { onceTranscodingCache.Do(func() {
log.Error(ctx, "Error loading transcoding command", "format", job.format, err) instanceTranscodingCache = cache.NewFileCache("Transcoding", conf.Server.TranscodingCacheSize,
return nil, os.ErrInvalid consts.TranscodingCacheDir, consts.DefaultTranscodingCacheMaxItems,
} func(ctx context.Context, arg cache.Item) (io.Reader, error) {
out, err := job.ms.ffm.Start(ctx, t.Command, job.mf.Path, job.bitRate) job := arg.(*streamJob)
if err != nil { t, err := job.ms.ds.Transcoding(ctx).FindByFormat(job.format)
log.Error(ctx, "Error starting transcoder", "id", job.mf.ID, err) if err != nil {
return nil, os.ErrInvalid log.Error(ctx, "Error loading transcoding command", "format", job.format, err)
} return nil, os.ErrInvalid
return out, nil }
}) out, err := job.ms.ffm.Start(ctx, t.Command, job.mf.Path, job.bitRate)
if err != nil {
log.Error(ctx, "Error starting transcoder", "id", job.mf.ID, err)
return nil, os.ErrInvalid
}
return out, nil
})
})
return instanceTranscodingCache
} }

View file

@ -4,7 +4,6 @@ import (
"context" "context"
"io" "io"
"io/ioutil" "io/ioutil"
"os"
"strings" "strings"
"github.com/deluan/navidrome/conf" "github.com/deluan/navidrome/conf"
@ -29,15 +28,11 @@ var _ = Describe("MediaStreamer", func() {
ds.MediaFile(ctx).(*tests.MockMediaFile).SetData(model.MediaFiles{ ds.MediaFile(ctx).(*tests.MockMediaFile).SetData(model.MediaFiles{
{ID: "123", Path: "tests/fixtures/test.mp3", Suffix: "mp3", BitRate: 128, Duration: 257.0}, {ID: "123", Path: "tests/fixtures/test.mp3", Suffix: "mp3", BitRate: 128, Duration: 257.0},
}) })
testCache := NewTranscodingCache() testCache := GetTranscodingCache()
Eventually(func() bool { return testCache.Ready() }).Should(BeTrue()) Eventually(func() bool { return testCache.Ready() }).Should(BeTrue())
streamer = NewMediaStreamer(ds, ffmpeg, testCache) streamer = NewMediaStreamer(ds, ffmpeg, testCache)
}) })
AfterEach(func() {
os.RemoveAll(conf.Server.DataFolder)
})
Context("NewStream", func() { Context("NewStream", func() {
It("returns a seekable stream if format is 'raw'", func() { It("returns a seekable stream if format is 'raw'", func() {
s, err := streamer.NewStream(ctx, "123", "raw", 0) s, err := streamer.NewStream(ctx, "123", "raw", 0)

View file

@ -13,8 +13,8 @@ import (
var Set = wire.NewSet( var Set = wire.NewSet(
NewArtwork, NewArtwork,
NewMediaStreamer, NewMediaStreamer,
NewTranscodingCache, GetTranscodingCache,
NewImageCache, GetImageCache,
NewArchiver, NewArchiver,
NewNowPlayingRepository, NewNowPlayingRepository,
NewExternalInfo, NewExternalInfo,