discord_radio: desired-state streams, logout on release, no mention controls (node-26#25)
- Rewritten as RadioManager reconciling C2's retained
nodes/{id}/discord/desired (token ids) and publishing
nodes/{id}/discord/actual {applied_seq, sessions, streams}.
- One gateway session per leased token, one voice connection per
(token, guild); a token no stream needs is logged OUT (client.close()),
which is what lets C2 free it safely (item 1).
- Watchdog is a separate reconcile loop; recovering a dead session can no
longer cancel it (item 2). Presence kept across rejoins.
- No message-content intent and no @bot leave/join mention controls (item 3).
- Local dashboard: /api/discord/join returns 409 with an explanation instead
of a TypeError 500; /api/discord/leave pauses locally; GET /api/discord
shows state (item 4). Join/leave results are reported to C2 (item 5).
- Token strings fetched over HTTPS from C2 (lease holder only), memory only.
- MQTT-loss fail-safe: logs every bot out after
DISCORD_MQTT_LOSS_STOP_SECONDS (300, below C2's 600s lease grace).
- Legacy discord_join/discord_leave MQTT commands are ignored.
- Audio path unchanged: FFmpeg -f pulse on settings.pulse_source per
connection, never Icecast.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
80a0e88fc4
commit
419d7c4d8c
@@ -400,15 +400,25 @@ async def set_sdr(body: SdrSettingsBody):
|
||||
return {"ok": True, "running": running}
|
||||
|
||||
|
||||
@router.get("/discord")
|
||||
async def discord_status():
|
||||
"""What the node's radio bots are doing (desired state from C2, actual here)."""
|
||||
return radio_bot.snapshot()
|
||||
|
||||
|
||||
@router.post("/discord/join")
|
||||
async def discord_join(guild_id: int, channel_id: int):
|
||||
ok = await radio_bot.join(guild_id, channel_id)
|
||||
if not ok:
|
||||
raise HTTPException(500, "Failed to join voice channel")
|
||||
return {"ok": True}
|
||||
async def discord_join():
|
||||
# node-26#25 item 4: this used to call join() without a token and 500 every
|
||||
# time. A node cannot lease a radio bot by itself — C2 owns the pool.
|
||||
raise HTTPException(
|
||||
409,
|
||||
"Discord radio channels are started from Discord (/join) or the DRB web app; "
|
||||
"the node cannot pick a radio bot on its own.",
|
||||
)
|
||||
|
||||
|
||||
@router.post("/discord/leave")
|
||||
async def discord_leave():
|
||||
await radio_bot.leave()
|
||||
"""Local stop: log every radio bot out until DRB sends a new channel list."""
|
||||
await radio_bot.pause_locally()
|
||||
return {"ok": True}
|
||||
|
||||
Reference in New Issue
Block a user