File size: 2,022 Bytes
00a912e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | 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<T = void>(
action: Actions,
subject: Subjects,
handler: (ctx: HandlerContext, data: T) => void | Promise<void>,
) {
return withRoom<T>((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<T = void>(handler: (ctx: HandlerContext, data: T) => void | Promise<void>) {
return withRoom<T>((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)
})
}
}
|