WebSockets4 min read

Adapterlar

WebSockets moduli platform-agnostik, shuning uchun WebSocketAdapter interfeysidan foydalanib o'zingizning kutubxonangizni (hatto native implementatsiyani) ulashingiz mumkin. Bu int

WebSockets moduli platform-agnostik, shuning uchun WebSocketAdapter interfeysidan foydalanib o'zingizning kutubxonangizni (hatto native implementatsiyani) ulashingiz mumkin. Bu interfeys quyidagi jadvalda tasvirlangan bir nechta metodlarni implement qilishni majbur qiladi:

createBerilgan argumentlar asosida socket instansiyasini yaratadi
bindClientConnectMijoz ulanish hodisasini bog'laydi
bindClientDisconnectMijoz uzilishi hodisasini bog'laydi (ixtiyoriy*)
bindMessageHandlersKirish xabarini mos xabar handleriga bog'laydi
closeServer instansiyasini yakunlaydi

socket.io ni kengaytirish

socket.io paketi IoAdapter klassiga o'ralgan. Adapterning asosiy funksionalligini kengaytirmoqchi bo'lsangiz-chi? Masalan, texnik talablaringiz web servisingizning bir nechta load-balance qilingan instansiyalari bo'ylab hodisalarni broadcast qilish imkoniyatini talab qiladi. Buning uchun IoAdapterni kengaytirib, socket.io serverlarini instansiyalash uchun mas'ul bo'lgan bitta metodni override qilishingiz mumkin. Avvalo, kerakli paketni o'rnatamiz.

Warning

Bir nechta load-balance qilingan instansiyalar bilan socket.io dan foydalanish uchun mijozlaringiz socket.io konfiguratsiyasida transports: ['websocket'] ni o'rnatib pollingni o'chirishingiz yoki load balanceringizda cookie asosidagi routingni yoqishingiz kerak. Faqat Redisning o'zi yetarli emas. Batafsil ma'lumot uchun here.

Terminal
1$ npm i --save redis socket.io @socket.io/redis-adapter

Paket o'rnatilgach, RedisIoAdapter klassini yaratishimiz mumkin.

TypeScript
1import { IoAdapter } from '@nestjs/platform-socket.io';
2import { ServerOptions } from 'socket.io';
3import { createAdapter } from '@socket.io/redis-adapter';
4import { createClient } from 'redis';
5
6export class RedisIoAdapter extends IoAdapter {
7  private adapterConstructor: ReturnType<typeof createAdapter>;
8
9  async connectToRedis(): Promise<void> {
10    const pubClient = createClient({ url: `redis://localhost:6379` });
11    const subClient = pubClient.duplicate();
12
13    await Promise.all([pubClient.connect(), subClient.connect()]);
14
15    this.adapterConstructor = createAdapter(pubClient, subClient);
16  }
17
18  createIOServer(port: number, options?: ServerOptions): any {
19    const server = super.createIOServer(port, options);
20    server.adapter(this.adapterConstructor);
21    return server;
22  }
23}

Shundan so'ng, shunchaki yangi yaratilgan Redis adapteringizga o'ting.

TypeScript
1const app = await NestFactory.create(AppModule);
2const redisIoAdapter = new RedisIoAdapter(app);
3await redisIoAdapter.connectToRedis();
4
5app.useWebSocketAdapter(redisIoAdapter);

Ws kutubxonasi

Yana bir mavjud adapter bu WsAdapter bo'lib, u framework va tezkor, yaxshi sinovdan o'tgan ws kutubxonasi orasida proksi sifatida ishlaydi. Bu adapter native brauzer WebSockets bilan to'liq mos va socket.io paketidan ancha tez. Afsuski, unda tayyor holatda mavjud funksiyalar sezilarli darajada kamroq. Ba'zi holatlarda esa ular shart emas.

Hint

ws kutubxonasi namespace ( socket.io ommalashtirgan aloqa kanallari) ni qo'llab-quvvatlamaydi. Biroq bu imkoniyatni bir muncha taqlid qilish uchun turli yo'llarda bir nechta ws serverlarini mount qilishingiz mumkin (masalan: @WebSocketGateway({{ '{' }} path: '/users' {{ '}' }})).

ws dan foydalanish uchun avval kerakli paketni o'rnatishimiz kerak:

Terminal
1$ npm i --save @nestjs/platform-ws

Paket o'rnatilgach, adapterga o'tishimiz mumkin:

TypeScript
1const app = await NestFactory.create(AppModule);
2app.useWebSocketAdapter(new WsAdapter(app));
Hint

WsAdapter@nestjs/platform-ws paketidan import qilinadi.

wsAdapter {{ '{' }} event: string, data: any {{ '}' }} formatidagi xabarlarni qayta ishlash uchun mo'ljallangan. Agar xabarlarni boshqa formatda qabul qilib, qayta ishlashingiz kerak bo'lsa, ularni talab qilingan formatga aylantirish uchun message parserni sozlashingiz kerak.

TypeScript
1const wsAdapter = new WsAdapter(app, {
2  // To handle messages in the [event, data] format
3  messageParser: (data) => {
4    const [event, payload] = JSON.parse(data.toString());
5    return { event, data: payload };
6  },
7});

Muqobil ravishda, adapter yaratilgandan keyin setMessageParser metodidan foydalanib message parserni sozlashingiz mumkin.

Kengaytirilgan (custom adapter)

Namoyish uchun ws kutubxonasini qo'lda integratsiya qilamiz. Aytilganidek, bu kutubxona uchun adapter allaqachon yaratilgan va @nestjs/platform-ws paketidan WsAdapter klassi sifatida ochiq. Soddalashtirilgan implementatsiya taxminan quyidagicha ko'rinishi mumkin:

TypeScript
ws-adapter
1import * as WebSocket from 'ws';
2import { WebSocketAdapter, INestApplicationContext } from '@nestjs/common';
3import { MessageMappingProperties } from '@nestjs/websockets';
4import { Observable, fromEvent, EMPTY } from 'rxjs';
5import { mergeMap, filter } from 'rxjs/operators';
6
7export class WsAdapter implements WebSocketAdapter {
8  constructor(private app: INestApplicationContext) {}
9
10  create(port: number, options: any = {}): any {
11    return new WebSocket.Server({ port, ...options });
12  }
13
14  bindClientConnect(server, callback: Function) {
15    server.on('connection', callback);
16  }
17
18  bindMessageHandlers(
19    client: WebSocket,
20    handlers: MessageMappingProperties[],
21    process: (data: any) => Observable<any>,
22  ) {
23    fromEvent(client, 'message')
24      .pipe(
25        mergeMap(data => this.bindMessageHandler(data, handlers, process)),
26        filter(result => result),
27      )
28      .subscribe(response => client.send(JSON.stringify(response)));
29  }
30
31  bindMessageHandler(
32    buffer,
33    handlers: MessageMappingProperties[],
34    process: (data: any) => Observable<any>,
35  ): Observable<any> {
36    const message = JSON.parse(buffer.data);
37    const messageHandler = handlers.find(
38      handler => handler.message === message.event,
39    );
40    if (!messageHandler) {
41      return EMPTY;
42    }
43    return process(messageHandler.callback(message.data));
44  }
45
46  close(server) {
47    server.close();
48  }
49}
Hint

ws kutubxonasining imkoniyatlaridan foydalanmoqchi bo'lsangiz, o'zingiznikini yaratish o'rniga ichki WsAdapterdan foydalaning.

Shundan so'ng, useWebSocketAdapter() metodi orqali custom adapterni sozlashimiz mumkin:

TypeScript
main
1const app = await NestFactory.create(AppModule);
2app.useWebSocketAdapter(new WsAdapter(app));

Misol

WsAdapterdan foydalanadigan ishlovchi misol here mavjud.