The "pipe" stays open, and the server pushes data to the device instantly.
SocketProvider creates a connection to http://localhost:3000 .@WebSocketGateway() in events.gateway.ts hears this "knock" and handles the connection.SocketProviderimport '../api/api_constants.dart';
part 'socket_provider.g.dart';
@riverpod
IO.Socket socket(Ref ref) {
final socket = IO.io(ApiConstants.socketUrl,
IO.OptionBuilder()
.setTransports(['websocket'])
.disableAutoConnect()
.build()
);
socket.connect();
ref.onDispose(() {
socket.dispose();
});
return socket;
}
import {
WebSocketGateway,
WebSocketServer,
SubscribeMessage,
OnGatewayInit,
OnGatewayConnection,
OnGatewayDisconnect,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { Logger } from '@nestjs/common';
import { WS_EVENTS } from '../../common/constants/app.constants';
@WebSocketGateway({
cors: {
origin: process.env.FRONTEND_URL || '*',
},
})
export class EventsGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
// WebSocket server instance
@WebSocketServer() server: Server;
private logger: Logger = new Logger('EventsGateway');
afterInit(server: Server) {
this.logger.log('WebSocket Gateway Initialized');
}
// Handle client connection
handleConnection(client: Socket, ...args: any[]) {
this.logger.log(`Client connected: ${client.id}`);
}
// Handle client disconnection
handleDisconnect(client: Socket) {
this.logger.log(`Client disconnected: ${client.id}`);
}
// Subscribe to the JOIN_PET event
@SubscribeMessage(WS_EVENTS.JOIN_PET)
handleJoinPet(client: Socket, petId: string) {
// Join a private room for each pet
// Prevents from waking up for thousands of unrelated likes.
client.join(`pet_${petId}`);
this.logger.log(`Client ${client.id} joined room pet_${petId}`);
}
// Subscribe to the LEAVE_PET event
@SubscribeMessage(WS_EVENTS.LEAVE_PET)
handleLeavePet(client: Socket, petId: string) {
// Leave the private room for the pet
client.leave(`pet_${petId}`);
this.logger.log(`Client ${client.id} left room pet_${petId}`);
}
// Broadcast to all clients in the pet's room
broadcastToPet(petId: string, event: string, data: any) {
this.server.to(`pet_${petId}`).emit(event, data);
}
}
import { IoAdapter } from '@nestjs/platform-socket.io';
import { ServerOptions } from 'socket.io';
import { createAdapter } from '@socket.io/redis-adapter';
import { createClient } from 'redis';
// To scale the WebSocket server to multiple instances.
// Each instance will have its own Redis connection.
// The adapter uses Redis pub/sub to broadcast messages to all instances.
export class RedisIoAdapter extends IoAdapter {
private adapterConstructor: ReturnType<typeof createAdapter>;
async connectToRedis(): Promise<void> {
const host = process.env.REDIS_HOST || 'localhost';
const port = process.env.REDIS_PORT || 6379;
const pubClient = createClient({ url: `redis://${host}:${port}` });
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;
}
}