Search code examples
node.jswebsocketnestjsnestjs-gateways

Not able to call Service inside WebSocket listener in Nestjs


I have implemented WebSockets in Nestjs using below method and one of the requirement is that I need to update the db once I receive any message from websocket server. In order to do that I have done the below code but getting error like this:

But if I call the same method inside any other controller method it works fine(check /test1). Only when I call it from websocket listener I'm getting this error. Even if I call simple method from same controller to just print some log, I'm getting the same error TypeError: this.processData is not a function. Weird!

Can someone tell me what am I doing wrong with this?

(node:11421) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'updateResponseData' of undefined
    at WebSocket.incoming (/opt/dist/controller/sample.controller.js:62:44)
    at WebSocket.emit (events.js:210:5)
    at Receiver.receiverOnMessage (/opt/node_modules/ws/lib/websocket.js:800:20)
    at Receiver.emit (events.js:210:5)
    at Receiver.dataMessage (/opt/node_modules/ws/lib/receiver.js:423:14)
    at Receiver.getData (/opt/node_modules/ws/lib/receiver.js:353:17)
    at Receiver.startLoop (/opt/node_modules/ws/lib/receiver.js:139:22)
    at Receiver._write (/opt/node_modules/ws/lib/receiver.js:74:10)
    at doWrite (_stream_writable.js:431:12)
    at writeOrBuffer (_stream_writable.js:415:5)
    at Receiver.Writable.write (_stream_writable.js:305:11)
    at Socket.socketOnData (/opt/node_modules/ws/lib/websocket.js:875:35)
    at Socket.emit (events.js:210:5)    
    at addChunk (_stream_readable.js:308:12)
    at readableAddChunk (_stream_readable.js:289:11)
    at Socket.Readable.push (_stream_readable.js:223:10)
(node:11421) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:11421) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Controller Code :

import { Controller, Post, Get, Inject, Req, UsePipes, Body, Header,Param } from '@nestjs/common';
import { Request } from 'express';
import * as WebSocket  from 'ws';
import { DatabaseService } from '../service/datafetch.service';

@Controller('sample')
export class SampleController {

    @Inject(dbService)
    private dbService: DatabaseService;

    static ws: any;
    static wsnew: any;
    public receiveDistData = '';

    // Connect WS & Listen to messages
    constructor() {
        this.initWs();     

        SampleController.ws.on('message', async function incoming(data) {
            console.log('message recieved 8081');
            var dataJson = JSON.parse(data);
            await this.dbService.updateResponseData(dataJson);
            return data;       
        }); 
    }

    @Get('/test/data/:id')
    async testData(@Param('id') id: string) {
        return await this.callWs(id);
    }

    @Get('/test1/data/:id')
    async testData1(@Param('id') id: string) {
        const data = {id: id, data:{}};
        return await this.dbService.updateResponseData(data);
    }

    async initWs() {
        SampleController.ws = new WebSocket('ws://127.0.0.1:8081');
    }

    async processData() {
        console.log('Printing a log...');
    }

    // Data Distribution
    async callWs(id) {    
        // If Socket is not opened, try to re-open    
        if(SampleController.ws.readyState != 1) { 
            console.log('Server is dead....');
            this.initWs();
        }

        const Data = await this.dbService.findAll(id);
        await SampleController.ws.send(JSON.stringify({
            event: 'channel1',
            data: Data,
        }));
    }

}

Repository Code:

import { InjectRepository } from '@nestjs/typeorm';
import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { SampleRepository } from '../repository/sample.repository';

@Injectable()
export class SampleService {

  constructor(
    @InjectRepository(SampleRepository)
    private readonly sampleRepository: SampleRepository
  ) {}

  async updateResponseData(data): Promise<any> {
    return await this.sampleRepository.updateData(data);
  }

}

Solution

  • Inside an anonymous function, this refers to the global object, not the instance of your service.

    Instead you can use an arrow function. Here, this refers to the class instance, as you would expect:

    async function(data) {
      // this is global object
      this.call();
    
    
    (data) => {
      // this is the same as in enclosing object
      this.call();