A. Arif
A. Arif

Reputation: 477

How to access websocket from controller or another component/services?

I have a REST API, I want to send event to the client via websocket. How to inject websocket instance in controller or another component?

Upvotes: 12

Views: 20569

Answers (3)

Raold
Raold

Reputation: 1493

Better solution is to create global module. You can then emit events from any other module/controller. A. Afir approach will create multiple instances of Gateway if you try to use it in other modules.

Note: This is just simplest solution

Create socket.module.ts

import { Module, Global } from '@nestjs/common';
import { SocketService } from './socket.service';

@Global()
@Module({
    controllers: [],
    providers: [SocketService],
    exports: [SocketService],
})
export class SocketModule {}

socket.service.ts

import { Injectable } from '@nestjs/common';
import { Server } from 'socket.io';

@Injectable()
export class SocketService {
    public socket: Server = null;
}

app.gateway.ts see afterInit function

import { WebSocketGateway, OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect, WebSocketServer } from '@nestjs/websockets';
import { Logger } from '@nestjs/common';
import { Server, Socket } from 'socket.io';
import { SocketService } from './socket/socket.service';

@WebSocketGateway()
export class AppGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {

  constructor(private socketService: SocketService){}

  @WebSocketServer() public server: Server;
  private logger: Logger = new Logger('AppGateway');


  afterInit(server: Server) {
    this.socketService.socket = server;
  }

  handleDisconnect(client: Socket) {
    this.logger.log(`Client disconnected: ${client.id}`);
  }

  handleConnection(client: Socket, ...args: any[]) {
    this.logger.log(`Client connected: ${client.id}`);
  }
}

Then import SocketModule into AppModule and you can use Socket service everywhere.

Upvotes: 41

Sergey Pogranichniy
Sergey Pogranichniy

Reputation: 466

I suppose that @Raold missed a fact in the documentation:

Gateways should not use request-scoped providers because they must act as singletons. Each gateway encapsulates a real socket and cannot be instantiated multiple times.

So it means that we can neither instantiate the gateway class multiple times nor do it explicitly using injection scopes features.

So creating just only one gateway for one namespaces will be right and it will produce only one instance of the websocket or socket.io server.

Upvotes: 2

A. Arif
A. Arif

Reputation: 477

class Gateway can be injected in another component, and use the server instance.

@Controller()
export class AppController {
  constructor(
    private readonly appService: AppService,
    private readonly messageGateway: MessageGateway
  ) {}

  @Get()
  async getHello() {
    this.messageGateway.server.emit('messages', 'Hello from REST API');
    return this.appService.getHello();
  }
}

Upvotes: 34

Related Questions