From 9f157e0aeded9f1951d10acfecbb71cdbb385490 Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Fri, 10 Nov 2023 08:58:09 -0800 Subject: [PATCH] Fix #277: Periodically write config file while app is running --- backend/app.go | 26 ++++++++++++++++++++++++++ backend/config.go | 8 ++++++++ ui/mainwindow.go | 2 ++ 3 files changed, 36 insertions(+) diff --git a/backend/app.go b/backend/app.go index 7ad81090..384a2dac 100644 --- a/backend/app.go +++ b/backend/app.go @@ -7,6 +7,7 @@ import ( "log" "os" "path" + "reflect" "time" "github.com/dweymouth/supersonic/backend/util" @@ -50,6 +51,8 @@ type App struct { isFirstLaunch bool // set by config file reader bgrndCtx context.Context cancel context.CancelFunc + + lastWrittenCfg Config } func (a *App) VersionTag() string { @@ -80,6 +83,7 @@ func StartupApp(appName, displayAppName, appVersionTag, configFile, latestReleas a := &App{appName: appName, appVersionTag: appVersionTag, configFile: configFile} a.bgrndCtx, a.cancel = context.WithCancel(context.Background()) a.readConfig() + a.startConfigWriter(a.bgrndCtx) if !a.Config.Application.AllowMultiInstance { log.Println("Creating session lock file") @@ -166,6 +170,23 @@ func (a *App) startSessionWatcher(sessionPath string) { } } +// periodically save config file so abnormal exit won't lose settings +func (a *App) startConfigWriter(ctx context.Context) { + tick := time.NewTicker(2 * time.Minute) + go func() { + select { + case <-ctx.Done(): + tick.Stop() + return + case <-tick.C: + if !reflect.DeepEqual(&a.lastWrittenCfg, a.Config) { + a.Config.WriteConfigFile(a.configPath()) + a.lastWrittenCfg = *a.Config + } + } + }() +} + func (a *App) callOnReactivate() { if a.OnReactivate != nil { a.OnReactivate() @@ -276,6 +297,11 @@ func (a *App) Shutdown() { os.RemoveAll(configdir.LocalConfig(a.appName, sessionDir)) } +func (a *App) SaveConfigFile() { + a.Config.WriteConfigFile(a.configPath()) + a.lastWrittenCfg = *a.Config +} + func (a *App) configPath() string { return path.Join(configdir.LocalConfig(a.appName), a.configFile) } diff --git a/backend/config.go b/backend/config.go index effe7828..3ffc0738 100644 --- a/backend/config.go +++ b/backend/config.go @@ -2,6 +2,7 @@ package backend import ( "os" + "sync" "github.com/google/uuid" "github.com/pelletier/go-toml/v2" @@ -206,7 +207,14 @@ func ReadConfigFile(filepath, appVersionTag string) (*Config, error) { return c, nil } +var writeLock sync.Mutex + func (c *Config) WriteConfigFile(filepath string) error { + if !writeLock.TryLock() { + return nil // another write in progress + } + defer writeLock.Unlock() + b, err := toml.Marshal(c) if err != nil { return err diff --git a/ui/mainwindow.go b/ui/mainwindow.go index 5524459e..ee19a1d4 100644 --- a/ui/mainwindow.go +++ b/ui/mainwindow.go @@ -100,11 +100,13 @@ func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string, m.ShowWhatsNewDialog() } m.App.Config.Application.LastLaunchedVersion = app.VersionTag() + m.App.SaveConfigFile() } else if t := app.UpdateChecker.VersionTagFound(); t != "" && t != app.Config.Application.LastCheckedVersion { if t != app.VersionTag() { m.ShowNewVersionDialog(displayAppName, t) } m.App.Config.Application.LastCheckedVersion = t + m.App.SaveConfigFile() } // register callback for the ongoing periodic update check m.App.UpdateChecker.OnUpdatedVersionFound = func() {