Подключите Nest JS к серверу websocket - PullRequest
1 голос
/ 07 мая 2020

Как можно использовать Nest JS в качестве клиента websocket? Я хочу подключиться к удаленному серверу websocket в качестве клиента с помощью Nest JS, но я не нашел никакой информации об этой реализации в структуре.

Ответы [ 2 ]

1 голос
/ 29 мая 2020

Пробую другим способом. Пишу переходник с socket.io-client. Затем используйте этот адаптер в ускорителе по методу useWebSocketAdapter. После этого я могу написать дескриптор события websocket на шлюзе, как при работе с сервером сокетов (используйте декоратор @SubscribeMessage)

Мой файл адаптера

import { WebSocketAdapter, INestApplicationContext } from '@nestjs/common';
import { MessageMappingProperties } from '@nestjs/websockets'

import * as SocketIoClient from 'socket.io-client';
import { isFunction, isNil } from '@nestjs/common/utils/shared.utils';
import { fromEvent, Observable } from 'rxjs';
import { filter, first, map, mergeMap, share, takeUntil } from 'rxjs/operators';

export class IoClientAdapter implements WebSocketAdapter {
    private io;
    constructor(private app: INestApplicationContext) {

    }

    create(port: number, options?: SocketIOClient.ConnectOpts) {
        const client = SocketIoClient("http://localhost:3000" , options || {})
        this.io = client;
        return client;
    }

    bindClientConnect(server: SocketIOClient.Socket, callback: Function) {
        this.io.on('connect', callback);
    }

    bindClientDisconnect(client: SocketIOClient.Socket, callback: Function) {
        console.log("it disconnect")
        //client.on('disconnect', callback);
    }

    public bindMessageHandlers(
        client: any,
        handlers: MessageMappingProperties[],
        transform: (data: any) => Observable<any>,
    ) {
        const disconnect$ = fromEvent(this.io, 'disconnect').pipe(
            share(),
            first(),
        );

        handlers.forEach(({ message, callback }) => {
            const source$ = fromEvent(this.io, message).pipe(
                mergeMap((payload: any) => {
                    const { data, ack } = this.mapPayload(payload);
                    return transform(callback(data, ack)).pipe(
                        filter((response: any) => !isNil(response)),
                        map((response: any) => [response, ack]),
                    );
                }),
                takeUntil(disconnect$),
            );
            source$.subscribe(([response, ack]) => {
                if (response.event) {
                    return client.emit(response.event, response.data);
                }
                isFunction(ack) && ack(response);
            });
        });
    }

    public mapPayload(payload: any): { data: any; ack?: Function } {
        if (!Array.isArray(payload)) {
            return { data: payload };
        }
        const lastElement = payload[payload.length - 1];
        const isAck = isFunction(lastElement);
        if (isAck) {
            const size = payload.length - 1;
            return {
                data: size === 1 ? payload[0] : payload.slice(0, size),
                ack: lastElement,
            };
        }
        return { data: payload };
    }

    close(server: SocketIOClient.Socket) {
        this.io.close()
    }
}

main. js

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import {IoClientAdapter} from './adapters/ioclient.adapter'

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useWebSocketAdapter(new IoClientAdapter(app))
  await app.listen(3006);
  console.log(`Application is running on: ${await app.getUrl()}`);
}
bootstrap();

затем шлюз

import {
  MessageBody,
  SubscribeMessage,
  WebSocketGateway,
  WebSocketServer,
  WsResponse,
} from '@nestjs/websockets';
import { from, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Server } from 'socket.io';

@WebSocketGateway()
export class EventsGateway {
  @WebSocketServer()
  server: Server;

  @SubscribeMessage('hello')
  async identity(@MessageBody() data: number): Promise<number> {
      console.log(data)
    return data;
  }
}

Это уловка, но выглядит так круто. Обработчик сообщений может писать больше как nest js style.

0 голосов
/ 08 мая 2020

Поскольку Nest js - это просто структура для Nodejs, поэтому вам нужно найти пакет NPM, поддерживающий Websocket. Например, я использую ws с определением типа @types/ws и создаю клиент Websocket как класс обслуживания Nest js:

// socket-client.ts
import { Injectable } from "@nestjs/common";
import * as WebSocket from "ws";

@Injectable()
export class WSService {
    // wss://echo.websocket.org is a test websocket server
    private ws = new WebSocket("wss://echo.websocket.org");

    constructor() {
        this.ws.on("open", () => {
            this.ws.send(Math.random())
        });

        this.ws.on("message", function(message) {
            console.log(message);
        });
    }

    send(data: any) {
        this.ws.send(data);
    }

    onMessage(handler: Function) {
        // ...
    }

    // ...
}

// app.module.ts
import { Module } from "@nestjs/common";
import { WSService } from "./socket-client";

@Module({
    providers: [WSService]
})
export class AppModule {}

...