diff --git a/engine/browser.go b/engine/browser.go index 123c7f24e..df551b1b1 100644 --- a/engine/browser.go +++ b/engine/browser.go @@ -32,11 +32,11 @@ type browser struct { } func (b *browser) MediaFolders(ctx context.Context) (model.MediaFolders, error) { - return b.ds.MediaFolder().GetAll() + return b.ds.MediaFolder(ctx).GetAll() } func (b *browser) Indexes(ctx context.Context, ifModifiedSince time.Time) (model.ArtistIndexes, time.Time, error) { - l, err := b.ds.Property().DefaultGet(model.PropLastScan, "-1") + l, err := b.ds.Property(ctx).DefaultGet(model.PropLastScan, "-1") ms, _ := strconv.ParseInt(l, 10, 64) lastModified := utils.ToTime(ms) @@ -45,7 +45,7 @@ func (b *browser) Indexes(ctx context.Context, ifModifiedSince time.Time) (model } if lastModified.After(ifModifiedSince) { - indexes, err := b.ds.Artist().GetIndex() + indexes, err := b.ds.Artist(ctx).GetIndex() return indexes, lastModified, err } @@ -72,7 +72,7 @@ type DirectoryInfo struct { } func (b *browser) Artist(ctx context.Context, id string) (*DirectoryInfo, error) { - a, albums, err := b.retrieveArtist(id) + a, albums, err := b.retrieveArtist(ctx, id) if err != nil { return nil, err } @@ -81,12 +81,12 @@ func (b *browser) Artist(ctx context.Context, id string) (*DirectoryInfo, error) for _, al := range albums { albumIds = append(albumIds, al.ID) } - annMap, err := b.ds.Annotation().GetMap(getUserID(ctx), model.AlbumItemType, albumIds) + annMap, err := b.ds.Annotation(ctx).GetMap(getUserID(ctx), model.AlbumItemType, albumIds) return b.buildArtistDir(a, albums, annMap), nil } func (b *browser) Album(ctx context.Context, id string) (*DirectoryInfo, error) { - al, tracks, err := b.retrieveAlbum(id) + al, tracks, err := b.retrieveAlbum(ctx, id) if err != nil { return nil, err } @@ -97,11 +97,11 @@ func (b *browser) Album(ctx context.Context, id string) (*DirectoryInfo, error) } userID := getUserID(ctx) - trackAnnMap, err := b.ds.Annotation().GetMap(userID, model.MediaItemType, mfIds) + trackAnnMap, err := b.ds.Annotation(ctx).GetMap(userID, model.MediaItemType, mfIds) if err != nil { return nil, err } - ann, err := b.ds.Annotation().Get(userID, model.AlbumItemType, al.ID) + ann, err := b.ds.Annotation(ctx).Get(userID, model.AlbumItemType, al.ID) if err != nil { return nil, err } @@ -121,13 +121,13 @@ func (b *browser) Directory(ctx context.Context, id string) (*DirectoryInfo, err } func (b *browser) GetSong(ctx context.Context, id string) (*Entry, error) { - mf, err := b.ds.MediaFile().Get(id) + mf, err := b.ds.MediaFile(ctx).Get(id) if err != nil { return nil, err } userId := getUserID(ctx) - ann, err := b.ds.Annotation().Get(userId, model.MediaItemType, id) + ann, err := b.ds.Annotation(ctx).Get(userId, model.MediaItemType, id) if err != nil { return nil, err } @@ -137,7 +137,7 @@ func (b *browser) GetSong(ctx context.Context, id string) (*Entry, error) { } func (b *browser) GetGenres(ctx context.Context) (model.Genres, error) { - genres, err := b.ds.Genre().GetAll() + genres, err := b.ds.Genre(ctx).GetAll() for i, g := range genres { if strings.TrimSpace(g.Name) == "" { genres[i].Name = "<Empty>" @@ -195,7 +195,7 @@ func (b *browser) buildAlbumDir(al *model.Album, albumAnn *model.Annotation, tra } func (b *browser) isArtist(ctx context.Context, id string) bool { - found, err := b.ds.Artist().Exists(id) + found, err := b.ds.Artist(ctx).Exists(id) if err != nil { log.Debug(ctx, "Error searching for Artist", "id", id, err) return false @@ -204,7 +204,7 @@ func (b *browser) isArtist(ctx context.Context, id string) bool { } func (b *browser) isAlbum(ctx context.Context, id string) bool { - found, err := b.ds.Album().Exists(id) + found, err := b.ds.Album(ctx).Exists(id) if err != nil { log.Debug(ctx, "Error searching for Album", "id", id, err) return false @@ -212,27 +212,27 @@ func (b *browser) isAlbum(ctx context.Context, id string) bool { return found } -func (b *browser) retrieveArtist(id string) (a *model.Artist, as model.Albums, err error) { - a, err = b.ds.Artist().Get(id) +func (b *browser) retrieveArtist(ctx context.Context, id string) (a *model.Artist, as model.Albums, err error) { + a, err = b.ds.Artist(ctx).Get(id) if err != nil { err = fmt.Errorf("Error reading Artist %s from DB: %v", id, err) return } - if as, err = b.ds.Album().FindByArtist(id); err != nil { + if as, err = b.ds.Album(ctx).FindByArtist(id); err != nil { err = fmt.Errorf("Error reading %s's albums from DB: %v", a.Name, err) } return } -func (b *browser) retrieveAlbum(id string) (al *model.Album, mfs model.MediaFiles, err error) { - al, err = b.ds.Album().Get(id) +func (b *browser) retrieveAlbum(ctx context.Context, id string) (al *model.Album, mfs model.MediaFiles, err error) { + al, err = b.ds.Album(ctx).Get(id) if err != nil { err = fmt.Errorf("Error reading Album %s from DB: %v", id, err) return } - if mfs, err = b.ds.MediaFile().FindByAlbum(id); err != nil { + if mfs, err = b.ds.MediaFile(ctx).FindByAlbum(id); err != nil { err = fmt.Errorf("Error reading %s's tracks from DB: %v", al.Name, err) } return diff --git a/engine/cover.go b/engine/cover.go index 4dd59d21f..ecc418759 100644 --- a/engine/cover.go +++ b/engine/cover.go @@ -31,17 +31,17 @@ func NewCover(ds model.DataStore) Cover { return &cover{ds} } -func (c *cover) getCoverPath(id string) (string, error) { +func (c *cover) getCoverPath(ctx context.Context, id string) (string, error) { switch { case strings.HasPrefix(id, "al-"): id = id[3:] - al, err := c.ds.Album().Get(id) + al, err := c.ds.Album(ctx).Get(id) if err != nil { return "", err } return al.CoverArtPath, nil default: - mf, err := c.ds.MediaFile().Get(id) + mf, err := c.ds.MediaFile(ctx).Get(id) if err != nil { return "", err } @@ -53,7 +53,7 @@ func (c *cover) getCoverPath(id string) (string, error) { } func (c *cover) Get(ctx context.Context, id string, size int, out io.Writer) error { - path, err := c.getCoverPath(id) + path, err := c.getCoverPath(ctx, id) if err != nil && err != model.ErrNotFound { return err } diff --git a/engine/cover_test.go b/engine/cover_test.go index 5253955b4..91caad922 100644 --- a/engine/cover_test.go +++ b/engine/cover_test.go @@ -17,8 +17,8 @@ func TestCover(t *testing.T) { Init(t, false) ds := &persistence.MockDataStore{} - mockMediaFileRepo := ds.MediaFile().(*persistence.MockMediaFile) - mockAlbumRepo := ds.Album().(*persistence.MockAlbum) + mockMediaFileRepo := ds.MediaFile(nil).(*persistence.MockMediaFile) + mockAlbumRepo := ds.Album(nil).(*persistence.MockAlbum) cover := engine.NewCover(ds) out := new(bytes.Buffer) diff --git a/engine/list_generator.go b/engine/list_generator.go index d83c060c6..69d424948 100644 --- a/engine/list_generator.go +++ b/engine/list_generator.go @@ -31,7 +31,7 @@ type listGenerator struct { } func (g *listGenerator) query(ctx context.Context, qo model.QueryOptions) (Entries, error) { - albums, err := g.ds.Album().GetAll(qo) + albums, err := g.ds.Album(ctx).GetAll(qo) if err != nil { return nil, err } @@ -39,7 +39,7 @@ func (g *listGenerator) query(ctx context.Context, qo model.QueryOptions) (Entri for i, al := range albums { albumIds[i] = al.ID } - annMap, err := g.ds.Annotation().GetMap(getUserID(ctx), model.AlbumItemType, albumIds) + annMap, err := g.ds.Annotation(ctx).GetMap(getUserID(ctx), model.AlbumItemType, albumIds) if err != nil { return nil, err } @@ -47,7 +47,7 @@ func (g *listGenerator) query(ctx context.Context, qo model.QueryOptions) (Entri } func (g *listGenerator) queryByAnnotation(ctx context.Context, qo model.QueryOptions) (Entries, error) { - annotations, err := g.ds.Annotation().GetAll(getUserID(ctx), model.AlbumItemType, qo) + annotations, err := g.ds.Annotation(ctx).GetAll(getUserID(ctx), model.AlbumItemType, qo) if err != nil { return nil, err } @@ -56,7 +56,7 @@ func (g *listGenerator) queryByAnnotation(ctx context.Context, qo model.QueryOpt albumIds[i] = ann.ItemID } - albumMap, err := g.ds.Album().GetMap(albumIds) + albumMap, err := g.ds.Album(ctx).GetMap(albumIds) if err != nil { return nil, err } @@ -103,7 +103,7 @@ func (g *listGenerator) GetByArtist(ctx context.Context, offset int, size int) ( } func (g *listGenerator) GetRandom(ctx context.Context, offset int, size int) (Entries, error) { - albums, err := g.ds.Album().GetRandom(model.QueryOptions{Max: size, Offset: offset}) + albums, err := g.ds.Album(ctx).GetRandom(model.QueryOptions{Max: size, Offset: offset}) if err != nil { return nil, err } @@ -120,7 +120,7 @@ func (g *listGenerator) getAnnotationsForAlbums(ctx context.Context, albums mode for i, al := range albums { albumIds[i] = al.ID } - return g.ds.Annotation().GetMap(getUserID(ctx), model.AlbumItemType, albumIds) + return g.ds.Annotation(ctx).GetMap(getUserID(ctx), model.AlbumItemType, albumIds) } func (g *listGenerator) GetRandomSongs(ctx context.Context, size int, genre string) (Entries, error) { @@ -128,14 +128,14 @@ func (g *listGenerator) GetRandomSongs(ctx context.Context, size int, genre stri if genre != "" { options.Filters = map[string]interface{}{"genre": genre} } - mediaFiles, err := g.ds.MediaFile().GetRandom(options) + mediaFiles, err := g.ds.MediaFile(ctx).GetRandom(options) if err != nil { return nil, err } r := make(Entries, len(mediaFiles)) for i, mf := range mediaFiles { - ann, err := g.ds.Annotation().Get(getUserID(ctx), model.MediaItemType, mf.ID) + ann, err := g.ds.Annotation(ctx).Get(getUserID(ctx), model.MediaItemType, mf.ID) if err != nil { return nil, err } @@ -146,7 +146,7 @@ func (g *listGenerator) GetRandomSongs(ctx context.Context, size int, genre stri func (g *listGenerator) GetStarred(ctx context.Context, offset int, size int) (Entries, error) { qo := model.QueryOptions{Offset: offset, Max: size, Sort: "starred_at", Order: "desc"} - albums, err := g.ds.Album().GetStarred(getUserID(ctx), qo) + albums, err := g.ds.Album(ctx).GetStarred(getUserID(ctx), qo) if err != nil { return nil, err } @@ -161,17 +161,17 @@ func (g *listGenerator) GetStarred(ctx context.Context, offset int, size int) (E func (g *listGenerator) GetAllStarred(ctx context.Context) (artists Entries, albums Entries, mediaFiles Entries, err error) { options := model.QueryOptions{Sort: "starred_at", Order: "desc"} - ars, err := g.ds.Artist().GetStarred(getUserID(ctx), options) + ars, err := g.ds.Artist(ctx).GetStarred(getUserID(ctx), options) if err != nil { return nil, nil, nil, err } - als, err := g.ds.Album().GetStarred(getUserID(ctx), options) + als, err := g.ds.Album(ctx).GetStarred(getUserID(ctx), options) if err != nil { return nil, nil, nil, err } - mfs, err := g.ds.MediaFile().GetStarred(getUserID(ctx), options) + mfs, err := g.ds.MediaFile(ctx).GetStarred(getUserID(ctx), options) if err != nil { return nil, nil, nil, err } @@ -180,7 +180,7 @@ func (g *listGenerator) GetAllStarred(ctx context.Context) (artists Entries, alb for _, mf := range mfs { mfIds = append(mfIds, mf.ID) } - trackAnnMap, err := g.ds.Annotation().GetMap(getUserID(ctx), model.MediaItemType, mfIds) + trackAnnMap, err := g.ds.Annotation(ctx).GetMap(getUserID(ctx), model.MediaItemType, mfIds) if err != nil { return nil, nil, nil, err } @@ -194,7 +194,7 @@ func (g *listGenerator) GetAllStarred(ctx context.Context) (artists Entries, alb for _, ar := range ars { artistIds = append(artistIds, ar.ID) } - artistAnnMap, err := g.ds.Annotation().GetMap(getUserID(ctx), model.MediaItemType, artistIds) + artistAnnMap, err := g.ds.Annotation(ctx).GetMap(getUserID(ctx), model.MediaItemType, artistIds) if err != nil { return nil, nil, nil, err } @@ -213,11 +213,11 @@ func (g *listGenerator) GetNowPlaying(ctx context.Context) (Entries, error) { } entries := make(Entries, len(npInfo)) for i, np := range npInfo { - mf, err := g.ds.MediaFile().Get(np.TrackID) + mf, err := g.ds.MediaFile(ctx).Get(np.TrackID) if err != nil { return nil, err } - ann, err := g.ds.Annotation().Get(getUserID(ctx), model.MediaItemType, mf.ID) + ann, err := g.ds.Annotation(ctx).Get(getUserID(ctx), model.MediaItemType, mf.ID) entries[i] = FromMediaFile(mf, ann) entries[i].UserName = np.Username entries[i].MinutesAgo = int(time.Now().Sub(np.Start).Minutes()) diff --git a/engine/playlists.go b/engine/playlists.go index 1a5fb9091..d05323de2 100644 --- a/engine/playlists.go +++ b/engine/playlists.go @@ -30,7 +30,7 @@ func (p *playlists) Create(ctx context.Context, playlistId, name string, ids []s var err error // If playlistID is present, override tracks if playlistId != "" { - pls, err = p.ds.Playlist().Get(playlistId) + pls, err = p.ds.Playlist(ctx).Get(playlistId) if err != nil { return err } @@ -48,7 +48,7 @@ func (p *playlists) Create(ctx context.Context, playlistId, name string, ids []s pls.Tracks = append(pls.Tracks, model.MediaFile{ID: id}) } - return p.ds.Playlist().Put(pls) + return p.ds.Playlist(ctx).Put(pls) } func (p *playlists) getUser(ctx context.Context) string { @@ -61,7 +61,7 @@ func (p *playlists) getUser(ctx context.Context) string { } func (p *playlists) Delete(ctx context.Context, playlistId string) error { - pls, err := p.ds.Playlist().Get(playlistId) + pls, err := p.ds.Playlist(ctx).Get(playlistId) if err != nil { return err } @@ -70,11 +70,11 @@ func (p *playlists) Delete(ctx context.Context, playlistId string) error { if owner != pls.Owner { return model.ErrNotAuthorized } - return p.ds.Playlist().Delete(playlistId) + return p.ds.Playlist(nil).Delete(playlistId) } func (p *playlists) Update(ctx context.Context, playlistId string, name *string, idsToAdd []string, idxToRemove []int) error { - pls, err := p.ds.Playlist().Get(playlistId) + pls, err := p.ds.Playlist(ctx).Get(playlistId) owner := p.getUser(ctx) if owner != pls.Owner { @@ -100,11 +100,11 @@ func (p *playlists) Update(ctx context.Context, playlistId string, name *string, } pls.Tracks = newTracks - return p.ds.Playlist().Put(pls) + return p.ds.Playlist(ctx).Put(pls) } func (p *playlists) GetAll(ctx context.Context) (model.Playlists, error) { - return p.ds.Playlist().GetAll(model.QueryOptions{}) + return p.ds.Playlist(ctx).GetAll(model.QueryOptions{}) } type PlaylistInfo struct { @@ -119,7 +119,7 @@ type PlaylistInfo struct { } func (p *playlists) Get(ctx context.Context, id string) (*PlaylistInfo, error) { - pl, err := p.ds.Playlist().GetWithTracks(id) + pl, err := p.ds.Playlist(ctx).GetWithTracks(id) if err != nil { return nil, err } @@ -141,7 +141,7 @@ func (p *playlists) Get(ctx context.Context, id string) (*PlaylistInfo, error) { mfIds = append(mfIds, mf.ID) } - annMap, err := p.ds.Annotation().GetMap(getUserID(ctx), model.MediaItemType, mfIds) + annMap, err := p.ds.Annotation(ctx).GetMap(getUserID(ctx), model.MediaItemType, mfIds) for i, mf := range pl.Tracks { ann := annMap[mf.ID] diff --git a/engine/ratings.go b/engine/ratings.go index 4f968ef6e..a2702bfa8 100644 --- a/engine/ratings.go +++ b/engine/ratings.go @@ -21,14 +21,14 @@ type ratings struct { } func (r ratings) SetRating(ctx context.Context, id string, rating int) error { - exist, err := r.ds.Album().Exists(id) + exist, err := r.ds.Album(ctx).Exists(id) if err != nil { return err } if exist { - return r.ds.Annotation().SetRating(rating, getUserID(ctx), model.AlbumItemType, id) + return r.ds.Annotation(ctx).SetRating(rating, getUserID(ctx), model.AlbumItemType, id) } - return r.ds.Annotation().SetRating(rating, getUserID(ctx), model.MediaItemType, id) + return r.ds.Annotation(ctx).SetRating(rating, getUserID(ctx), model.MediaItemType, id) } func (r ratings) SetStar(ctx context.Context, star bool, ids ...string) error { @@ -40,29 +40,29 @@ func (r ratings) SetStar(ctx context.Context, star bool, ids ...string) error { return r.ds.WithTx(func(tx model.DataStore) error { for _, id := range ids { - exist, err := r.ds.Album().Exists(id) + exist, err := r.ds.Album(ctx).Exists(id) if err != nil { return err } if exist { - err = tx.Annotation().SetStar(star, userId, model.AlbumItemType, ids...) + err = tx.Annotation(ctx).SetStar(star, userId, model.AlbumItemType, ids...) if err != nil { return err } continue } - exist, err = r.ds.Artist().Exists(id) + exist, err = r.ds.Artist(ctx).Exists(id) if err != nil { return err } if exist { - err = tx.Annotation().SetStar(star, userId, model.ArtistItemType, ids...) + err = tx.Annotation(ctx).SetStar(star, userId, model.ArtistItemType, ids...) if err != nil { return err } continue } - err = tx.Annotation().SetStar(star, userId, model.MediaItemType, ids...) + err = tx.Annotation(ctx).SetStar(star, userId, model.MediaItemType, ids...) if err != nil { return err } diff --git a/engine/scrobbler.go b/engine/scrobbler.go index b65533b6f..d3d874365 100644 --- a/engine/scrobbler.go +++ b/engine/scrobbler.go @@ -29,15 +29,15 @@ func (s *scrobbler) Register(ctx context.Context, playerId int, trackId string, var mf *model.MediaFile var err error err = s.ds.WithTx(func(tx model.DataStore) error { - mf, err = s.ds.MediaFile().Get(trackId) + mf, err = s.ds.MediaFile(ctx).Get(trackId) if err != nil { return err } - err = s.ds.Annotation().IncPlayCount(userId, model.MediaItemType, trackId, playTime) + err = s.ds.Annotation(ctx).IncPlayCount(userId, model.MediaItemType, trackId, playTime) if err != nil { return err } - err = s.ds.Annotation().IncPlayCount(userId, model.AlbumItemType, mf.AlbumID, playTime) + err = s.ds.Annotation(ctx).IncPlayCount(userId, model.AlbumItemType, mf.AlbumID, playTime) return err }) return mf, err @@ -45,7 +45,7 @@ func (s *scrobbler) Register(ctx context.Context, playerId int, trackId string, // TODO Validate if NowPlaying still works after all refactorings func (s *scrobbler) NowPlaying(ctx context.Context, playerId int, playerName, trackId, username string) (*model.MediaFile, error) { - mf, err := s.ds.MediaFile().Get(trackId) + mf, err := s.ds.MediaFile(ctx).Get(trackId) if err != nil { return nil, err } diff --git a/engine/search.go b/engine/search.go index 6a913d456..8d7ae5e33 100644 --- a/engine/search.go +++ b/engine/search.go @@ -25,7 +25,7 @@ func NewSearch(ds model.DataStore) Search { func (s *search) SearchArtist(ctx context.Context, q string, offset int, size int) (Entries, error) { q = sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*"))) - artists, err := s.ds.Artist().Search(q, offset, size) + artists, err := s.ds.Artist(ctx).Search(q, offset, size) if len(artists) == 0 || err != nil { return nil, nil } @@ -34,7 +34,7 @@ func (s *search) SearchArtist(ctx context.Context, q string, offset int, size in for i, al := range artists { artistIds[i] = al.ID } - annMap, err := s.ds.Annotation().GetMap(getUserID(ctx), model.ArtistItemType, artistIds) + annMap, err := s.ds.Annotation(ctx).GetMap(getUserID(ctx), model.ArtistItemType, artistIds) if err != nil { return nil, nil } @@ -44,7 +44,7 @@ func (s *search) SearchArtist(ctx context.Context, q string, offset int, size in func (s *search) SearchAlbum(ctx context.Context, q string, offset int, size int) (Entries, error) { q = sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*"))) - albums, err := s.ds.Album().Search(q, offset, size) + albums, err := s.ds.Album(ctx).Search(q, offset, size) if len(albums) == 0 || err != nil { return nil, nil } @@ -53,7 +53,7 @@ func (s *search) SearchAlbum(ctx context.Context, q string, offset int, size int for i, al := range albums { albumIds[i] = al.ID } - annMap, err := s.ds.Annotation().GetMap(getUserID(ctx), model.AlbumItemType, albumIds) + annMap, err := s.ds.Annotation(ctx).GetMap(getUserID(ctx), model.AlbumItemType, albumIds) if err != nil { return nil, nil } @@ -63,7 +63,7 @@ func (s *search) SearchAlbum(ctx context.Context, q string, offset int, size int func (s *search) SearchSong(ctx context.Context, q string, offset int, size int) (Entries, error) { q = sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*"))) - mediaFiles, err := s.ds.MediaFile().Search(q, offset, size) + mediaFiles, err := s.ds.MediaFile(ctx).Search(q, offset, size) if len(mediaFiles) == 0 || err != nil { return nil, nil } @@ -72,7 +72,7 @@ func (s *search) SearchSong(ctx context.Context, q string, offset int, size int) for i, mf := range mediaFiles { trackIds[i] = mf.ID } - annMap, err := s.ds.Annotation().GetMap(getUserID(ctx), model.MediaItemType, trackIds) + annMap, err := s.ds.Annotation(ctx).GetMap(getUserID(ctx), model.MediaItemType, trackIds) if err != nil { return nil, nil } diff --git a/engine/users.go b/engine/users.go index 120d90751..fde6fd04b 100644 --- a/engine/users.go +++ b/engine/users.go @@ -24,7 +24,7 @@ type users struct { } func (u *users) Authenticate(ctx context.Context, username, pass, token, salt string) (*model.User, error) { - user, err := u.ds.User().FindByUsername(username) + user, err := u.ds.User(ctx).FindByUsername(username) if err == model.ErrNotFound { return nil, model.ErrInvalidAuth } @@ -50,7 +50,7 @@ func (u *users) Authenticate(ctx context.Context, username, pass, token, salt st return nil, model.ErrInvalidAuth } go func() { - err := u.ds.User().UpdateLastAccessAt(user.ID) + err := u.ds.User(ctx).UpdateLastAccessAt(user.ID) if err != nil { log.Error(ctx, "Could not update user's lastAccessAt", "user", user.UserName) } diff --git a/model/datastore.go b/model/datastore.go index 493a8cb69..61f1ce862 100644 --- a/model/datastore.go +++ b/model/datastore.go @@ -1,6 +1,8 @@ package model import ( + "context" + "github.com/deluan/rest" ) @@ -22,17 +24,17 @@ type ResourceRepository interface { } type DataStore interface { - Album() AlbumRepository - Artist() ArtistRepository - MediaFile() MediaFileRepository - MediaFolder() MediaFolderRepository - Genre() GenreRepository - Playlist() PlaylistRepository - Property() PropertyRepository - User() UserRepository - Annotation() AnnotationRepository + Album(ctx context.Context) AlbumRepository + Artist(ctx context.Context) ArtistRepository + MediaFile(ctx context.Context) MediaFileRepository + MediaFolder(ctx context.Context) MediaFolderRepository + Genre(ctx context.Context) GenreRepository + Playlist(ctx context.Context) PlaylistRepository + Property(ctx context.Context) PropertyRepository + User(ctx context.Context) UserRepository + Annotation(ctx context.Context) AnnotationRepository - Resource(model interface{}) ResourceRepository + Resource(ctx context.Context, model interface{}) ResourceRepository WithTx(func(tx DataStore) error) error } diff --git a/persistence/mock_persistence.go b/persistence/mock_persistence.go index ab268cbb1..ac021a526 100644 --- a/persistence/mock_persistence.go +++ b/persistence/mock_persistence.go @@ -1,6 +1,10 @@ package persistence -import "github.com/deluan/navidrome/model" +import ( + "context" + + "github.com/deluan/navidrome/model" +) type MockDataStore struct { MockedGenre model.GenreRepository @@ -10,54 +14,54 @@ type MockDataStore struct { MockedUser model.UserRepository } -func (db *MockDataStore) Album() model.AlbumRepository { +func (db *MockDataStore) Album(context.Context) model.AlbumRepository { if db.MockedAlbum == nil { db.MockedAlbum = CreateMockAlbumRepo() } return db.MockedAlbum } -func (db *MockDataStore) Artist() model.ArtistRepository { +func (db *MockDataStore) Artist(context.Context) model.ArtistRepository { if db.MockedArtist == nil { db.MockedArtist = CreateMockArtistRepo() } return db.MockedArtist } -func (db *MockDataStore) MediaFile() model.MediaFileRepository { +func (db *MockDataStore) MediaFile(context.Context) model.MediaFileRepository { if db.MockedMediaFile == nil { db.MockedMediaFile = CreateMockMediaFileRepo() } return db.MockedMediaFile } -func (db *MockDataStore) MediaFolder() model.MediaFolderRepository { +func (db *MockDataStore) MediaFolder(context.Context) model.MediaFolderRepository { return struct{ model.MediaFolderRepository }{} } -func (db *MockDataStore) Genre() model.GenreRepository { +func (db *MockDataStore) Genre(context.Context) model.GenreRepository { if db.MockedGenre != nil { return db.MockedGenre } return struct{ model.GenreRepository }{} } -func (db *MockDataStore) Playlist() model.PlaylistRepository { +func (db *MockDataStore) Playlist(context.Context) model.PlaylistRepository { return struct{ model.PlaylistRepository }{} } -func (db *MockDataStore) Property() model.PropertyRepository { +func (db *MockDataStore) Property(context.Context) model.PropertyRepository { return struct{ model.PropertyRepository }{} } -func (db *MockDataStore) User() model.UserRepository { +func (db *MockDataStore) User(context.Context) model.UserRepository { if db.MockedUser == nil { db.MockedUser = &mockedUserRepo{} } return db.MockedUser } -func (db *MockDataStore) Annotation() model.AnnotationRepository { +func (db *MockDataStore) Annotation(context.Context) model.AnnotationRepository { return struct{ model.AnnotationRepository }{} } @@ -65,7 +69,7 @@ func (db *MockDataStore) WithTx(block func(db model.DataStore) error) error { return block(db) } -func (db *MockDataStore) Resource(m interface{}) model.ResourceRepository { +func (db *MockDataStore) Resource(ctx context.Context, m interface{}) model.ResourceRepository { return struct{ model.ResourceRepository }{} } diff --git a/persistence/persistence.go b/persistence/persistence.go index f53728214..1b19a9113 100644 --- a/persistence/persistence.go +++ b/persistence/persistence.go @@ -1,6 +1,7 @@ package persistence import ( + "context" "reflect" "strings" "sync" @@ -41,43 +42,43 @@ func New() model.DataStore { return &SQLStore{} } -func (db *SQLStore) Album() model.AlbumRepository { +func (db *SQLStore) Album(context.Context) model.AlbumRepository { return NewAlbumRepository(db.getOrmer()) } -func (db *SQLStore) Artist() model.ArtistRepository { +func (db *SQLStore) Artist(context.Context) model.ArtistRepository { return NewArtistRepository(db.getOrmer()) } -func (db *SQLStore) MediaFile() model.MediaFileRepository { +func (db *SQLStore) MediaFile(context.Context) model.MediaFileRepository { return NewMediaFileRepository(db.getOrmer()) } -func (db *SQLStore) MediaFolder() model.MediaFolderRepository { +func (db *SQLStore) MediaFolder(context.Context) model.MediaFolderRepository { return NewMediaFolderRepository(db.getOrmer()) } -func (db *SQLStore) Genre() model.GenreRepository { +func (db *SQLStore) Genre(context.Context) model.GenreRepository { return NewGenreRepository(db.getOrmer()) } -func (db *SQLStore) Playlist() model.PlaylistRepository { +func (db *SQLStore) Playlist(context.Context) model.PlaylistRepository { return NewPlaylistRepository(db.getOrmer()) } -func (db *SQLStore) Property() model.PropertyRepository { +func (db *SQLStore) Property(context.Context) model.PropertyRepository { return NewPropertyRepository(db.getOrmer()) } -func (db *SQLStore) User() model.UserRepository { +func (db *SQLStore) User(context.Context) model.UserRepository { return NewUserRepository(db.getOrmer()) } -func (db *SQLStore) Annotation() model.AnnotationRepository { +func (db *SQLStore) Annotation(context.Context) model.AnnotationRepository { return NewAnnotationRepository(db.getOrmer()) } -func (db *SQLStore) Resource(model interface{}) model.ResourceRepository { +func (db *SQLStore) Resource(ctx context.Context, model interface{}) model.ResourceRepository { return NewResource(db.getOrmer(), model, getMappedModel(model)) } diff --git a/persistence/persistence_suite_test.go b/persistence/persistence_suite_test.go index d4f50b7a1..cd3dd10a6 100644 --- a/persistence/persistence_suite_test.go +++ b/persistence/persistence_suite_test.go @@ -63,21 +63,21 @@ var _ = Describe("Initialize test DB", func() { BeforeSuite(func() { conf.Server.DbPath = ":memory:" ds := New() - artistRepo := ds.Artist() + artistRepo := ds.Artist(nil) for _, a := range testArtists { err := artistRepo.Put(&a) if err != nil { panic(err) } } - albumRepository := ds.Album() + albumRepository := ds.Album(nil) for _, a := range testAlbums { err := albumRepository.Put(&a) if err != nil { panic(err) } } - mediaFileRepository := ds.MediaFile() + mediaFileRepository := ds.MediaFile(nil) for _, s := range testSongs { err := mediaFileRepository.Put(&s) if err != nil { diff --git a/scanner/scanner.go b/scanner/scanner.go index 7c03e9b10..5b1d8212e 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -60,7 +60,7 @@ func (s *Scanner) RescanAll(fullRescan bool) error { func (s *Scanner) Status() []StatusInfo { return nil } func (s *Scanner) getLastModifiedSince(folder string) time.Time { - ms, err := s.ds.Property().Get(model.PropLastScan + "-" + folder) + ms, err := s.ds.Property(nil).Get(model.PropLastScan + "-" + folder) if err != nil { return time.Time{} } @@ -73,11 +73,11 @@ func (s *Scanner) getLastModifiedSince(folder string) time.Time { func (s *Scanner) updateLastModifiedSince(folder string, t time.Time) { millis := t.UnixNano() / int64(time.Millisecond) - s.ds.Property().Put(model.PropLastScan+"-"+folder, fmt.Sprint(millis)) + s.ds.Property(nil).Put(model.PropLastScan+"-"+folder, fmt.Sprint(millis)) } func (s *Scanner) loadFolders() { - fs, _ := s.ds.MediaFolder().GetAll() + fs, _ := s.ds.MediaFolder(nil).GetAll() for _, f := range fs { log.Info("Configuring Media Folder", "name", f.Name, "path", f.Path) s.folders[f.Path] = NewTagScanner(f.Path, s.ds) diff --git a/scanner/tag_scanner.go b/scanner/tag_scanner.go index 2fb053f33..60f6621f1 100644 --- a/scanner/tag_scanner.go +++ b/scanner/tag_scanner.go @@ -58,16 +58,16 @@ func (s *TagScanner) Scan(ctx context.Context, lastModifiedSince time.Time) erro updatedAlbums := map[string]bool{} for _, c := range changed { - err := s.processChangedDir(c, updatedArtists, updatedAlbums) + err := s.processChangedDir(ctx, c, updatedArtists, updatedAlbums) if err != nil { return err } if len(updatedAlbums)+len(updatedArtists) > 100 { - err = s.refreshAlbums(updatedAlbums) + err = s.refreshAlbums(ctx, updatedAlbums) if err != nil { return err } - err = s.refreshArtists(updatedArtists) + err = s.refreshArtists(ctx, updatedArtists) if err != nil { return err } @@ -76,16 +76,16 @@ func (s *TagScanner) Scan(ctx context.Context, lastModifiedSince time.Time) erro } } for _, c := range deleted { - err := s.processDeletedDir(c, updatedArtists, updatedAlbums) + err := s.processDeletedDir(ctx, c, updatedArtists, updatedAlbums) if err != nil { return err } if len(updatedAlbums)+len(updatedArtists) > 100 { - err = s.refreshAlbums(updatedAlbums) + err = s.refreshAlbums(ctx, updatedAlbums) if err != nil { return err } - err = s.refreshArtists(updatedArtists) + err = s.refreshArtists(ctx, updatedArtists) if err != nil { return err } @@ -94,22 +94,22 @@ func (s *TagScanner) Scan(ctx context.Context, lastModifiedSince time.Time) erro } } - err = s.refreshAlbums(updatedAlbums) + err = s.refreshAlbums(ctx, updatedAlbums) if err != nil { return err } - err = s.refreshArtists(updatedArtists) + err = s.refreshArtists(ctx, updatedArtists) if err != nil { return err } - err = s.ds.Album().PurgeEmpty() + err = s.ds.Album(ctx).PurgeEmpty() if err != nil { return err } - err = s.ds.Artist().PurgeEmpty() + err = s.ds.Artist(ctx).PurgeEmpty() if err != nil { return err } @@ -117,30 +117,30 @@ func (s *TagScanner) Scan(ctx context.Context, lastModifiedSince time.Time) erro return nil } -func (s *TagScanner) refreshAlbums(updatedAlbums map[string]bool) error { +func (s *TagScanner) refreshAlbums(ctx context.Context, updatedAlbums map[string]bool) error { var ids []string for id := range updatedAlbums { ids = append(ids, id) } - return s.ds.Album().Refresh(ids...) + return s.ds.Album(ctx).Refresh(ids...) } -func (s *TagScanner) refreshArtists(updatedArtists map[string]bool) error { +func (s *TagScanner) refreshArtists(ctx context.Context, updatedArtists map[string]bool) error { var ids []string for id := range updatedArtists { ids = append(ids, id) } - return s.ds.Artist().Refresh(ids...) + return s.ds.Artist(ctx).Refresh(ids...) } -func (s *TagScanner) processChangedDir(dir string, updatedArtists map[string]bool, updatedAlbums map[string]bool) error { +func (s *TagScanner) processChangedDir(ctx context.Context, dir string, updatedArtists map[string]bool, updatedAlbums map[string]bool) error { dir = path.Join(s.rootFolder, dir) start := time.Now() // Load folder's current tracks from DB into a map currentTracks := map[string]model.MediaFile{} - ct, err := s.ds.MediaFile().FindByPath(dir) + ct, err := s.ds.MediaFile(ctx).FindByPath(dir) if err != nil { return err } @@ -168,7 +168,7 @@ func (s *TagScanner) processChangedDir(dir string, updatedArtists map[string]boo for _, n := range newTracks { c, ok := currentTracks[n.ID] if !ok || (ok && n.UpdatedAt.After(c.UpdatedAt)) { - err := s.ds.MediaFile().Put(&n) + err := s.ds.MediaFile(ctx).Put(&n) updatedArtists[n.ArtistID] = true updatedAlbums[n.AlbumID] = true numUpdatedTracks++ @@ -182,7 +182,7 @@ func (s *TagScanner) processChangedDir(dir string, updatedArtists map[string]boo // Remaining tracks from DB that are not in the folder are deleted for id := range currentTracks { numPurgedTracks++ - if err := s.ds.MediaFile().Delete(id); err != nil { + if err := s.ds.MediaFile(ctx).Delete(id); err != nil { return err } } @@ -191,10 +191,10 @@ func (s *TagScanner) processChangedDir(dir string, updatedArtists map[string]boo return nil } -func (s *TagScanner) processDeletedDir(dir string, updatedArtists map[string]bool, updatedAlbums map[string]bool) error { +func (s *TagScanner) processDeletedDir(ctx context.Context, dir string, updatedArtists map[string]bool, updatedAlbums map[string]bool) error { dir = path.Join(s.rootFolder, dir) - ct, err := s.ds.MediaFile().FindByPath(dir) + ct, err := s.ds.MediaFile(ctx).FindByPath(dir) if err != nil { return err } @@ -203,7 +203,7 @@ func (s *TagScanner) processDeletedDir(dir string, updatedArtists map[string]boo updatedAlbums[t.AlbumID] = true } - return s.ds.MediaFile().DeleteByPath(dir) + return s.ds.MediaFile(ctx).DeleteByPath(dir) } func (s *TagScanner) loadTracks(dirPath string) (model.MediaFiles, error) { diff --git a/server/app/app.go b/server/app/app.go index fe9f49114..1ed9eb4e6 100644 --- a/server/app/app.go +++ b/server/app/app.go @@ -64,7 +64,7 @@ func (app *Router) routes() http.Handler { func (app *Router) R(r chi.Router, pathPrefix string, model interface{}) { constructor := func(ctx context.Context) rest.Repository { - return app.ds.Resource(model) + return app.ds.Resource(ctx, model) } r.Route(pathPrefix, func(r chi.Router) { r.Get("/", rest.GetAll(constructor)) diff --git a/server/app/auth.go b/server/app/auth.go index c70a93c24..4a9f53585 100644 --- a/server/app/auth.go +++ b/server/app/auth.go @@ -41,7 +41,7 @@ func Login(ds model.DataStore) func(w http.ResponseWriter, r *http.Request) { } func handleLogin(ds model.DataStore, username string, password string, w http.ResponseWriter, r *http.Request) { - user, err := validateLogin(ds.User(), username, password) + user, err := validateLogin(ds.User(r.Context()), username, password) if err != nil { rest.RespondWithError(w, http.StatusInternalServerError, "Unknown error authentication user. Please try again") return @@ -89,7 +89,7 @@ func CreateAdmin(ds model.DataStore) func(w http.ResponseWriter, r *http.Request rest.RespondWithError(w, http.StatusUnprocessableEntity, err.Error()) return } - c, err := ds.User().CountAll() + c, err := ds.User(r.Context()).CountAll() if err != nil { rest.RespondWithError(w, http.StatusInternalServerError, err.Error()) return @@ -98,7 +98,7 @@ func CreateAdmin(ds model.DataStore) func(w http.ResponseWriter, r *http.Request rest.RespondWithError(w, http.StatusForbidden, "Cannot create another first admin") return } - err = createDefaultUser(ds, username, password) + err = createDefaultUser(r.Context(), ds, username, password) if err != nil { rest.RespondWithError(w, http.StatusInternalServerError, err.Error()) return @@ -107,7 +107,7 @@ func CreateAdmin(ds model.DataStore) func(w http.ResponseWriter, r *http.Request } } -func createDefaultUser(ds model.DataStore, username, password string) error { +func createDefaultUser(ctx context.Context, ds model.DataStore, username, password string) error { id, _ := uuid.NewRandom() log.Warn("Creating initial user", "user", consts.InitialUserName) initialUser := model.User{ @@ -118,7 +118,7 @@ func createDefaultUser(ds model.DataStore, username, password string) error { Password: password, IsAdmin: true, } - err := ds.User().Put(&initialUser) + err := ds.User(ctx).Put(&initialUser) if err != nil { log.Error("Could not create initial user", "user", initialUser, err) } @@ -127,7 +127,7 @@ func createDefaultUser(ds model.DataStore, username, password string) error { func initTokenAuth(ds model.DataStore) { once.Do(func() { - secret, err := ds.Property().DefaultGet(consts.JWTSecretKey, "not so secret") + secret, err := ds.Property(nil).DefaultGet(consts.JWTSecretKey, "not so secret") if err != nil { log.Error("No JWT secret found in DB. Setting a temp one, but please report this error", err) } @@ -190,7 +190,7 @@ func getToken(ds model.DataStore, ctx context.Context) (*jwt.Token, error) { return token, nil } - c, err := ds.User().CountAll() + c, err := ds.User(ctx).CountAll() firstTime := c == 0 && err == nil if firstTime { return nil, ErrFirstTime diff --git a/server/initial_setup.go b/server/initial_setup.go index d1b47aa0a..437859871 100644 --- a/server/initial_setup.go +++ b/server/initial_setup.go @@ -11,7 +11,7 @@ import ( func initialSetup(ds model.DataStore) { _ = ds.WithTx(func(tx model.DataStore) error { - _, err := ds.Property().Get(consts.InitialSetupFlagKey) + _, err := ds.Property(nil).Get(consts.InitialSetupFlagKey) if err == nil { return nil } @@ -20,19 +20,19 @@ func initialSetup(ds model.DataStore) { return err } - err = ds.Property().Put(consts.InitialSetupFlagKey, time.Now().String()) + err = ds.Property(nil).Put(consts.InitialSetupFlagKey, time.Now().String()) return err }) } func createJWTSecret(ds model.DataStore) error { - _, err := ds.Property().Get(consts.JWTSecretKey) + _, err := ds.Property(nil).Get(consts.JWTSecretKey) if err == nil { return nil } jwtSecret, _ := uuid.NewRandom() log.Warn("Creating JWT secret, used for encrypting UI sessions") - err = ds.Property().Put(consts.JWTSecretKey, jwtSecret.String()) + err = ds.Property(nil).Put(consts.JWTSecretKey, jwtSecret.String()) if err != nil { log.Error("Could not save JWT secret in DB", err) }