package app import ( "encoding/json" "os" "path/filepath" "sync" "time" "vrc_osc_go/internal/common" ) type RuntimeState struct { mu sync.RWMutex DiscordMuted bool LastOCRText string LastTranslate string CurrentWorld string } var runtimeState = &RuntimeState{} var guestTracker *GuestTracker func SetGuestTracker(t *GuestTracker) { guestTracker = t } func InitGuestTracker(t *GuestTracker) { guestTracker = t if guestTracker != nil { guestTracker.mu.Lock() _ = guestTracker.persistLocked() guestTracker.mu.Unlock() } } func GetGuestTracker() *GuestTracker { return guestTracker } func SetDiscordMuted(v bool) { runtimeState.mu.Lock() runtimeState.DiscordMuted = v runtimeState.mu.Unlock() _ = persistRuntimeState() } func SetOCRText(v string) { runtimeState.mu.Lock() runtimeState.LastOCRText = v runtimeState.mu.Unlock() _ = persistRuntimeState() } func SetTranslateText(v string) { runtimeState.mu.Lock() runtimeState.LastTranslate = v runtimeState.mu.Unlock() _ = persistRuntimeState() } func SetCurrentWorld(v string) { runtimeState.mu.Lock() runtimeState.CurrentWorld = v runtimeState.mu.Unlock() _ = persistRuntimeState() } func SnapshotRuntime() RuntimeState { runtimeState.mu.RLock() defer runtimeState.mu.RUnlock() return *runtimeState } func persistRuntimeState() error { s := SnapshotRuntime() dir := filepath.Join(common.RootDir(), "runtime") if err := os.MkdirAll(dir, 0o755); err != nil { return err } f, err := os.Create(filepath.Join(dir, "state.json")) if err != nil { return err } defer f.Close() enc := json.NewEncoder(f) enc.SetIndent("", " ") return enc.Encode(map[string]any{ "discord_muted": s.DiscordMuted, "ocr": s.LastOCRText, "translate": s.LastTranslate, "world": s.CurrentWorld, "updated_at": time.Now().Format(time.RFC3339), }) }