feat(guild-realtime): add websocket gateway with api-key auth and channel rooms
This commit is contained in:
@@ -8,11 +8,13 @@ import { GuildsModule } from './guilds/guilds.module';
|
||||
import { ChannelsModule } from './channels/channels.module';
|
||||
import { MessagingModule } from './messaging/messaging.module';
|
||||
import { EventsModule } from './events/events.module';
|
||||
import { RealtimeModule } from './realtime/realtime.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forRoot(buildTypeOrmConfig()),
|
||||
EventsModule,
|
||||
RealtimeModule,
|
||||
GuildsModule,
|
||||
ChannelsModule,
|
||||
MessagingModule,
|
||||
|
||||
72
Fabric.Backend.Guild/src/realtime/realtime.gateway.ts
Normal file
72
Fabric.Backend.Guild/src/realtime/realtime.gateway.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import {
|
||||
ConnectedSocket,
|
||||
MessageBody,
|
||||
OnGatewayConnection,
|
||||
OnGatewayDisconnect,
|
||||
SubscribeMessage,
|
||||
WebSocketGateway,
|
||||
WebSocketServer,
|
||||
} from '@nestjs/websockets';
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { Server, Socket } from 'socket.io';
|
||||
|
||||
@WebSocketGateway({
|
||||
namespace: '/realtime',
|
||||
cors: {
|
||||
origin: '*',
|
||||
},
|
||||
})
|
||||
export class RealtimeGateway implements OnGatewayConnection, OnGatewayDisconnect {
|
||||
@WebSocketServer()
|
||||
server!: Server;
|
||||
|
||||
private readonly logger = new Logger(RealtimeGateway.name);
|
||||
|
||||
handleConnection(client: Socket): void {
|
||||
const expected = process.env.FABRIC_API_KEY;
|
||||
if (!expected) {
|
||||
client.disconnect(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const authKey = client.handshake.auth?.apiKey;
|
||||
const headerKey = client.handshake.headers['x-api-key'];
|
||||
const apiKey = typeof authKey === 'string' ? authKey : Array.isArray(headerKey) ? headerKey[0] : headerKey;
|
||||
|
||||
if (apiKey !== expected) {
|
||||
this.logger.warn(`socket rejected: ${client.id}`);
|
||||
client.disconnect(true);
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(`socket connected: ${client.id}`);
|
||||
}
|
||||
|
||||
handleDisconnect(client: Socket): void {
|
||||
this.logger.log(`socket disconnected: ${client.id}`);
|
||||
}
|
||||
|
||||
@SubscribeMessage('join_channel')
|
||||
joinChannel(
|
||||
@ConnectedSocket() client: Socket,
|
||||
@MessageBody() body: { channelId?: string },
|
||||
): { ok: boolean } {
|
||||
if (!body?.channelId) return { ok: false };
|
||||
client.join(`channel:${body.channelId}`);
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
@SubscribeMessage('leave_channel')
|
||||
leaveChannel(
|
||||
@ConnectedSocket() client: Socket,
|
||||
@MessageBody() body: { channelId?: string },
|
||||
): { ok: boolean } {
|
||||
if (!body?.channelId) return { ok: false };
|
||||
client.leave(`channel:${body.channelId}`);
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
emitChannelEvent(channelId: string, event: string, data: Record<string, unknown>): void {
|
||||
this.server.to(`channel:${channelId}`).emit(event, data);
|
||||
}
|
||||
}
|
||||
9
Fabric.Backend.Guild/src/realtime/realtime.module.ts
Normal file
9
Fabric.Backend.Guild/src/realtime/realtime.module.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { RealtimeGateway } from './realtime.gateway';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [RealtimeGateway],
|
||||
exports: [RealtimeGateway],
|
||||
})
|
||||
export class RealtimeModule {}
|
||||
Reference in New Issue
Block a user