import { EVENTS, ERROR_CODE, defineAbilityFor } from '@music-together/shared' import type { Actions, Subjects, UserRole } from '@music-together/shared' import type { HandlerContext, TypedServer } from './types.js' import { createWithRoom } from './withRoom.js' import { userRepo } from '../repositories/userRepository.js' /** Server administrators have full room permissions regardless of room role. */ export function defineAbilityForRoomUser(userId: string, roomRole: UserRole) { return defineAbilityFor(userRepo.isServerAdmin(userId) ? 'owner' : roomRole) } /** * Socket 中间件:基于 CASL 权限检查。 * 根据用户 role 生成 ability,检查 (action, subject) 是否允许。 */ export function createWithPermission(io: TypedServer) { const withRoom = createWithRoom(io) return function withPermission( action: Actions, subject: Subjects, handler: (ctx: HandlerContext, data: T) => void | Promise, ) { return withRoom((ctx, data) => { const ability = defineAbilityForRoomUser(ctx.user.id, ctx.user.role) if (!ability.can(action, subject)) { ctx.socket.emit(EVENTS.ROOM_ERROR, { code: ERROR_CODE.NO_PERMISSION, message: '你没有权限执行此操作', }) return } return handler(ctx, data) }) } } /** * Socket 中间件:仅 Owner(房间创建者)可执行。 * 用于房间设置、角色管理等只有房主才能操作的场景。 */ export function createWithOwnerOnly(io: TypedServer) { const withRoom = createWithRoom(io) return function withOwnerOnly(handler: (ctx: HandlerContext, data: T) => void | Promise) { return withRoom((ctx, data) => { if (ctx.user.role !== 'owner' && !userRepo.isServerAdmin(ctx.user.id)) { ctx.socket.emit(EVENTS.ROOM_ERROR, { code: ERROR_CODE.NO_PERMISSION, message: '只有房主可以操作', }) return } return handler(ctx, data) }) } }