feat: implement all real backend endpoints, Redis pub/sub bridge, and gateway command handler

Backend (real implementations, no more stubs):
- Redis pub/sub bridge: subscribes to discord-gateway events (message/attachment/voice) and broadcasts to WS clients
- Redis command channel: backend publishes voice/media commands, discord-gateway executes and replies
- Voice service: connectVoice/disconnectVoice/getVoiceStatus via Redis commands with graceful fallback
- Media service: queue/skip/stop/volume via Redis commands, reads status from Redis cache
- Messages repository: ALL 7 methods now use real PostgreSQL queries (findMany, findById, findByChannel, create, update, delete, getAttachmentsByChannel)
- Analytics: period returns {start,end} epoch millis, overview includes hourly/topics/top_users, worst_flags as string[]
- Health check: actually queries SELECT 1 against database
- VoiceStatus type fixed: {connected, activeGuildId, activeChannelId, activeChannelName}
- Guild type: includes icon: string | null
- asyncHandler: accepts Promise<unknown> instead of Promise<void>

Discord Gateway:
- CommandHandler: subscribes to 'backend:command' Redis channel, executes voice/media commands, publishes replies
- Publishes voice:status and media:status to Redis for backend caching
- Shutdown handler updated to close command handler

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MythEclipse
2026-06-02 00:32:38 +07:00
co-authored by Claude Opus 4.8
parent 9b41eb9c12
commit 3b2709455e
16 changed files with 1326 additions and 148 deletions
+17 -14
View File
@@ -10,15 +10,18 @@ interface BroadcastEvent {
timestamp: string;
}
type BroadcastFn = (data: unknown) => void;
// Extend globalThis with broadcast function types
declare global {
// biome-ignore lint/suspicious/noAssignInExpressions: intentional global broadcast registry
var broadcastMessageCreated: BroadcastFn | undefined;
var broadcastMessageUpdated: BroadcastFn | undefined;
var broadcastMessageDeleted: BroadcastFn | undefined;
var broadcastAttachmentUploaded: BroadcastFn | undefined;
var __broadcastFns:
| {
messageCreated: (data: unknown) => void;
messageUpdated: (data: unknown) => void;
messageDeleted: (data: unknown) => void;
attachmentUploaded: (data: unknown) => void;
raw: (type: string, data: unknown) => void;
}
| undefined;
}
export function createWebSocketServer(server: Server): WebSocketServer {
@@ -87,18 +90,18 @@ export function createWebSocketServer(server: Server): WebSocketServer {
}
}
globalThis.broadcastMessageCreated = (data: unknown) =>
broadcast({ type: "message_created", data });
globalThis.broadcastMessageUpdated = (data: unknown) =>
broadcast({ type: "message_updated", data });
globalThis.broadcastMessageDeleted = (data: unknown) =>
broadcast({ type: "message_deleted", data });
globalThis.broadcastAttachmentUploaded = (data: unknown) =>
broadcast({ type: "attachment_uploaded", data });
globalThis.__broadcastFns = {
messageCreated: (data: unknown) => broadcast({ type: "message_created", data }),
messageUpdated: (data: unknown) => broadcast({ type: "message_updated", data }),
messageDeleted: (data: unknown) => broadcast({ type: "message_deleted", data }),
attachmentUploaded: (data: unknown) => broadcast({ type: "attachment_uploaded", data }),
raw: (type: string, data: unknown) => broadcast({ type, data }),
};
// Cleanup on close
wss.on("close", () => {
clearInterval(heartbeatInterval);
globalThis.__broadcastFns = undefined;
});
logger.info({ path: "/ws" }, "WebSocket server created");