package common import ( "encoding/json" "fmt" "os" "path/filepath" "time" ) type SrtoolConfig struct { LeaseFile string `json:"lease_file"` LeaseSeconds uint32 `json:"lease_seconds"` } type srtoolLease struct { ExpiresAt int64 `json:"expires_at"` } // This is an expiring tool connection, not a persisted gameplay preference. // A stale FreeSR file alone must never enable custom encounters. func SetSrtoolConnection(connected bool) (uint32, error) { cfg, err := LoadRuntimeConfig() if err != nil { return 0, err } lease := srtoolLease{} if connected { lease.ExpiresAt = time.Now().Add(time.Duration(cfg.Srtool.LeaseSeconds) * time.Second).UnixMilli() } if err = os.MkdirAll(filepath.Dir(cfg.Srtool.LeaseFile), 0700); err != nil { return 0, err } raw, err := json.Marshal(lease) if err != nil { return 0, err } f, err := os.CreateTemp(filepath.Dir(cfg.Srtool.LeaseFile), ".tool-session-*.tmp") if err != nil { return 0, err } name := f.Name() defer os.Remove(name) if _, err = f.Write(raw); err != nil { f.Close() return 0, err } if err = f.Close(); err != nil { return 0, err } if err = os.Rename(name, cfg.Srtool.LeaseFile); err != nil { return 0, fmt.Errorf("save tool connection: %w", err) } return cfg.Srtool.LeaseSeconds, nil } func SrtoolCustomBattleActive() bool { cfg, err := LoadRuntimeConfig() if err != nil { return false } raw, err := os.ReadFile(cfg.Srtool.LeaseFile) if err != nil { return false } var lease srtoolLease return json.Unmarshal(raw, &lease) == nil && lease.ExpiresAt > time.Now().UnixMilli() }