Nest: Inject Websocket into component

Created on 14 May 2018  路  6Comments  路  Source: nestjs/nest

I'm submitting a...


[ ] Regression 
[ ] Bug report
[X] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior


Adding these lines:

@WebSocketServer()
public socketServer: SocketIO.Server;

Results in this.socketServer being null in Components.

It would be awesome if one could get the native web socket server from everywhere. So I do not need to create a Gateway everytime I want to emit a simple message.

Expected behavior


Attribute is not null.

Minimal reproduction of the problem with instructions

@Component()
export class SocketService {
    // Only connections that are correctly authenticated get into this array
    protected authenticatedConnections: Array<SocketConnection> = [];

    // this is the SocketIO server (can be used for emit etc.)
    @WebSocketServer()
    public socketServer: SocketIO.Server;
}

What is the motivation / use case for changing the behavior?

Environment


Nest version: 4.6.7


For Tooling issues:
- Node version: 8  
- Platform:  

Others:

websockets question 馃檶

Most helpful comment

I was having the same issue, but i had to inject it in one gateway, that gateway dose not do anything, you can think of it as wrapper around the underlying socket server, and then i used it as a dependency in another gateways. Idk if this the only way to do this, but it works :)

All 6 comments

Honestly, it's not that easy. What if someone uses multiple gateways at the same time? IMO, you should inject a gateway to the component instead and pick up the server then.

I was having the same issue, but i had to inject it in one gateway, that gateway dose not do anything, you can think of it as wrapper around the underlying socket server, and then i used it as a dependency in another gateways. Idk if this the only way to do this, but it works :)

@kamilmysliwiec hi, I met a problem when I injected a WebSocketGateway. Here's the sample code.

// event.module.ts

import { Module } from '@nestjs/common'

import { EventGateway } from './event.gateway'
import { EventController } from './event.controller'

@Module({
  providers: [EventGateway],
  controllers: [EventController],
})
export class EventModule {}
// event.gateway.ts
import { SubscribeMessage, WebSocketGateway, WebSocketServer, WsResponse } from '@nestjs/websockets'
import { of, from, Observable } from 'rxjs'
import { map } from 'rxjs/operators'
import { Client, Server } from 'socket.io'

export const store: any = {}

@WebSocketGateway()
export class EventGateway {
  @WebSocketServer()
  server!: Server

  @SubscribeMessage('action:join-room')
  joinRoom(client: Client, room_name: string): Observable<WsResponse<string>> {
    const socket = this.server.sockets.connected[client.id]
    console.log(this.server.sockets.connected)     // will print:  { KUTCDbFhek0BS1YCAAAA: { ... }}
    store.server = this.server
    socket.join(room_name)
    return of({ event: 'events', data: 'join room success' })
  }
}
// event.controller.ts
import { Controller, Post, Inject, Body } from '@nestjs/common'
import { EventGateway, store } from './event.gateway'

@Controller()
export class EventController {
  constructor(
    private readonly eventGateway: EventGateway,
  ) {}

  @Post('/v1/broadcast')
  broadcast(@Body() body: string): string {
    console.log(`broadcast something...`)
    if (!store.server) {
      console.log('no server')
    } else {
      console.log(store.server===this.eventGateway.server)
    }
    console.log(this.eventGateway.server.sockets.connected)  // will print `{}`, it's empty
    this.eventGateway.server
      .to('default-room')
      .emit('broadcast', `POST/broadcast is called. ${body}`)
    return 'ok';
  }
}

And my client could connect successfully to gateway, and could receive "join room success" after send action:join-room message.
But when I call that /v1/broadcast api, I found the server injected doesn't equal to that server which I cached in store object, so the .sockets.connected looks different. It's quite weird to me. Is it expected behavior? If yes, how could I get a singleton injectable instance?

And I tried @shekohex 's solution, to make EventController and EventGateway both depend on a seperated AnotherGateway. And these two injected gateway are still different instances.

Hi, all.

I used socket.io-redis and socket.io-emitter to solve my problem. I could create a singleton server object by socket.io-redis, and it has same data source with the server created in WebSocketGateway.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings