fix: protect server config from truncation and recover from Discord guilds

- Save servers_config.json atomically via temp file + fsync + rename
- Keep .bak backup and auto-restore when main config is empty/corrupt
- Add /servers/recover endpoint for manual recovery
- Auto-recover basic server configs on startup when config is empty but bot is in guilds
This commit is contained in:
2026-06-11 20:37:04 +03:00
parent 486acb5c14
commit cfd5eb16f7
3 changed files with 222 additions and 20 deletions

View File

@@ -163,6 +163,42 @@ async def on_ready():
# Start server-specific schedulers (includes DM mood rotation)
server_manager.start_all_schedulers(globals.client)
# Auto-recover server config if it was lost/corrupted (e.g., disk full)
if not server_manager.servers and globals.client.guilds:
logger.warning("⚠️ Server config is empty but bot is in guilds — attempting auto-recovery")
recovered = 0
for guild in globals.client.guilds:
text_channels = [ch for ch in guild.text_channels if ch.permissions_for(guild.me).send_messages]
if not text_channels:
text_channels = guild.text_channels
if not text_channels:
continue
preferred = None
for ch in text_channels:
if ch.name.lower() in ("general", "chat", "main", "lounge", "general-chat"):
preferred = ch
break
channel = preferred or text_channels[0]
try:
server_manager.add_server(
guild_id=guild.id,
guild_name=guild.name,
autonomous_channel_id=channel.id,
autonomous_channel_name=f"#{channel.name}",
bedtime_channel_ids=[channel.id],
enabled_features={"autonomous", "bedtime", "monday_video"}
)
recovered += 1
logger.info(f"🔄 Auto-recovered server: {guild.name} (ID: {guild.id}) → #{channel.name}")
except Exception as e:
logger.error(f"Failed to auto-recover server {guild.name}: {e}")
if recovered > 0:
logger.info(f"✅ Auto-recovered {recovered} server(s) — restarting schedulers")
server_manager.stop_all_schedulers()
server_manager.start_all_schedulers(globals.client)
else:
logger.warning("Auto-recovery found no recoverable servers")
# Start the global scheduler for other tasks
globals.scheduler.start()