| import { EVENTS, LIMITS, ERROR_CODE, chatMessageSchema } from '@music-together/shared' |
| import { RateLimiterMemory } from 'rate-limiter-flexible' |
| import * as chatService from '../services/chatService.js' |
| import { createWithRoom } from '../middleware/withRoom.js' |
| import type { TypedServer, TypedSocket } from '../middleware/types.js' |
|
|
| const chatLimiter = new RateLimiterMemory({ |
| points: LIMITS.CHAT_RATE_LIMIT_PER_SECOND, |
| duration: 1, |
| }) |
|
|
| export function registerChatController(io: TypedServer, socket: TypedSocket) { |
| const withRoom = createWithRoom(io) |
|
|
| socket.on( |
| EVENTS.CHAT_MESSAGE, |
| withRoom(async (ctx, raw) => { |
| |
| try { |
| await chatLimiter.consume(ctx.socket.id) |
| } catch { |
| ctx.socket.emit(EVENTS.ROOM_ERROR, { code: ERROR_CODE.RATE_LIMITED, message: '发送过于频繁,请稍后再试' }) |
| return |
| } |
|
|
| const parsed = chatMessageSchema.safeParse(raw) |
| if (!parsed.success) { |
| ctx.socket.emit(EVENTS.ROOM_ERROR, { code: ERROR_CODE.INVALID_INPUT, message: '消息格式无效' }) |
| return |
| } |
|
|
| const trimmed = parsed.data.content.trim() |
| if (trimmed.length === 0) return |
|
|
| const message = chatService.createMessage(ctx.roomId, ctx.user, trimmed) |
| io.to(ctx.roomId).emit(EVENTS.CHAT_MESSAGE, message) |
| }), |
| ) |
| } |
|
|