From daaa6b7f9779385979fe9dddae4e7bb388b3e5fb Mon Sep 17 00:00:00 2001 From: Caleb Allen Date: Sat, 28 Feb 2026 12:09:14 -0500 Subject: [PATCH] fix(01-01): add mutex protection to Queue, Library, and Playlist SetContext methods - Queue.SetContext acquires existing q.mu before writing q.ctx - Library struct gets new mu sync.Mutex; SetContext and SetRescanHooks acquire it - Playlist Service struct gets new mu sync.Mutex; SetContext and SetFavoritesConfig acquire it - Library and Playlist release lock before calling post-init methods (registerEventHandlers, migrateExistingPlaylists) --- backend/library/library.go | 9 +++++++++ backend/playlist/playlist.go | 10 ++++++++++ backend/queue/queue.go | 3 +++ 3 files changed, 22 insertions(+) diff --git a/backend/library/library.go b/backend/library/library.go index 5692da8..f30d4c4 100644 --- a/backend/library/library.go +++ b/backend/library/library.go @@ -76,6 +76,9 @@ type RescanHooks struct { // Library manages scanning and querying the music collection. type Library struct { + // mu protects ctx, conf, and rescanHooks from concurrent + // access during initialization. + mu sync.Mutex ctx context.Context logger *slog.Logger conf *Config @@ -86,6 +89,9 @@ type Library struct { // SetRescanHooks provides optional hooks for cross-cutting // orchestration during FullRescan. func (l *Library) SetRescanHooks(h RescanHooks) { + l.mu.Lock() + defer l.mu.Unlock() + l.rescanHooks = h } @@ -118,7 +124,10 @@ func NewLibrary( // SetContext sets the Wails runtime context and registers event handlers. func (l *Library) SetContext(ctx context.Context) { + l.mu.Lock() l.ctx = ctx + l.mu.Unlock() + l.registerEventHandlers() } diff --git a/backend/playlist/playlist.go b/backend/playlist/playlist.go index e175438..e038ccf 100644 --- a/backend/playlist/playlist.go +++ b/backend/playlist/playlist.go @@ -11,6 +11,7 @@ import ( "slices" "strconv" "strings" + "sync" "github.com/wailsapp/wails/v2/pkg/runtime" @@ -96,6 +97,9 @@ type PhantomSearchResult struct { // Service manages playlist operations. type Service struct { + // mu protects ctx and favoritesConf from concurrent access + // during initialization. + mu sync.Mutex ctx context.Context logger *slog.Logger db *database.DB @@ -121,6 +125,9 @@ func NewService( func (s *Service) SetFavoritesConfig( provider FavoritesConfigProvider, ) { + s.mu.Lock() + defer s.mu.Unlock() + s.favoritesConf = provider } @@ -128,7 +135,10 @@ func (s *Service) SetFavoritesConfig( // one-time startup migration to bootstrap M3U8 files for // existing playlists. func (s *Service) SetContext(ctx context.Context) { + s.mu.Lock() s.ctx = ctx + s.mu.Unlock() + s.migrateExistingPlaylists() } diff --git a/backend/queue/queue.go b/backend/queue/queue.go index e2ef303..23b0a1a 100644 --- a/backend/queue/queue.go +++ b/backend/queue/queue.go @@ -132,6 +132,9 @@ func NewQueue(logger *slog.Logger, db *database.DB) *Queue { // SetContext sets the Wails runtime context for event emission. func (q *Queue) SetContext(ctx context.Context) { + q.mu.Lock() + defer q.mu.Unlock() + q.ctx = ctx }