fix: preserve ui state broadcasts in routes

This commit is contained in:
MythEclipse
2026-05-14 19:46:47 +07:00
parent c81a499535
commit 08cd515d8a
2 changed files with 58 additions and 3 deletions

View File

@@ -3,12 +3,40 @@ import express from "express";
import { AppError } from "../errors"; import { AppError } from "../errors";
import { createChildLogger } from "../logger"; import { createChildLogger } from "../logger";
import type { VoiceController } from "../voiceController"; import type { VoiceController } from "../voiceController";
import type { ModerationBroadcaster } from "../moderation/broadcaster";
import type { SharedUIState } from "./uiStateRoutes";
const logger = createChildLogger("voice-routes"); const logger = createChildLogger("voice-routes");
export function createVoiceRoutes(voiceController: VoiceController): Router { export interface VoiceRouteOptions {
voiceController: VoiceController;
patchSharedUIState: (patch: Partial<SharedUIState>) => SharedUIState;
broadcaster: ModerationBroadcaster;
}
export function createVoiceRoutes(
options: VoiceRouteOptions | VoiceController,
): Router {
const router = express.Router(); const router = express.Router();
// Support both old signature (VoiceController) and new signature (options object)
let voiceController: VoiceController;
let patchSharedUIState:
| ((patch: Partial<SharedUIState>) => SharedUIState)
| undefined;
let broadcaster: ModerationBroadcaster | undefined;
if ("connect" in options && "disconnect" in options) {
// Old signature: just VoiceController
voiceController = options as VoiceController;
} else {
// New signature: options object
const opts = options as VoiceRouteOptions;
voiceController = opts.voiceController;
patchSharedUIState = opts.patchSharedUIState;
broadcaster = opts.broadcaster;
}
// GET /api/status - Get voice connection status // GET /api/status - Get voice connection status
router.get("/status", (_req, res, next) => { router.get("/status", (_req, res, next) => {
try { try {
@@ -96,6 +124,16 @@ export function createVoiceRoutes(voiceController: VoiceController): Router {
logger.info({ guildId, channelId }, "Connecting to voice channel"); logger.info({ guildId, channelId }, "Connecting to voice channel");
const status = await voiceController.connect(guildId, channelId); const status = await voiceController.connect(guildId, channelId);
// Update UI state and broadcast to connected clients
if (patchSharedUIState && broadcaster) {
const updatedState = patchSharedUIState({
selectedGuild: guildId,
selectedVoiceChannel: channelId,
});
broadcaster.uiState(updatedState);
}
res.json(status); res.json(status);
} catch (error) { } catch (error) {
next(error); next(error);
@@ -108,6 +146,16 @@ export function createVoiceRoutes(voiceController: VoiceController): Router {
logger.info("Disconnecting from voice channel"); logger.info("Disconnecting from voice channel");
const status = await voiceController.disconnect(); const status = await voiceController.disconnect();
// Update UI state and broadcast to connected clients
if (patchSharedUIState && broadcaster) {
const updatedState = patchSharedUIState({
selectedGuild: "",
selectedVoiceChannel: "",
});
broadcaster.uiState(updatedState);
}
res.json(status); res.json(status);
} catch (error) { } catch (error) {
next(error); next(error);

View File

@@ -182,7 +182,14 @@ export async function startWebserver(
"/api", "/api",
createUIStateRoutes({ getSharedUIState, patchSharedUIState }), createUIStateRoutes({ getSharedUIState, patchSharedUIState }),
); );
app.use("/api", createVoiceRoutes(voiceController)); app.use(
"/api",
createVoiceRoutes({
voiceController,
patchSharedUIState,
broadcaster,
}),
);
app.use("/api", createMessageRoutes()); app.use("/api", createMessageRoutes());
app.use("/api", createAnalysisRoutes()); app.use("/api", createAnalysisRoutes());
app.use("/api", createSyncRoutes(_client)); app.use("/api", createSyncRoutes(_client));
@@ -197,7 +204,7 @@ export async function startWebserver(
const header = Buffer.alloc(4); const header = Buffer.alloc(4);
header.writeInt32LE(hash, 0); header.writeInt32LE(hash, 0);
const packet = Buffer.concat([header, chunk]); const packet = Buffer.concat([header, chunk]);
for (const client of broadcaster.getClients?.() || []) { for (const client of broadcaster.getClients()) {
if (client.readyState === 1) client.send(packet); if (client.readyState === 1) client.send(packet);
} }
}; };