Fix all activity system edge cases

Critical fixes:
- Add threading.Lock for all shared mutable state (override, cache, current activity)
- Atomic YAML writes (temp file + os.replace) to prevent corruption on crash
- Deep-copy cache on reads to prevent callers from mutating shared state

High-severity fixes:
- Validate entries in pick_activity_for_mood() — skip/log malformed instead of KeyError
- Log warning on unrecognized activity type fallback
- Normalize empty-string state to None (avoid 'None' display)
- release_manual_override() now uses force=True so bot always shows activity
- Add try/except in release_manual_override() to handle failures gracefully

Medium fixes:
- Remove dead 'test' mood from activities.yaml
- Validate name length (128 char Discord limit) in CRUD and manual set
- Validate streaming entries have URL in CRUD path
- Add JSON parse error handling in API routes
- on_ready preserves active manual override instead of overwriting
- Log override expiry timestamp (HH:MM:SS) for easier debugging
- exc_info=True on presence update errors for full stack traces

Low fixes:
- JS activitySetFromEntry() shows notification on parse error
This commit is contained in:
2026-04-28 00:18:25 +03:00
parent 2d7acd7850
commit 6080fe170f
5 changed files with 172 additions and 78 deletions

View File

@@ -7137,7 +7137,7 @@ async function activitySetFromEntry(btnElement) {
const raw = btnElement.getAttribute('data-entry');
if (!raw) return;
let entry;
try { entry = JSON.parse(decodeURIComponent(raw)); } catch { return; }
try { entry = JSON.parse(decodeURIComponent(raw)); } catch (e) { showNotification('Failed to parse activity data', 'error'); return; }
const type = entry.type;
const name = entry.name;
const state = entry.state || null;