mirror of
https://github.com/rommapp/grout.git
synced 2026-04-23 06:54:36 +00:00
206 lines
4.0 KiB
Go
206 lines
4.0 KiB
Go
package cache
|
|
|
|
import (
|
|
"grout/romm"
|
|
"sync"
|
|
|
|
gaba "github.com/BrandonKowalski/gabagool/v2/pkg/gabagool"
|
|
)
|
|
|
|
const (
|
|
iconSynced = "\U000F0AA9"
|
|
iconSyncing = "\U000F0CFF"
|
|
iconAlert = "\U000F163A"
|
|
)
|
|
|
|
type syncType int
|
|
|
|
const (
|
|
syncFull syncType = iota
|
|
syncCollectionsOnly
|
|
syncPlatformsOnly
|
|
)
|
|
|
|
type syncRequest struct {
|
|
Type syncType
|
|
Platforms []romm.Platform
|
|
}
|
|
|
|
type BackgroundSync struct {
|
|
platforms []romm.Platform
|
|
icon *gaba.DynamicStatusBarIcon
|
|
requests chan syncRequest
|
|
stop chan struct{}
|
|
wg sync.WaitGroup
|
|
mu sync.Mutex
|
|
running bool
|
|
}
|
|
|
|
func NewBackgroundSync(platforms []romm.Platform) *BackgroundSync {
|
|
return &BackgroundSync{
|
|
platforms: platforms,
|
|
icon: gaba.NewDynamicStatusBarIcon(iconSyncing),
|
|
requests: make(chan syncRequest, 1),
|
|
stop: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
func (b *BackgroundSync) Icon() gaba.StatusBarIcon {
|
|
return gaba.StatusBarIcon{
|
|
Dynamic: b.icon,
|
|
}
|
|
}
|
|
|
|
func (b *BackgroundSync) Start() {
|
|
if b.ensureWorkerRunning() {
|
|
b.queueSync(syncRequest{Type: syncFull})
|
|
}
|
|
}
|
|
|
|
func (b *BackgroundSync) Restart() {
|
|
b.ensureWorkerRunning()
|
|
b.queueSync(syncRequest{Type: syncFull})
|
|
}
|
|
|
|
func (b *BackgroundSync) SyncCollections() {
|
|
b.ensureWorkerRunning()
|
|
b.queueSync(syncRequest{Type: syncCollectionsOnly})
|
|
}
|
|
|
|
func (b *BackgroundSync) SyncPlatforms(platforms []romm.Platform) {
|
|
b.ensureWorkerRunning()
|
|
b.queueSync(syncRequest{Type: syncPlatformsOnly, Platforms: platforms})
|
|
}
|
|
|
|
// ensureWorkerRunning starts the worker if not running. Returns true if worker was started.
|
|
func (b *BackgroundSync) ensureWorkerRunning() bool {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
|
|
if b.running {
|
|
return false
|
|
}
|
|
|
|
b.running = true
|
|
b.requests = make(chan syncRequest, 1)
|
|
b.stop = make(chan struct{})
|
|
b.wg.Add(1)
|
|
go b.worker()
|
|
return true
|
|
}
|
|
|
|
func (b *BackgroundSync) queueSync(req syncRequest) {
|
|
select {
|
|
case b.requests <- req:
|
|
// Queued
|
|
default:
|
|
// Already queued, skip
|
|
}
|
|
}
|
|
|
|
func (b *BackgroundSync) IsRunning() bool {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
return b.running
|
|
}
|
|
|
|
func (b *BackgroundSync) Stop() {
|
|
b.mu.Lock()
|
|
if !b.running {
|
|
b.mu.Unlock()
|
|
return
|
|
}
|
|
b.running = false
|
|
close(b.stop)
|
|
b.mu.Unlock()
|
|
|
|
gaba.GetLogger().Debug("BackgroundSync: Stop requested")
|
|
}
|
|
|
|
func (b *BackgroundSync) SetSynced() {
|
|
b.icon.SetText(iconSynced)
|
|
}
|
|
|
|
func (b *BackgroundSync) worker() {
|
|
logger := gaba.GetLogger()
|
|
defer b.wg.Done()
|
|
|
|
for {
|
|
select {
|
|
case <-b.stop:
|
|
logger.Debug("BackgroundSync: Worker stopped")
|
|
return
|
|
case req := <-b.requests:
|
|
b.runSync(req)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (b *BackgroundSync) runSync(req syncRequest) {
|
|
logger := gaba.GetLogger()
|
|
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
logger.Error("BackgroundSync: Panic recovered", "panic", r)
|
|
b.icon.SetText(iconAlert)
|
|
}
|
|
}()
|
|
|
|
// Check if stopped
|
|
select {
|
|
case <-b.stop:
|
|
return
|
|
default:
|
|
}
|
|
|
|
b.icon.SetText(iconSyncing)
|
|
|
|
cm := GetCacheManager()
|
|
if cm == nil {
|
|
logger.Error("BackgroundSync: Cache manager not initialized")
|
|
b.icon.SetText(iconAlert)
|
|
return
|
|
}
|
|
|
|
var err error
|
|
|
|
switch req.Type {
|
|
case syncCollectionsOnly:
|
|
logger.Debug("BackgroundSync: Starting collections-only sync")
|
|
_, err = cm.SyncCollectionsOnly()
|
|
|
|
case syncPlatformsOnly:
|
|
logger.Debug("BackgroundSync: Starting platform games sync", "platforms", len(req.Platforms))
|
|
_, err = cm.SyncPlatformGames(req.Platforms)
|
|
|
|
default:
|
|
logger.Debug("BackgroundSync: Starting full cache update")
|
|
_, err = cm.PopulateFullCacheWithProgress(b.platforms, nil)
|
|
|
|
// After full sync, retry any platforms that previously failed
|
|
if err == nil {
|
|
needSync := cm.GetPlatformsNeedingSync(b.platforms)
|
|
if len(needSync) > 0 {
|
|
logger.Debug("BackgroundSync: Retrying failed platforms", "count", len(needSync))
|
|
cm.SyncPlatformGames(needSync)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if we were stopped mid-sync
|
|
select {
|
|
case <-b.stop:
|
|
return
|
|
default:
|
|
}
|
|
|
|
if err != nil {
|
|
logger.Error("BackgroundSync: Sync failed", "error", err)
|
|
b.icon.SetText(iconAlert)
|
|
return
|
|
}
|
|
|
|
b.icon.SetText(iconSynced)
|
|
logger.Debug("BackgroundSync: Sync completed")
|
|
}
|