Home > OS >  Pending Request | NestJS WebSocket Observer
Pending Request | NestJS WebSocket Observer

Time:11-21

I'm developing NestJS app which asks Binance Websocket API for some data. I got all data in my console.log but in Postman or Browser Window a request is pending. I can't understand what's wrong. How can I get data in Postman or Browser Window? Please help.

Update

I developed a new WebSocket server that sends data from Binance's WS to UI. And on the UI side I got only the first item :| What's wrong?

Coin.gateway.ts

import { MessageBody, SubscribeMessage, WebSocketGateway, WebSocketServer } from '@nestjs/websockets';
import { Server } from 'socket.io';
import { from, of, take, map, Observable } from 'rxjs';
import { Coin } from './classes/coin';
import * as coinlist from './list/coins.json'


@WebSocketGateway(811, {transports: ['websocket', 'polling'], cors: true})
export class CoinGateway {

  @WebSocketServer()
  server: Server;

  @SubscribeMessage('events')
  handleMessage(@MessageBody() data: any) {
    console.log('data',data)
    const coins = new Coin(coinlist, 'usdt', 'miniTicker')
    return coins.getCryptoData().pipe(map((c) => {
      return c
    }))
  }
}

Coin.ts

import { GetCryptocurrencies } from "./abstract/get-cryptocurrencies";
import { WebSocket } from "ws";
import { Logger } from "@nestjs/common";
import { Observable } from "rxjs";

export class Coin extends GetCryptocurrencies {
    private readonly logger = new Logger(Coin.name)
    private baseUrl: string
    private url: string
    constructor(coin: { name: string, symbol: string }[], pair: string, method: string) {
        super(coin, pair, method)
        this.baseUrl = 'wss://stream.binance.com:9443/stream?streams='
        this.url = coin.map((c) => {
            return `${c.symbol.toLowerCase()}${pair}@${method}`
        }).join('/')
        }

    getCryptoData(): any {
        const stream$ = new Observable((observer) => {

            const ws = new WebSocket(`${this.baseUrl}${this.url}`)
            ws.on('open', () => {
                this.logger.log('Connection established')
            })
            ws.onmessage = (msg: any) => {
                const message = JSON.parse(msg.data)
                observer.next(message)
            }
            ws.on('close', () => {
                this.logger.log('Connection closed')
            })
        })
        return stream$
    }
}

Client UI useEffect hook

useEffect(() => {
    const socket = io('ws://localhost:811', {transports: ['websocket']})
    socket.on('connect', () => {
        console.log('Connection established from client')

        socket.emit('events', '', (res: any) => {
            console.log(res)
        })
        const engine = socket.io.engine;
        console.log(engine.transport.name); // in most cases, prints "polling"

        engine.once("upgrade", () => {
            // called when the transport is upgraded (i.e. from HTTP long-polling to WebSocket)
            console.log(engine.transport.name); // in most cases, prints "websocket"
        });

        engine.on("packetCreate", ({ type, data }) => {
            // called for each packet sent
            console.log('Stype', type)
            console.log('Sdata', data)
        });

    })
    }, [])

CodePudding user response:

That's happening because you're keeping the Observable (and implicitly the underneath WebSocket) alive, which means that the HTTP GET call never completes.

You could solve it by making sure that the Observable completes after the first data comes from the WS channel. So add take(1) inside the pipe, like this:

import { take } from 'rxjs/operators';

......................................

@Injectable()
export class GetDataService {
    getCoins(): Observable<any[]> {
        const coins = new Coin(coinlist, 'usdt', 'miniTicker')
        return coins.getCryptoData().pipe(
        take(1), // <---- I've added this
        map((c) => {
            console.log(c)
            return c
        }))
    }
}

It should fix your issue.

  • Related