Example using NestJS with Socket.IO and Redis


Example using NestJS with Socket.IO and Redis

File adapters/redis-io.adapter.ts

import { IoAdapter } from '@nestjs/platform-socket.io';
import * as io from 'socket.io'
import * as redisIoAdapter from 'socket.io-redis';
import * as redis from 'redis'

export class RedisIoAdapter extends IoAdapter {
    protected ioServer: io.Server
    constructor(app:any) {    
        super()          
        let httpServer = app.getHttpServer()        
        this.ioServer = io(httpServer)         
    }    
    createIOServer(port: number, options?: io.ServerOptions): any {
        let server
        //same port with main application
        if(port==0 || port == parseInt(process.env.PORT || '4000'))
            server = this.ioServer 
        //different port with main application
        else  
            server = super.createIOServer(port, options);
        
        const pub = redis.createClient({
            host: process.env.REDISHOST||'localhost',
            port: parseInt(process.env.REDISPORT||"6379")
        })
        const sub = redis.createClient({
            host: process.env.REDISHOST||'localhost',
            port: parseInt(process.env.REDISPORT||"6379")
        })
        const redisAdapter = redisIoAdapter({ pubClient: pub, subClient: sub });
        //const redisAdapter = redisIoAdapter({ port: parseInt(process.env.REDISPORT || '6379'), host: process.env.REDISHOST || 'localhost' });

        server.adapter(redisAdapter);
        return server;
    }
}

File main.ts

import { NestFactory } from '@nestjs/core'
import { AppModule } from './app.module'
import * as dotenv from 'dotenv'
import * as helmet from 'helmet'
import * as consolidate from 'consolidate'
import * as path from 'path'
import { NestExpressApplication } from '@nestjs/platform-express'
import { RedisIoAdapter } from './adapters/redis-io.adapter'
dotenv.config()
 
async function bootstrap() {  
  const app = await NestFactory.create<NestExpressApplication>(AppModule,{
    bodyParser:true,    
  })
  app.set('trust proxy', 1)
  app.use(helmet({
    contentSecurityPolicy: false,
  }))  
  app.engine('html', consolidate.mustache)
  app.set('view engine', 'html')
  app.set('views', path.join(__dirname,"..", 'views'))
  
  app.useWebSocketAdapter(new RedisIoAdapter(app));

  await app.listen(process.env.PORT||4000)
}
bootstrap()

File events/events.gateway.ts

import {
  MessageBody,
  SubscribeMessage,
  WebSocketGateway,  
  WsResponse,
  ConnectedSocket  
} from '@nestjs/websockets'
import { Socket } from 'socket.io'

@WebSocketGateway(parseInt(process.env.WSPORT || '4001'),{ namespace: 'events' })
export class EventsGateway { 
  @SubscribeMessage('events')
  handleEvent(
    @MessageBody() data: unknown,
    @ConnectedSocket() client: Socket
  ): WsResponse<unknown> {    
    const event = 'events';
    return { event, data };
  }
}

File events/events.module.ts

import { Module } from '@nestjs/common';
import { EventsGateway } from './events.gateway';

@Module({
  providers: [EventsGateway]
})
export class EventsModule {}

Run test app.

File test.html

<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <meta http-equiv="X-UA-Compatible" content="ie=edge" />
   <title>Sockets test</title>
 </head>
 <body>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.dev.js"></script>
   <script>
     window.s = io('http://localhost:4000/events', {
       query: {
         token: '123',
       },
	   transports: ['polling']
     });

     s.emit('events', { event: 'events', data: { test: true } });
     s.on('events', (response) => {
       console.log(response);
     });
   </script>
 </body>
</html>

Leave a Reply