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)
    })
  }
}