package services import ( "encoding/json" "os" "path/filepath" "sync" "time" "arma3-web-server/internal/models" ) func writeFileAtomic(path string, data []byte) error { dir := filepath.Dir(path) tmp, err := os.CreateTemp(dir, ".tmp-*") if err != nil { return err } tmpPath := tmp.Name() if _, err := tmp.Write(data); err != nil { tmp.Close() os.Remove(tmpPath) return err } if err := tmp.Close(); err != nil { os.Remove(tmpPath) return err } if err := os.Rename(tmpPath, path); err != nil { os.Remove(tmpPath) return err } return nil } type SettingsManager struct { path string mu sync.Mutex } func NewSettingsManager(dataDir string) *SettingsManager { return &SettingsManager{ path: filepath.Join(dataDir, "settings.json"), } } func (sm *SettingsManager) Load() (*models.ServerSettings, error) { sm.mu.Lock() defer sm.mu.Unlock() data, err := os.ReadFile(sm.path) if err != nil { if os.IsNotExist(err) { return sm.defaults(), nil } return nil, err } var s models.ServerSettings if err := json.Unmarshal(data, &s); err != nil { return nil, err } return &s, nil } func (sm *SettingsManager) Save(s *models.ServerSettings) error { sm.mu.Lock() defer sm.mu.Unlock() s.UpdatedAt = time.Now().UTC() data, err := json.MarshalIndent(s, "", " ") if err != nil { return err } return writeFileAtomic(sm.path, data) } func (sm *SettingsManager) Update(fn func(*models.ServerSettings)) (*models.ServerSettings, error) { sm.mu.Lock() defer sm.mu.Unlock() data, err := os.ReadFile(sm.path) if err != nil { if os.IsNotExist(err) { s := sm.defaults() fn(s) s.UpdatedAt = time.Now().UTC() out, err := json.MarshalIndent(s, "", " ") if err != nil { return nil, err } if err := writeFileAtomic(sm.path, out); err != nil { return nil, err } return s, nil } return nil, err } var s models.ServerSettings if err := json.Unmarshal(data, &s); err != nil { return nil, err } fn(&s) s.UpdatedAt = time.Now().UTC() out, err := json.MarshalIndent(s, "", " ") if err != nil { return nil, err } if err := writeFileAtomic(sm.path, out); err != nil { return nil, err } return &s, nil } func (sm *SettingsManager) defaults() *models.ServerSettings { return &models.ServerSettings{ IPPort: "0.0.0.0:2302", ServerParameters: "-server -world=empty -loadMissionToMemory -noPause", SteamBranch: "stable", SteamUser: "anonymous", Platform: "linux", ActiveConfig: "", ActiveModlist: "", AutoUpdateOnStartup: false, AutoStartOnStartup: false, AutoUpdateModsOnStartup: false, WasRunning: false, ScheduledUpdate: "", UpdatedAt: time.Now().UTC(), } }