2026-04-29 15:18:30 +08:00
|
|
|
|
import * as websocket from "ws";
|
|
|
|
|
|
import { Server } from 'http';
|
|
|
|
|
|
import * as handler from "./class/websockethandler";
|
2026-05-06 16:08:00 +08:00
|
|
|
|
import { log, LogLevel } from './log';
|
2026-04-29 15:18:30 +08:00
|
|
|
|
|
|
|
|
|
|
export default class WSSignaling {
|
|
|
|
|
|
server: Server;
|
|
|
|
|
|
wss: websocket.Server;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 构造函数,初始化WebSocket信令服务器
|
|
|
|
|
|
* @param server HTTP服务器实例
|
|
|
|
|
|
* @param mode 通信模式(public或private)
|
|
|
|
|
|
*/
|
|
|
|
|
|
constructor(server: Server, mode: string) {
|
|
|
|
|
|
// 保存服务器实例
|
|
|
|
|
|
this.server = server;
|
|
|
|
|
|
// 创建WebSocket服务器
|
|
|
|
|
|
this.wss = new websocket.Server({ server });
|
|
|
|
|
|
// 重置处理器,设置通信模式
|
|
|
|
|
|
handler.reset(mode);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 监听WebSocket连接事件
|
|
|
|
|
|
* @param ws WebSocket连接实例
|
|
|
|
|
|
*/
|
|
|
|
|
|
this.wss.on('connection', (ws: WebSocket) => {
|
|
|
|
|
|
// 添加新的WebSocket连接到处理器
|
|
|
|
|
|
handler.add(ws);
|
|
|
|
|
|
//handler.AddHeartbeat(ws);
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 监听连接关闭事件
|
|
|
|
|
|
*/
|
|
|
|
|
|
ws.onclose = (): void => {
|
|
|
|
|
|
// 从处理器中移除关闭的连接
|
|
|
|
|
|
handler.remove(ws);
|
|
|
|
|
|
//handler.RemoveHeartbeat(ws);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 监听消息事件
|
|
|
|
|
|
* @param event 消息事件对象
|
|
|
|
|
|
*/
|
|
|
|
|
|
ws.onmessage = (event: MessageEvent): void => {
|
|
|
|
|
|
// 消息类型说明:
|
|
|
|
|
|
// 1. connect, disconnect 消息格式:
|
|
|
|
|
|
// { type: "connect", connectionId: "连接ID" }
|
|
|
|
|
|
// { type: "disconnect", connectionId: "连接ID" }
|
|
|
|
|
|
// 2. offer, answer, candidate 消息格式:
|
|
|
|
|
|
// {
|
|
|
|
|
|
// type: "offer",
|
|
|
|
|
|
// data: {
|
|
|
|
|
|
// from: "发送方连接ID",
|
|
|
|
|
|
// to: "接收方连接ID",
|
|
|
|
|
|
// data: "信令数据"
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// 3. broadcast 消息格式:
|
|
|
|
|
|
// {
|
|
|
|
|
|
// type: "broadcast",
|
|
|
|
|
|
// message: "广播消息内容",
|
|
|
|
|
|
// targetConnectionId: "目标连接ID(可选)"
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// 解析消息数据
|
|
|
|
|
|
const msg = JSON.parse(event.data);
|
|
|
|
|
|
// 检查消息是否有效
|
|
|
|
|
|
if (!msg || !this) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 打印接收到的消息
|
2026-05-06 16:08:00 +08:00
|
|
|
|
log(LogLevel.log, 'WS received:', msg);
|
2026-04-29 15:18:30 +08:00
|
|
|
|
|
|
|
|
|
|
// 根据消息类型处理
|
|
|
|
|
|
switch (msg.type) {
|
|
|
|
|
|
case "connect":
|
|
|
|
|
|
handler.onConnect(ws, msg.connectionId);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "disconnect":
|
|
|
|
|
|
handler.onDisconnect(ws, msg.connectionId);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "offer":
|
|
|
|
|
|
if (msg.participantId !== undefined) msg.data.participantId = msg.participantId;
|
|
|
|
|
|
handler.onOffer(ws, msg.data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "answer":
|
|
|
|
|
|
if (msg.participantId !== undefined) msg.data.participantId = msg.participantId;
|
|
|
|
|
|
handler.onAnswer(ws, msg.data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "candidate":
|
|
|
|
|
|
if (msg.participantId !== undefined) msg.data.participantId = msg.participantId;
|
|
|
|
|
|
handler.onCandidate(ws, msg.data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "ping":
|
|
|
|
|
|
ws.send(JSON.stringify({ type: "pong" }));
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "pong":
|
|
|
|
|
|
(ws as any).lastActivity = Date.now();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "broadcast":
|
|
|
|
|
|
handler.onBroadcast(ws, msg.data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'call-request':
|
|
|
|
|
|
handler.onCallConnectionId(ws, msg.data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'on-message':
|
|
|
|
|
|
if (msg.from) msg.data.connectionId = msg.from;
|
|
|
|
|
|
handler.onMessage(ws, msg.data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|