IvanX
IvanX

Reputation: 360

How to inject ConnectedSocket into a service in NestJS

I want to inject @ConnectedSocket into a nestjs service that provides an interface for event emitting. The goal is pretty clear - to avoid calling emit with raw event name and any data. SocketFacadeHost below is an example of such a service.

So far the only way I could think of is replacing each emit call by wrapping socket with a facade service factory - SocketFacade.

socket.facade.ts

class SocketFacadeHost {
  constructor(private client: Socket) { }

  syncDSL(dsl: CoreDSL): void {
    this.client.emit('syncDSL', dsl);
  }
}

export const SocketFacade = (client: Socket) => new SocketFacadeHost(client);

socket.gateway.ts

  ...

  @SubscribeMessage('bind')
  async bindEnvironment(
    @MessageBody() data: BindingDTO,
    @ConnectedSocket() client: Socket,
  ): Promise<void> {
    const { pageUUID } = data;
    const page = await this.pagesService.getByUUID(pageUUID);
    SocketFacade(client).syncDSL(page.coreDSL);
  }

But that is still kinda hackish. Any straightforward way of doing this?

Something like extending @ConnectedSocket decorator or WebSocketGateway?

--- Edit 1 ---

After going through tons of documentation, examples and issues on the subject, I believe the problem lies in the idea of making the service aware of context, that is by default incorrect. Thus guards, interceptors, pipes and all the ExecutionContext decorators only work on the controller/gateway level. Service should either be stateless or instantiated all over on each call (which is controlled by the @Injectable scope).

So my approach of using the facade factory is OK.

But then again, it would be convenient if it was possible to 'replace' @ConnectedSocket() decorator by a decorator that returns wrapped socket with an interface, that wouldn't mess with clean mvc.

Upvotes: 2

Views: 3067

Answers (1)

IvanX
IvanX

Reputation: 360

In the end, I settled with hacking my own 'dependency injection'. Since request scope is not an option for WebSocketGateway, I decided to manually instantiate and cleanup the needed services and store them within Socket client with additional storage interface.

This way I have ConnectedSocket-scoped classes that can communicate to one another, while still having an access to global scoped injections (that have to be manually passed down to all the classes through gateway).

Given approach solves all the problems, while keeping everything dry and in sync with the idea that some day ConnectedSocket-scopes may be added to NestJS.

enter image description here

Upvotes: 1

Related Questions