- Added eager selfbot voice connection establishment to ensure video capture works seamlessly during voice channel joins. - Introduced a manual video watch command for selfbots to allow operators to initiate screen recording of other members' streams. - Enhanced video recording functionality to split recordings into segments based on user activity, similar to voice recordings. - Fixed mobile navigation issues by extending the navbar to include all items and ensuring responsive form controls. - Standardized error handling across frontend components to improve user experience during failures.
3.7 KiB
3.7 KiB
Spec: Voice auto-reconnect (persistent state + rejoin on drop)
Goal
Setelah VoiceController.connect() berhasil, state "sedang merekam di /"
disimpan di Postgres. Kalau gateway restart/reboot, atau koneksi voice drop tidak
disengaja (dikeluarkan/moved/server restart), gateway otomatis join ulang ke channel
yang sama.
Requirement mapping (user's ask)
- "autoreconnect ke channel yg sama jika server restart atau reboot" → reconnect on startup (ready handler) + keep DB record across graceful shutdown.
- "state nya persistent di db" →
voice_auto_reconnecttable. - "rejoin jika tidak sengaja dikeluarkan" → watchdog on
Disconnected/Destroyed(kick / moved / voice server restart) → full rejoin with backoff. - Manual leave (
/voice disconnect, dashboard disconnect) MUST NOT rejoin.
Design decisions
- New table
voice_auto_reconnect(dedicated, notui_state):guild_idtext PKchannel_idtext NOT NULLchannel_nametextconnected_atbigint epoch-msupdated_atbigint epoch-ms DAO:voiceAutoReconnectRepo.ts—upsert(record),list(),delete(guildId).
- Write on connect:
VoiceController.connect()→ afterstartRecordingsuccess →upsert. IDEMPOTENT (upsert per guild). - Clear on manual leave:
handleVoiceDisconnect(all) +handleVoiceDisconnectGuildpassclearPersisted: true. Graceful shutdowndisconnect()keeps the record. - Rejoin on startup: bootstrap
ready→await voiceController.autoReconnect()(list persisted → connect each, non-fatal on failure). - Rejoin on unexpected drop: monitor per-connection; on
Disconnected/Destroyedwith!intentional→ schedule rejoinconnect(guildId, persistedChannelId)with backoff (min 2s, max 30s, max 5 attempts). TrackrejoinAttempts, reset on success. - Intentional flag:
disconnectGuild(guildId, { clearPersisted?, intentional? }).- shutdown
disconnect()→{ intentional: true, clearPersisted: false }. - manual
disconnect()(dashboard) →{ clearPersisted: true }, sets intentional. - manual
disconnectGuild→{ clearPersisted: true }, sets intentional. The monitor checksintentionalbefore rejoin;clearPersistedonly deletes the row.
- shutdown
Files touched
services/discord-gateway/src/shared/database/schema.ts— addpgVoiceAutoReconnectTable- types.
services/discord-gateway/src/shared/database/voiceAutoReconnectRepo.ts(NEW) — DAO.services/discord-gateway/src/modules/voice-recording/voiceController.ts— upsert on connect; monitor + rejoin;autoReconnect();disconnect/disconnectGuildopts.services/discord-gateway/src/modules/command-handler/voice.handler.ts— manual disconnect/disconnectGuild passclearPersisted: true.services/discord-gateway/src/app/bootstrap.ts— callvoiceController.autoReconnect()inready.services/discord-gateway/drizzle/migrations/0020_add_voice_auto_reconnect.sql+meta/_journal.jsonentry (apply manually per gmw-ops).
Edge cases
- Channel deleted / guild lost while persisted →
connect()throws (channel not found) → log + delete persisted row (don't retry forever). - Rejoin attempts exhausted → keep row (so next restart retries) + log.
- Multiple guilds: per-guild monitor, per-guild persisted row.
- Graceful shutdown order: shutdown sets intentional=true (so no rejoin during teardown) but keeps row.
Verification
pnpm typecheck && pnpm build && pnpm lintinservices/discord-gateway.- Apply migration
0020manually; verify table exists. - CI
Build & Deploy (Nix)green; gateway deploy lands. - Manual: connect via dashboard → check
voice_auto_reconnectrow; simulate drop → confirm rejoin; manual disconnect → row cleared.