将服务注入到未由 NestJS 实例化的类中(尝试实现 Colyseus + NestJS)

问题描述 投票:0回答:1

我正在努力在未由 NestJS 实例化的类中实现依赖注入。 我想在我的 NestJS 项目中使用 Colyseus 框架 (https://colyseus.io/),并且我需要注入服务,例如用于验证客户端。

export class GameRoom extends Room<GameRoomState> {
    constructor (
        private authService: AuthService
    ) { super() }

    onCreate(options: any) {
        this.setState(new GameRoomState())
    }

    async onAuth(client: Client, options: any, request: IncomingMessage) {
        if (request.headers.cookies) {
            const sessionId = this.authService.getSessionId(request.headers.cookie)
            const user = await this.authService.authSessionId(sessionId)

            if (!user) {
                throw new ServerError(401, 'Invalid Session ID')
            }

            return true
        } else {
            throw new ServerError(401,'You need to provide a "session" cookie with a valid Session ID')
        }
    }
}

然后,如果我们将房间类传递给服务器的定义函数,它将实例化它

this.server.define("GameRoom", GameRoom)

https://docs.colyseus.io/server/api/#define-roomname-string-room-room-options-any

问题是,尽管有一个提供 AuthService 和 GameRoom 类的模块,但当服务器触发“onAuth”回调时,this.authService 将是未定义的,因为 Colyseus 服务器使用的 GameRoom 不是由 Nest 实例化的

Colyseus框架不提供通过传递房间实例来定义房间的方法,仅提供房间类型。 有什么方法可以为我的 GameRoom 类提供服务吗?我没有看到任何方法可以做到这一点,因为 Nest 没有实例化它...... 非常感谢任何愿意提供帮助的人:)

我尝试修改 Colyseus 包来实现一个采用 Room 实例而不是类型的构造函数,但我是一个新手开发人员,但没有成功。 我尝试了很多东西,包括基于属性的注入、使用 NestJS 的 moduleRef,但最终没有任何效果,因为 Colyseus 服务器不使用与我的模块相同的房间实例

class dependency-injection nestjs colyseus
1个回答
0
投票

我解决这个问题的方法是创建一个从 Room 类获取参数类型的函数,然后从这些类型中,可以通过 NextApplication 实例检索依赖项。

这是我写的函数

function injectDeps<T extends { new (...args: any[]): Room }>(
  app: INestApplication,
  target: T,
): T {
  const selfDeps = Reflect.getMetadata('self:paramtypes', target) || [];
  const dependencies = Reflect.getMetadata('design:paramtypes', target) || [];

  selfDeps.forEach((dep: any) => {
    dependencies[dep.index] = dep.param;
  });

  const injectables =
    dependencies.map((dependency: any) => {
      return app.get(dependency);
    }) || [];

  return class extends target {
    constructor(...args: any[]) {
      super(...injectables);
    }
  };
}

在这个函数中,我使用了metadatakey

design:paramtypes
来获取Room类构造函数中所有参数的类型。

self:paramtypes
用于检索使用
@Inject()
装饰器注入的参数类型。

然后你可以如下定义,

  server.define('test', injectDeps(app, BaseRoom));

注意,你的房间等级必须用

@Injectable()
装饰器标记。

这是示例代码

© www.soinside.com 2019 - 2024. All rights reserved.