웹소켓 모듈은 플랫폼에 독립적이기 때문에 WebSocketAdapter
인터페이스를 사용하여 자체 라이브러리를 가져올 수 있습니다. 이 인터페이스는 다음 표에 설명된 몇 가지 메서드를 구현하도록 강제합니다.
socket.io 패키지는 IoAdapter 클래스로 래핑되어 있습니다. 어댑터의 기본 기능을 향상시키고 싶다면 IoAdapter를 확장할 수 있습니다.
여러 로드 밸런싱된 인스턴스에서 socket.io를 사용하려면 Redis 어댑터를 사용해야 합니다. 필요한 패키지를 설치하고 RedisIoAdapter 클래스를 만듭니다.
$ npm i --save redis socket.io @socket.io/redis-adapter
그런 다음 RedisIoAdapter
클래스를 만듭니다.
import { IoAdapter } from '@nestjs/platform-socket.io';
import { ServerOptions } from 'socket.io';
import { createAdapter } from '@socket.io/redis-adapter';
import { createClient } from 'redis';
export class RedisIoAdapter extends IoAdapter {
private adapterConstructor: ReturnType<typeof createAdapter>;
async connectToRedis(): Promise<void> {
const pubClient = createClient({ url: `redis://localhost:6379` });
const subClient = pubClient.duplicate();
await Promise.all([pubClient.connect(), subClient.connect()]);
this.adapterConstructor = createAdapter(pubClient, subClient);
}
createIOServer(port: number, options?: ServerOptions): any {
const server = super.createIOServer(port, options);
server.adapter(this.adapterConstructor);
return server;
}
}
그런 다음 새로 만든 Redis 어댑터로 전환합니다.
//main.ts
const app = await NestFactory.create(AppModule);
const redisIoAdapter = new RedisIoAdapter(app);
await redisIoAdapter.connectToRedis();
app.useWebSocketAdapter(redisIoAdapter);
이렇게 하면 여러 로드 밸런싱된 인스턴스에서 Redis를 사용하여 socket.io를 구현할 수 있습니다.
또 다른 사용 가능한 어댑터는 WsAdapter
입니다. 이 어댑터는 프레임워크와 ws 라이브러리 간의 프록시 역할을 합니다. 이 어댑터는 네이티브 브라우저 웹소켓과 완벽하게 호환되며 socket.io 패키지보다 훨씬 빠릅니다. 불행히도, 기본으로 제공되는 기능은 상당히 적지만, sometime 그것들이 필요하지 않을 수 있을지도 모릅니다.
Hint!
ws 라이브러리는 socket.io에서 인기 있는 네임스페이스(communication channels)를 지원하지 않습니다. 그러나 이 기능을 어떻게든 흉내내기 위해 다른 경로에 여러 ws 서버를 마운트할 수 있습니다. (예: @WebSocketGateway({ path: '/users' }))
ws를 사용하려면 먼저 필요한 패키지를 설치해야 합니다.
$ npm i --save @nestjs/platform-ws
패키지를 설치한 후에는 다음과 같이 어댑터를 전환할 수 있습니다.
//main.ts
const app = await NestFactory.create(AppModule);
app.useWebSocketAdapter(new WsAdapter(app));
Hint!
TheWsAdapter
is imported from@nestjs/platform-ws
.
데모 목적으로 ws 라이브러리를 수동으로 통합해 보겠습니다. 어댑터는 이미 @nestjs/platform-ws
패키지에서 노출되어 있는 WsAdapter
클래스로 만들어졌습니다. 다음은 간소화된 구현 예제일 수 있습니다.
//ws-adapter.ts
import * as WebSocket from 'ws';
import { WebSocketAdapter, INestApplicationContext } from '@nestjs/common';
import { MessageMappingProperties } from '@nestjs/websockets';
import { Observable, fromEvent, EMPTY } from 'rxjs';
import { mergeMap, filter } from 'rxjs/operators';
export class WsAdapter implements WebSocketAdapter {
constructor(private app: INestApplicationContext) {}
create(port: number, options: any = {}): any {
return new WebSocket.Server({ port, ...options });
}
bindClientConnect(server, callback: Function) {
server.on('connection', callback);
}
bindMessageHandlers(
client: WebSocket,
handlers: MessageMappingProperties[],
process: (data: any) => Observable<any>,
) {
fromEvent(client, 'message')
.pipe(
mergeMap(data => this.bindMessageHandler(data, handlers, process)),
filter(result => result),
)
.subscribe(response => client.send(JSON.stringify(response)));
}
bindMessageHandler(
buffer,
handlers: MessageMappingProperties[],
process: (data: any) => Observable<any>,
): Observable<any> {
const message = JSON.parse(buffer.data);
const messageHandler = handlers.find(
handler => handler.message === message.event,
);
if (!messageHandler) {
return EMPTY;
}
return process(messageHandler.callback(message.data));
}
close(server) {
server.close();
}
}
그런 다음 useWebSocketAdapter() 메서드를 사용하여 사용자 정의 어댑터를 설정할 수 있습니다.
//main.ts
const app = await NestFactory.create(AppModule);
app.useWebSocketAdapter(new WsAdapter(app));
이렇게 하면 ws 라이브러리를 사용하는 데모 어플리케이션을 만들 수 있습니다.