chatapi / src /handlers /signalingHandler.ts
wilooper's picture
initial commit
87cb242
Raw History Blame Contribute Delete
2.75 kB
import WebSocket from 'ws';
import { ClientMessage } from '../utils/protocol';
import { safeSend, ServerMessageType } from '../utils/protocol';
import { isOnline } from '../redis/presenceClient';
import { enqueueOfflineMessage } from '../redis/messageClient';
import { registry } from '../services/connectionRegistry';
import { logger } from '../utils/logger';
/**
* Handles WebRTC signaling:
* - offer / answer / ice-candidate are forwarded to the target peer.
* - If the peer is offline, the signal is dropped (SDP signals don't
* queue — they are ephemeral). Only chat messages queue offline.
*
* WebRTC fallback to WS relay:
* When a client detects iceConnectionState === 'failed' or 'disconnected',
* it switches to type: 'relay' messages instead.
* The server relays those via handleRelay in connectionHandler.ts.
* This handler is only responsible for SDP/ICE forwarding.
*/
export async function handleSignaling(
_senderWs: WebSocket,
fromUid: string,
msg: ClientMessage
): Promise<void> {
const toUid = msg.payload.toUid as string | undefined;
if (!toUid || typeof toUid !== 'string') {
logger.warn('Signaling message missing toUid', { fromUid, type: msg.type });
return;
}
// Security: block self-signaling
if (toUid === fromUid) return;
const target = registry.getByUid(toUid);
if (!target) {
// Peer not on this process — check Redis
const online = await isOnline(toUid).catch(() => false);
if (!online) {
// Peer offline — signal is ephemeral, inform the sender
safeSend(_senderWs, 'peer-offline', { uid: toUid });
}
// In a multi-node deployment: publish to Redis pub/sub here
// for cross-node delivery. Single-node (HF): nothing to do.
return;
}
// Forward the signal verbatim to the peer
const forwardType = msg.type as ServerMessageType;
safeSend(
target.ws,
forwardType,
{
fromUid,
sdp: msg.payload.sdp,
candidate: msg.payload.candidate,
},
msg.requestId
);
logger.debug('Signal forwarded', { type: msg.type, fromUid, toUid });
}
/**
* Notify a user that a specific peer has come online.
* Called from connectionHandler after the user connects.
*/
export function notifyPeerOnline(targetUid: string, peerUid: string): void {
const target = registry.getByUid(targetUid);
if (!target) return;
safeSend(target.ws, 'peer-online', { uid: peerUid });
}
/**
* Notify a user that a specific peer has gone offline.
* Called from connectionHandler on disconnect.
*/
export function notifyPeerOffline(targetUid: string, peerUid: string): void {
const target = registry.getByUid(targetUid);
if (!target) return;
safeSend(target.ws, 'peer-offline', { uid: peerUid });
}