优化信息
This commit is contained in:
@@ -7,7 +7,7 @@ import Offer from './offer';
|
||||
import Answer from './answer';
|
||||
import Candidate from './candidate';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { onGetAllConnectionIds, onGetOnlineUsers as onGetWsOnlineUsers } from './websockethandler';
|
||||
import { onGetAllConnectionIds, onGetOnlineUsers as onGetWsOnlineUsers, onGetRooms as onGetWsRooms } from './websockethandler';
|
||||
import { log, LogLevel } from '../log';
|
||||
/**
|
||||
* 断开连接记录类
|
||||
@@ -1039,40 +1039,13 @@ function postCandidate(req: Request, res: Response): void {
|
||||
* description: 总房间数
|
||||
*/
|
||||
function onGetConnections(req: Request, res: Response): void {
|
||||
const connectionId = typeof req.query.connectionId === 'string' ? req.query.connectionId : undefined;
|
||||
const wsRooms = onGetWsRooms(connectionId).map((room) => ({
|
||||
...room,
|
||||
users: room.members
|
||||
}));
|
||||
|
||||
// 收集所有房间ID和链接用户信息
|
||||
const rooms = [];
|
||||
|
||||
// 遍历所有连接对
|
||||
for (const [connectionId, pair] of Array.from(connectionPair.entries())) {
|
||||
// 收集房间中的用户信息
|
||||
const users = [];
|
||||
|
||||
// 添加第一个用户
|
||||
if (pair[0] && clients.has(pair[0])) {
|
||||
users.push({
|
||||
sessionId: pair[0],
|
||||
connected: true
|
||||
});
|
||||
}
|
||||
|
||||
// 添加第二个用户
|
||||
if (pair[1] && clients.has(pair[1])) {
|
||||
users.push({
|
||||
sessionId: pair[1],
|
||||
connected: true
|
||||
});
|
||||
}
|
||||
|
||||
// 添加房间信息
|
||||
rooms.push({
|
||||
roomId: connectionId,
|
||||
users: users,
|
||||
userCount: users.length
|
||||
});
|
||||
}
|
||||
|
||||
res.json({ rooms: rooms, totalRooms: rooms.length });
|
||||
res.json({ rooms: wsRooms, totalRooms: wsRooms.length });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,12 +53,37 @@ interface OnlineUser {
|
||||
avatar: string;
|
||||
}
|
||||
|
||||
interface RoomMemberInfo extends OnlineUser {
|
||||
joinedAt: number;
|
||||
updatedAt: number;
|
||||
}
|
||||
|
||||
interface RoomSnapshot {
|
||||
roomId: string;
|
||||
connectionId: string;
|
||||
hostSocketId: string;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
members: RoomMemberInfo[];
|
||||
userCount: number;
|
||||
}
|
||||
|
||||
interface StoredRoom {
|
||||
roomId: string;
|
||||
connectionId: string;
|
||||
hostSocketId: string;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
members: Map<string, RoomMemberInfo>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接组映射
|
||||
* 键: connectionId
|
||||
* 值: ConnectionGroup(1个host + 多个participants)
|
||||
*/
|
||||
const connectionGroup: Map<string, ConnectionGroup> = new Map<string, ConnectionGroup>();
|
||||
const rooms: Map<string, StoredRoom> = new Map<string, StoredRoom>();
|
||||
|
||||
function asAppWebSocket(ws: WebSocket): AppWebSocket {
|
||||
return ws as AppWebSocket;
|
||||
@@ -89,7 +114,12 @@ function getUserInfo(ws: WebSocket): UserInfo {
|
||||
}
|
||||
|
||||
function setUserInfo(ws: WebSocket, userInfo: UserInfo): void {
|
||||
asAppWebSocket(ws).userInfo = userInfo;
|
||||
asAppWebSocket(ws).userInfo = {
|
||||
id: userInfo.id || '',
|
||||
name: userInfo.name || '',
|
||||
avatar: userInfo.avatar || ''
|
||||
};
|
||||
updateRoomMembersForSocket(ws);
|
||||
}
|
||||
|
||||
function safeSend(ws: WebSocket, payload: unknown): boolean {
|
||||
@@ -111,6 +141,106 @@ function findParticipantSocket(group: ConnectionGroup, participantId: string): W
|
||||
return null;
|
||||
}
|
||||
|
||||
function getSocketRoleInRoom(ws: WebSocket, connectionId: string): 'host' | 'participant' | 'idle' {
|
||||
const group = connectionGroup.get(connectionId);
|
||||
if (group) {
|
||||
if (group.host === ws) {
|
||||
return 'host';
|
||||
}
|
||||
if (group.participants.has(ws)) {
|
||||
return 'participant';
|
||||
}
|
||||
}
|
||||
|
||||
return isPrivate ? 'idle' : 'participant';
|
||||
}
|
||||
|
||||
function toRoomMember(ws: WebSocket, connectionId: string, existing?: RoomMemberInfo): RoomMemberInfo {
|
||||
const userInfo = getUserInfo(ws);
|
||||
const now = Date.now();
|
||||
return {
|
||||
socketId: ensureSocketId(ws),
|
||||
connectionId,
|
||||
participantId: ensureParticipantId(ws),
|
||||
role: getSocketRoleInRoom(ws, connectionId),
|
||||
userId: userInfo.id || '',
|
||||
name: userInfo.name || '',
|
||||
avatar: userInfo.avatar || '',
|
||||
joinedAt: existing ? existing.joinedAt : now,
|
||||
updatedAt: now
|
||||
};
|
||||
}
|
||||
|
||||
function getOrCreateRoom(connectionId: string, ws: WebSocket): StoredRoom {
|
||||
let room = rooms.get(connectionId);
|
||||
const now = Date.now();
|
||||
const socketId = ensureSocketId(ws);
|
||||
if (!room) {
|
||||
room = {
|
||||
roomId: connectionId,
|
||||
connectionId,
|
||||
hostSocketId: '',
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
members: new Map<string, RoomMemberInfo>()
|
||||
};
|
||||
rooms.set(connectionId, room);
|
||||
}
|
||||
|
||||
if (!room.hostSocketId || getSocketRoleInRoom(ws, connectionId) === 'host') {
|
||||
room.hostSocketId = socketId;
|
||||
}
|
||||
room.updatedAt = now;
|
||||
return room;
|
||||
}
|
||||
|
||||
function saveRoomMember(ws: WebSocket, connectionId: string): void {
|
||||
const room = getOrCreateRoom(connectionId, ws);
|
||||
const socketId = ensureSocketId(ws);
|
||||
const existing = room.members.get(socketId);
|
||||
room.members.set(socketId, toRoomMember(ws, connectionId, existing));
|
||||
room.updatedAt = Date.now();
|
||||
}
|
||||
|
||||
function updateRoomMembersForSocket(ws: WebSocket): void {
|
||||
const connectionIds = clients.get(ws);
|
||||
if (!connectionIds) {
|
||||
return;
|
||||
}
|
||||
|
||||
connectionIds.forEach(connectionId => {
|
||||
if (rooms.has(connectionId)) {
|
||||
saveRoomMember(ws, connectionId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function removeRoomMember(ws: WebSocket, connectionId: string): void {
|
||||
const room = rooms.get(connectionId);
|
||||
if (!room) {
|
||||
return;
|
||||
}
|
||||
|
||||
room.members.delete(getSocketId(ws));
|
||||
room.updatedAt = Date.now();
|
||||
if (room.members.size === 0 || room.hostSocketId === getSocketId(ws)) {
|
||||
rooms.delete(connectionId);
|
||||
}
|
||||
}
|
||||
|
||||
function toRoomSnapshot(room: StoredRoom): RoomSnapshot {
|
||||
const members = Array.from(room.members.values());
|
||||
return {
|
||||
roomId: room.roomId,
|
||||
connectionId: room.connectionId,
|
||||
hostSocketId: room.hostSocketId,
|
||||
createdAt: room.createdAt,
|
||||
updatedAt: room.updatedAt,
|
||||
members,
|
||||
userCount: members.length
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取或创建WebSocket会话的连接ID集合
|
||||
* @param session WebSocket会话实例
|
||||
@@ -140,6 +270,7 @@ function reset(mode: string): void {
|
||||
isPrivate = mode == "private";
|
||||
clients.clear();
|
||||
connectionGroup.clear();
|
||||
rooms.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,12 +332,16 @@ function remove(ws: WebSocket): void {
|
||||
group.participants.forEach(participantWs => {
|
||||
safeSend(participantWs, { type: "disconnect", connectionId: connectionId, reason: "host-left" });
|
||||
});
|
||||
rooms.delete(connectionId);
|
||||
connectionGroup.delete(connectionId);
|
||||
} else {
|
||||
group.participants.delete(ws);
|
||||
removeRoomMember(ws, connectionId);
|
||||
// 包含participantId,让host能识别是哪个participant离开
|
||||
safeSend(group.host, { type: "participant-left", connectionId: connectionId, participantId: getParticipantId(ws) });
|
||||
}
|
||||
} else {
|
||||
removeRoomMember(ws, connectionId);
|
||||
}
|
||||
log(LogLevel.log, `Remove connectionId: ${connectionId}`);
|
||||
});
|
||||
@@ -242,6 +377,7 @@ function onConnect(ws: WebSocket, connectionId: string): void {
|
||||
const connectionIds = getOrCreateConnectionIds(ws);
|
||||
connectionIds.add(connectionId);
|
||||
const role = polite ? 'participant' : 'host';
|
||||
saveRoomMember(ws, connectionId);
|
||||
safeSend(ws, { type: "connect", connectionId: connectionId, polite: polite, role: role, participantId: participantId });
|
||||
}
|
||||
|
||||
@@ -266,14 +402,18 @@ function onDisconnect(ws: WebSocket, connectionId: string): void {
|
||||
group.participants.forEach(participantWs => {
|
||||
safeSend(participantWs, { type: "disconnect", connectionId: connectionId, reason: "host-left" });
|
||||
});
|
||||
rooms.delete(connectionId);
|
||||
connectionGroup.delete(connectionId);
|
||||
log(LogLevel.log, `Host disconnected, room ${connectionId} deleted, notified ${group.participants.size} participants`);
|
||||
} else {
|
||||
// participant断开连接,从组中移除并通知host(使用participant-left类型,host不会关闭房间)
|
||||
group.participants.delete(ws);
|
||||
removeRoomMember(ws, connectionId);
|
||||
safeSend(group.host, { type: "participant-left", connectionId: connectionId, participantId: getParticipantId(ws) });
|
||||
log(LogLevel.log, `Participant left connectionId: ${connectionId}, remaining participants: ${group.participants.size}`);
|
||||
}
|
||||
} else {
|
||||
removeRoomMember(ws, connectionId);
|
||||
}
|
||||
|
||||
// 向当前连接发送断开连接消息
|
||||
@@ -328,6 +468,7 @@ function onOffer(ws: WebSocket, message: any): void {
|
||||
if (!connectionGroup.has(connectionId)) {
|
||||
connectionGroup.set(connectionId, { host: ws, participants: new Set<WebSocket>() });
|
||||
}
|
||||
saveRoomMember(ws, connectionId);
|
||||
// 向所有其他客户端广播offer
|
||||
clients.forEach((_v, k) => {
|
||||
if (k == ws) {
|
||||
@@ -570,8 +711,11 @@ function RemoveHeartbeat(ws: WebSocket) {
|
||||
*/
|
||||
function onGetAllConnectionIds(): string[] {
|
||||
// 获取所有connectionId
|
||||
const connectionIds = Array.from(connectionGroup.keys());
|
||||
return connectionIds;
|
||||
const connectionIds = new Set<string>(Array.from(connectionGroup.keys()));
|
||||
rooms.forEach((_room, connectionId) => {
|
||||
connectionIds.add(connectionId);
|
||||
});
|
||||
return Array.from(connectionIds);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -629,6 +773,17 @@ function onGetOnlineUsers(connectionId?: string): OnlineUser[] {
|
||||
return onlineUsers;
|
||||
}
|
||||
|
||||
function onGetRooms(connectionId?: string): RoomSnapshot[] {
|
||||
const roomSnapshots: RoomSnapshot[] = [];
|
||||
rooms.forEach((room, roomConnectionId) => {
|
||||
if (connectionId && roomConnectionId !== connectionId) {
|
||||
return;
|
||||
}
|
||||
roomSnapshots.push(toRoomSnapshot(room));
|
||||
});
|
||||
return roomSnapshots;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理chat-message信令(1对多模式)
|
||||
* host的消息转发给所有participants,participant的消息转发给host
|
||||
@@ -677,5 +832,5 @@ function onMessage(ws: WebSocket, message: any): void {
|
||||
* 导出WebSocket处理器函数
|
||||
*/
|
||||
export { reset, add, remove, onConnect, onDisconnect, onOffer, onAnswer, onCandidate, onCallConnectionId,
|
||||
onBroadcast, onGetAllConnectionIds, onGetOnlineUsers, AddHeartbeat, RemoveHeartbeat, onMessage, isHost,
|
||||
onBroadcast, onGetAllConnectionIds, onGetOnlineUsers, onGetRooms, AddHeartbeat, RemoveHeartbeat, onMessage, isHost,
|
||||
broadcastToGroup, connectionGroup, onHostUserInfo, onInviteCall };
|
||||
|
||||
@@ -6,6 +6,7 @@ const router: express.Router = express.Router();
|
||||
// 不需要会话ID的路由
|
||||
router.get('/connection-ids', handler.getAllConnectionIds);
|
||||
router.get('/users', handler.getOnlineUsers);
|
||||
router.get('/rooms', handler.onGetConnections);
|
||||
|
||||
// 需要会话ID的路由
|
||||
router.use(handler.checkSessionId);
|
||||
|
||||
Reference in New Issue
Block a user