fenghuo/apps/backend/src/socket.ts

132 lines
3.1 KiB
TypeScript

import { createBunWebSocket } from 'hono/bun';
import type { ServerWebSocket } from 'bun';
import { WSContext } from 'hono/ws';
enum MessageType {
TEXT = 'text',
IMAGE = 'image',
FILE = 'file',
RETRACT = 'retract', // 用于实现撤回
}
interface WSMessageParams {
text?: string;
type?: MessageType;
fileUri?: string;
}
// 定义消息类型接口
interface WSMessage {
action: 'join' | 'leave' | 'message';
roomId: string;
data: WSMessageParams;
}
// 创建 WebSocket 实例并指定泛型类型
const { upgradeWebSocket, websocket } = createBunWebSocket<ServerWebSocket>();
// 存储房间和连接的映射关系
const rooms = new Map<string, Set<WSContext<ServerWebSocket>>>();
// WebSocket 处理器
const wsHandler = upgradeWebSocket((c) => {
// 存储当前连接加入的房间
const joinedRooms = new Set<string>();
return {
onOpen(_, ws) {
console.log('WebSocket 连接已建立');
},
onMessage(message, ws) {
try {
const parsedMessage: WSMessage = JSON.parse(message.data as any);
console.log('收到消息:', parsedMessage);
switch (parsedMessage.action) {
case 'join':
// 加入房间
if (!rooms.has(parsedMessage.roomId)) {
rooms.set(parsedMessage.roomId, new Set());
}
rooms.get(parsedMessage.roomId)?.add(ws);
joinedRooms.add(parsedMessage.roomId);
// 发送加入成功消息
ws.send(
JSON.stringify({
action: 'system',
data: {
text: `成功加入房间 ${parsedMessage.roomId}`,
type: MessageType.TEXT,
},
roomId: parsedMessage.roomId,
}),
);
break;
case 'leave':
// 离开房间
rooms.get(parsedMessage.roomId)?.delete(ws);
joinedRooms.delete(parsedMessage.roomId);
if (rooms.get(parsedMessage.roomId)?.size === 0) {
rooms.delete(parsedMessage.roomId);
}
break;
case 'message':
// 在指定房间内广播消息
const room = rooms.get(parsedMessage.roomId);
if (room) {
const messageToSend = {
action: 'message',
data: parsedMessage.data,
roomId: parsedMessage.roomId,
};
for (const conn of room) {
if (conn.readyState === WebSocket.OPEN) {
conn.send(JSON.stringify(messageToSend));
}
}
}
break;
}
} catch (error) {
console.error('处理消息时出错:', error);
ws.send(
JSON.stringify({
action: 'error',
data: {
text: '消息处理失败',
type: MessageType.TEXT,
},
}),
);
}
},
onClose(_, ws) {
console.log('WebSocket 连接已关闭');
// 清理所有加入的房间
for (const roomId of joinedRooms) {
rooms.get(roomId)?.delete(ws);
if (rooms.get(roomId)?.size === 0) {
rooms.delete(roomId);
}
}
},
onError(error, ws) {
console.error('WebSocket 错误:', error);
// 清理所有加入的房间
for (const roomId of joinedRooms) {
rooms.get(roomId)?.delete(ws);
if (rooms.get(roomId)?.size === 0) {
rooms.delete(roomId);
}
}
},
};
});
export const wsConfig = {
websocket,
};
export { wsHandler, rooms };