2026-06-02 00:11:29 +07:00
|
|
|
/**
|
2026-06-09 11:56:03 +07:00
|
|
|
* Broadcast functions for WebSocket events.
|
2026-06-02 00:11:29 +07:00
|
|
|
*
|
2026-06-09 11:56:03 +07:00
|
|
|
* These are injected by ws/server.ts when the WebSocket server initializes.
|
2026-06-02 00:11:29 +07:00
|
|
|
* Other modules call them to push real-time events to connected frontend clients.
|
|
|
|
|
*
|
|
|
|
|
* Usage:
|
|
|
|
|
* import { broadcastMessageCreated } from "../ws/broadcast.js";
|
|
|
|
|
* broadcastMessageCreated(messageData);
|
|
|
|
|
*/
|
|
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
import { createChildLogger } from "@bete/shared/logger";
|
|
|
|
|
|
|
|
|
|
const logger = createChildLogger("broadcast");
|
|
|
|
|
|
2026-06-02 00:11:29 +07:00
|
|
|
type BroadcastFn = (data: unknown) => void;
|
2026-06-02 00:32:38 +07:00
|
|
|
type BroadcastRawFn = (type: string, data: unknown) => void;
|
2026-06-08 19:14:34 +07:00
|
|
|
type BroadcastBinaryFn = (data: Buffer) => void;
|
2026-06-02 00:11:29 +07:00
|
|
|
|
2026-06-09 11:56:03 +07:00
|
|
|
export interface BroadcastFunctions {
|
|
|
|
|
messageCreated: BroadcastFn;
|
|
|
|
|
messageUpdated: BroadcastFn;
|
|
|
|
|
messageDeleted: BroadcastFn;
|
2026-06-09 16:36:23 +07:00
|
|
|
messageAnalyzed: BroadcastFn;
|
2026-06-09 16:56:44 +07:00
|
|
|
attachmentCreated: BroadcastFn;
|
2026-06-09 11:56:03 +07:00
|
|
|
attachmentUploaded: BroadcastFn;
|
2026-06-09 16:56:44 +07:00
|
|
|
voiceRecordingStarted: BroadcastFn;
|
|
|
|
|
voiceRecordingStopped: BroadcastFn;
|
|
|
|
|
voiceRecordingUploaded: BroadcastFn;
|
2026-06-09 16:36:23 +07:00
|
|
|
voicePcmData: BroadcastFn;
|
|
|
|
|
voiceActiveUser: BroadcastFn;
|
2026-06-09 16:56:44 +07:00
|
|
|
analysisQueueStatus: BroadcastFn;
|
2026-06-09 11:56:03 +07:00
|
|
|
raw: BroadcastRawFn;
|
|
|
|
|
binary: BroadcastBinaryFn;
|
2026-06-02 00:11:29 +07:00
|
|
|
}
|
|
|
|
|
|
2026-06-09 11:56:03 +07:00
|
|
|
let _fns: BroadcastFunctions | null = null;
|
|
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
let _enabled = true;
|
|
|
|
|
|
|
|
|
|
/** Enable or disable broadcast logging (disabled by default to reduce noise). */
|
|
|
|
|
export function setBroadcastLogging(enabled: boolean): void {
|
|
|
|
|
_enabled = enabled;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-09 11:56:03 +07:00
|
|
|
/**
|
|
|
|
|
* Inject broadcast functions from the WebSocket server initializer.
|
|
|
|
|
* Must be called once during server startup before any broadcast is used.
|
|
|
|
|
*/
|
|
|
|
|
export function setBroadcastFunctions(fns: BroadcastFunctions): void {
|
|
|
|
|
_fns = fns;
|
2026-06-09 19:46:08 +07:00
|
|
|
logger.info("Broadcast functions initialized");
|
2026-06-09 11:56:03 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Clear injected functions (used during cleanup). */
|
|
|
|
|
export function clearBroadcastFunctions(): void {
|
|
|
|
|
_fns = null;
|
2026-06-09 19:46:08 +07:00
|
|
|
logger.info("Broadcast functions cleared");
|
2026-06-09 11:56:03 +07:00
|
|
|
}
|
|
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
function logBroadcast(name: string, data: unknown): void {
|
|
|
|
|
if (!_enabled) return;
|
|
|
|
|
// Avoid logging binary or PCM data due to volume
|
|
|
|
|
if (name === "voice_pcm_data" || name === "binary") return;
|
|
|
|
|
logger.debug({ event: name }, "Broadcasting event");
|
|
|
|
|
}
|
2026-06-02 00:11:29 +07:00
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
export const broadcastMessageCreated: BroadcastFn = (data) => {
|
|
|
|
|
logBroadcast("message_created", data);
|
|
|
|
|
_fns?.messageCreated?.(data);
|
|
|
|
|
};
|
2026-06-02 00:11:29 +07:00
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
export const broadcastMessageUpdated: BroadcastFn = (data) => {
|
|
|
|
|
logBroadcast("message_updated", data);
|
|
|
|
|
_fns?.messageUpdated?.(data);
|
|
|
|
|
};
|
2026-06-02 00:11:29 +07:00
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
export const broadcastMessageDeleted: BroadcastFn = (data) => {
|
|
|
|
|
logBroadcast("message_deleted", data);
|
|
|
|
|
_fns?.messageDeleted?.(data);
|
|
|
|
|
};
|
2026-06-09 16:56:44 +07:00
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
export const broadcastAttachmentCreated: BroadcastFn = (data) => {
|
|
|
|
|
logBroadcast("attachment_created", data);
|
|
|
|
|
_fns?.attachmentCreated?.(data);
|
|
|
|
|
};
|
2026-06-02 00:32:38 +07:00
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
export const broadcastAttachmentUploaded: BroadcastFn = (data) => {
|
|
|
|
|
logBroadcast("attachment_uploaded", data);
|
|
|
|
|
_fns?.attachmentUploaded?.(data);
|
|
|
|
|
};
|
2026-06-09 16:36:23 +07:00
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
export const broadcastMessageAnalyzed: BroadcastFn = (data) => {
|
|
|
|
|
logBroadcast("message_analyzed", data);
|
|
|
|
|
_fns?.messageAnalyzed?.(data);
|
|
|
|
|
};
|
2026-06-09 16:56:44 +07:00
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
export const broadcastVoiceRecordingStarted: BroadcastFn = (data) => {
|
|
|
|
|
logBroadcast("voice_recording_started", data);
|
|
|
|
|
_fns?.voiceRecordingStarted?.(data);
|
|
|
|
|
};
|
2026-06-09 16:56:44 +07:00
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
export const broadcastVoiceRecordingStopped: BroadcastFn = (data) => {
|
|
|
|
|
logBroadcast("voice_recording_stopped", data);
|
|
|
|
|
_fns?.voiceRecordingStopped?.(data);
|
|
|
|
|
};
|
2026-06-09 16:56:44 +07:00
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
export const broadcastVoiceRecordingUploaded: BroadcastFn = (data) => {
|
|
|
|
|
logBroadcast("voice_recording_uploaded", data);
|
|
|
|
|
_fns?.voiceRecordingUploaded?.(data);
|
|
|
|
|
};
|
2026-06-09 16:36:23 +07:00
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
export const broadcastVoicePcmData: BroadcastFn = (data) => {
|
|
|
|
|
// PCM data is high-volume; logging is skipped unconditionally
|
|
|
|
|
_fns?.voicePcmData?.(data);
|
|
|
|
|
};
|
2026-06-09 16:36:23 +07:00
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
export const broadcastVoiceActiveUser: BroadcastFn = (data) => {
|
|
|
|
|
logBroadcast("voice_active_user", data);
|
|
|
|
|
_fns?.voiceActiveUser?.(data);
|
|
|
|
|
};
|
2026-06-09 16:56:44 +07:00
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
export const broadcastAnalysisQueueStatus: BroadcastFn = (data) => {
|
|
|
|
|
logBroadcast("analysis_queue_status", data);
|
|
|
|
|
_fns?.analysisQueueStatus?.(data);
|
|
|
|
|
};
|
2026-06-08 19:14:34 +07:00
|
|
|
|
2026-06-09 19:46:08 +07:00
|
|
|
export const broadcastRaw: BroadcastRawFn = (type, data) => {
|
|
|
|
|
logBroadcast(type, data);
|
|
|
|
|
_fns?.raw?.(type, data);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const broadcastBinary: BroadcastBinaryFn = (data) => {
|
|
|
|
|
// Binary data is high-volume; logging is skipped unconditionally
|
|
|
|
|
_fns?.binary?.(data);
|
|
|
|
|
};
|