Nest.js中的Socket.io确认

时间:2018-04-02 13:55:47

标签: javascript socket.io nestjs

我正在尝试在Nest.js WebSocketGateways中启用socket.io确认回调。

我希望能够发出这个:

socket.emit('event', 'some data', function (response) { //do something });

并使用这样的消息处理程序:

@SubscribeMessage('event')
onStart(client, data, ack) {
  //Do stuff
  ack('stuff completed');
}

根据this问题,库中不支持它,因此您必须构建自己的websocket适配器。我尝试过但不确定如何做到这一点。我想我需要在bindMessageHandlers函数中做一些特别的事情,但我的尝试都是徒劳的。 这是框架中捆绑的默认socket.io适配器中的bindMessageHandlers实现:

public bindMessageHandlers(
  client,
  handlers: MessageMappingProperties[],
  process: (data: any) => Observable<any>,
) {
  handlers.forEach(({ message, callback }) =>
    Observable.fromEvent(client, message)
      .switchMap(data => process(callback(data)))
      .filter(result => !!result && result.event)
      .subscribe(({ event, data }) => client.emit(event, data)),
  );
}

有没有人对如何实施这一点有任何指示?
提前谢谢!

4 个答案:

答案 0 :(得分:2)

在短时间内研究NestJS。 这是我的解决方案。

src
├── app.controller.spec.ts
├── app.controller.ts
├── app.module.ts
├── common
│   └── adapters
│       └── ws-adapter.ts
├── events
│   ├── events.gateway.ts
│   └── events.module.ts
└── main.ts

main.ts档案

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { WsAdapter } from './common/adapters/ws-adapter.ts';
import * as cors from 'cors';

let corsOptions = {
    origin: 'http://nestjs.test',
    credentials: true
}

async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    app.useWebSocketAdapter(new WsAdapter(3000));
    app.use(cors(corsOptions));
    await app.listen(4000);
}
bootstrap();

因为当我们使用WebSocket Adapter时,我们不能再使用与NestJS应用程序相同的端口。

common\adapters\ws-adapter.ts档案

import * as WebSocket from 'ws';
import { WebSocketAdapter } from '@nestjs/common';
import { IoAdapter } from '@nestjs/websockets';
import { MessageMappingProperties } from '@nestjs/websockets';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/observable/empty';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/filter';

export class WsAdapter extends IoAdapter {
  public bindMessageHandlers(
    client,
    handlers: MessageMappingProperties[],
    process: (data: any) => Observable<any>,
  ) {
    handlers.forEach(({ message, callback }) => {
        client.on('event', function (data, ack) {
            console.log('DATA', data)
            ack('woot')
        })
        Observable.fromEvent(client, message)
            .switchMap(data => process(callback(data)))
            .filter(result => !!result && result.event)
            .subscribe(({ event, data }) => client.emit(event, data))
        });
  }
}

我的客户端源代码

socket.emit('event', {data: 'some data'}, function (response) {
    console.log('RESPONSE', response)
});
socket.on('event', function(data) {
    console.log('ON EVENT', data);
});

这是我的结果

enter image description here

enter image description here

希望这有帮助!!

答案 1 :(得分:1)

更新:在Nest 5.0中添加了对确认的支持 如果套接字提供程序将多个参数传递到SubscribeMessage处理程序,则request参数将是包含这些参数的数组。

例如使用默认的socket.io-adapter:

@SubscribeMessage('event')
async onEvent(client, request) {
  let data = request[0]
  let ack = request[1] //the acknowledgement function
}

一个问题是,如果您没有提供确认功能request将不是数组,而只是data对象。

在我目前的一个项目中,我通过创建一个提取数据和确认功能的辅助函数或者创建一个占位符来解决这个问题,这意味着我总是可以在不考虑它的情况下调用ack函数&#39存在:

export function extractRequest (req: any): { data: any, ack?: Function } {
  if (Array.isArray(req)) {
    const [data, ack] = req
    return { data, ack }
  } else {
    return { data: req, ack: () => {} }
  }
}

旧回答: 当前状态是,如果不修改Nest源,则无法做到这一点。它将在即将发布的5.0版本中添加。我将在发布时通过示例更新此答案。

来源:https://github.com/nestjs/nest/issues/581

答案 2 :(得分:0)

您可以尝试以下模块:https://www.npmjs.com/package/nestjs-socket-handlers-with-ack。它在后台调用确认功能,您只需要返回一些值或抛出错误即可。希望对您有帮助

答案 3 :(得分:0)

只需使用SubscribeMessage中的return语句

// server
@SubscribeMessage('message')
  async onMessage(
    client: Socket, query: string
  ) {
    try {
      console.log(query) 
      return 'hello'
    } catch (e) {
      // ...
    } 
  }

在客户端将功能用作第三参数

// client
this.socket.emit('message', query, (res) => {
  console.log(res); // should log 'hello'
});