diff --git a/api/wire_gen.go b/api/wire_gen.go index e81d31a03..0da14e251 100644 --- a/api/wire_gen.go +++ b/api/wire_gen.go @@ -38,7 +38,7 @@ func initBrowsingController() *BrowsingController { func initAlbumListController() *AlbumListController { albumRepository := db_storm.NewAlbumRepository() mediaFileRepository := db_storm.NewMediaFileRepository() - nowPlayingRepository := db_ledis.NewNowPlayingRepository() + nowPlayingRepository := persistence.NewNowPlayingRepository() listGenerator := engine.NewListGenerator(albumRepository, mediaFileRepository, nowPlayingRepository) albumListController := NewAlbumListController(listGenerator) return albumListController @@ -47,7 +47,7 @@ func initAlbumListController() *AlbumListController { func initMediaAnnotationController() *MediaAnnotationController { itunesControl := itunesbridge.NewItunesControl() mediaFileRepository := db_storm.NewMediaFileRepository() - nowPlayingRepository := db_ledis.NewNowPlayingRepository() + nowPlayingRepository := persistence.NewNowPlayingRepository() scrobbler := engine.NewScrobbler(itunesControl, mediaFileRepository, nowPlayingRepository) albumRepository := db_storm.NewAlbumRepository() artistRepository := db_storm.NewArtistRepository() @@ -96,7 +96,7 @@ func initStreamController() *StreamController { // wire_injectors.go: -var allProviders = wire.NewSet(itunesbridge.NewItunesControl, db_ledis.Set, db_storm.Set, engine.Set, NewSystemController, +var allProviders = wire.NewSet(itunesbridge.NewItunesControl, db_storm.Set, engine.Set, NewSystemController, NewBrowsingController, NewAlbumListController, NewMediaAnnotationController, diff --git a/api/wire_injectors.go b/api/wire_injectors.go index 89841bf94..9a7d00ecc 100644 --- a/api/wire_injectors.go +++ b/api/wire_injectors.go @@ -14,7 +14,7 @@ import ( var allProviders = wire.NewSet( itunesbridge.NewItunesControl, - db_ledis.Set, + //db_ledis.Set, db_storm.Set, engine.Set, NewSystemController, diff --git a/domain/nowplaying.go b/domain/nowplaying.go index c0e2481ee..1122ab4e7 100644 --- a/domain/nowplaying.go +++ b/domain/nowplaying.go @@ -29,6 +29,6 @@ type NowPlayingRepository interface { // Size of the queue for the playerId Count(playerId int) (int64, error) - // Returns all tails from all playerIds + // Returns all heads from all playerIds GetAll() ([]*NowPlayingInfo, error) } diff --git a/persistence/db_ledis/wire_providers.go b/persistence/db_ledis/wire_providers.go index 59f66ea5e..4353dfd66 100644 --- a/persistence/db_ledis/wire_providers.go +++ b/persistence/db_ledis/wire_providers.go @@ -1,9 +1,18 @@ package db_ledis import ( + "github.com/cloudsonic/sonic-server/persistence" "github.com/google/wire" ) var Set = wire.NewSet( + NewPropertyRepository, + NewArtistRepository, + NewAlbumRepository, + NewMediaFileRepository, + NewArtistIndexRepository, + NewPlaylistRepository, + NewCheckSumRepository, NewNowPlayingRepository, + persistence.NewMediaFolderRepository, ) diff --git a/persistence/db_storm/wire_providers.go b/persistence/db_storm/wire_providers.go index fa5f63b63..09ae7de3b 100644 --- a/persistence/db_storm/wire_providers.go +++ b/persistence/db_storm/wire_providers.go @@ -13,5 +13,6 @@ var Set = wire.NewSet( NewArtistIndexRepository, NewPlaylistRepository, NewCheckSumRepository, + persistence.NewNowPlayingRepository, persistence.NewMediaFolderRepository, ) diff --git a/persistence/nowplaying_repository.go b/persistence/nowplaying_repository.go new file mode 100644 index 000000000..54fe9ecf4 --- /dev/null +++ b/persistence/nowplaying_repository.go @@ -0,0 +1,75 @@ +package persistence + +import ( + "container/list" + "sync" + + "github.com/cloudsonic/sonic-server/domain" +) + +var playerMap = sync.Map{} + +type nowPlayingRepository struct{} + +// TODO Make it persistent +func NewNowPlayingRepository() domain.NowPlayingRepository { + r := &nowPlayingRepository{} + return r +} + +func (r *nowPlayingRepository) getList(id int) *list.List { + l, _ := playerMap.LoadOrStore(id, list.New()) + return l.(*list.List) +} + +func (r *nowPlayingRepository) Enqueue(info *domain.NowPlayingInfo) error { + l := r.getList(info.PlayerId) + l.PushFront(info) + return nil +} + +func (r *nowPlayingRepository) Dequeue(playerId int) (*domain.NowPlayingInfo, error) { + l := r.getList(playerId) + e := l.Back() + if e == nil { + return nil, nil + } + l.Remove(e) + return e.Value.(*domain.NowPlayingInfo), nil +} + +func (r *nowPlayingRepository) Head(playerId int) (*domain.NowPlayingInfo, error) { + l := r.getList(playerId) + e := l.Front() + if e == nil { + return nil, nil + } + return e.Value.(*domain.NowPlayingInfo), nil +} + +func (r *nowPlayingRepository) Tail(playerId int) (*domain.NowPlayingInfo, error) { + l := r.getList(playerId) + e := l.Back() + if e == nil { + return nil, nil + } + return e.Value.(*domain.NowPlayingInfo), nil +} + +func (r *nowPlayingRepository) Count(playerId int) (int64, error) { + l := r.getList(playerId) + return int64(l.Len()), nil +} + +func (r *nowPlayingRepository) GetAll() ([]*domain.NowPlayingInfo, error) { + var all []*domain.NowPlayingInfo + playerMap.Range(func(playerId, l interface{}) bool { + ll := l.(*list.List) + e := ll.Front() + all = append(all, e.Value.(*domain.NowPlayingInfo)) + return true + }) + return all, nil +} + +var _ domain.NowPlayingRepository = (*nowPlayingRepository)(nil) diff --git a/persistence/nowplaying_repository_test.go b/persistence/nowplaying_repository_test.go new file mode 100644 index 000000000..0fc8010e7 --- /dev/null +++ b/persistence/nowplaying_repository_test.go @@ -0,0 +1,50 @@ +package persistence + +import ( + "sync" + + "github.com/cloudsonic/sonic-server/domain" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("NowPlayingRepository", func() { + var repo domain.NowPlayingRepository + + BeforeEach(func() { + playerMap = sync.Map{} + repo = NewNowPlayingRepository() + }) + + It("enqueues and dequeues records", func() { + Expect(repo.Enqueue(&domain.NowPlayingInfo{PlayerId: 1, TrackID: "AAA"})).To(BeNil()) + Expect(repo.Enqueue(&domain.NowPlayingInfo{PlayerId: 1, TrackID: "BBB"})).To(BeNil()) + + Expect(repo.Tail(1)).To(Equal(&domain.NowPlayingInfo{PlayerId: 1, TrackID: "AAA"})) + Expect(repo.Head(1)).To(Equal(&domain.NowPlayingInfo{PlayerId: 1, TrackID: "BBB"})) + + Expect(repo.Count(1)).To(Equal(int64(2))) + + Expect(repo.Dequeue(1)).To(Equal(&domain.NowPlayingInfo{PlayerId: 1, TrackID: "AAA"})) + Expect(repo.Count(1)).To(Equal(int64(1))) + }) + + It("handles multiple players", func() { + Expect(repo.Enqueue(&domain.NowPlayingInfo{PlayerId: 1, TrackID: "AAA"})).To(BeNil()) + Expect(repo.Enqueue(&domain.NowPlayingInfo{PlayerId: 1, TrackID: "BBB"})).To(BeNil()) + + Expect(repo.Enqueue(&domain.NowPlayingInfo{PlayerId: 2, TrackID: "CCC"})).To(BeNil()) + Expect(repo.Enqueue(&domain.NowPlayingInfo{PlayerId: 2, TrackID: "DDD"})).To(BeNil()) + + Expect(repo.GetAll()).To(Equal([]*domain.NowPlayingInfo{ + {PlayerId: 1, TrackID: "BBB"}, + {PlayerId: 2, TrackID: "DDD"}, + })) + + Expect(repo.Count(2)).To(Equal(int64(2))) + Expect(repo.Count(2)).To(Equal(int64(2))) + + Expect(repo.Tail(1)).To(Equal(&domain.NowPlayingInfo{PlayerId: 1, TrackID: "AAA"})) + Expect(repo.Head(2)).To(Equal(&domain.NowPlayingInfo{PlayerId: 2, TrackID: "DDD"})) + }) +}) diff --git a/persistence/persistence_suite_test.go b/persistence/persistence_suite_test.go new file mode 100644 index 000000000..586ae5f5c --- /dev/null +++ b/persistence/persistence_suite_test.go @@ -0,0 +1,14 @@ +package persistence + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestPersistence(t *testing.T) { + //log.SetLevel(log.LevelCritical) + RegisterFailHandler(Fail) + RunSpecs(t, "Common Persistence Suite") +} diff --git a/wire_gen.go b/wire_gen.go index 1bc39d869..13d7b9682 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -35,7 +35,7 @@ func initImporter(musicFolder string) *scanner.Importer { // wire_injectors.go: -var allProviders = wire.NewSet(itunesbridge.NewItunesControl, db_ledis.Set, db_storm.Set, engine.Set, scanner.Set, newDB) +var allProviders = wire.NewSet(itunesbridge.NewItunesControl, db_storm.Set, engine.Set, scanner.Set, newDB) func newDB() gomate.DB { return ledis.NewEmbeddedDB(db_ledis.Db()) diff --git a/wire_injectors.go b/wire_injectors.go index 8442a1727..771c6629e 100644 --- a/wire_injectors.go +++ b/wire_injectors.go @@ -15,7 +15,7 @@ import ( var allProviders = wire.NewSet( itunesbridge.NewItunesControl, - db_ledis.Set, + //db_ledis.Set, db_storm.Set, engine.Set, scanner.Set,