@@ -2,91 +2,121 @@ import {
22 WebSocketGateway ,
33 WebSocketServer ,
44 OnGatewayConnection ,
5- OnGatewayDisconnect ,
6- } from '@nestjs/websockets' ;
7- import { Server , Socket } from 'socket.io' ;
8- import { SocketIoService } from './socketio .service' ;
5+ } from "@nestjs/websockets" ;
6+ import { Server , Socket as SocketServer } from "socket.io" ;
7+ import { SocketIoService } from "./socketio.service" ;
8+ import { WebSocketService } from "./websocket .service" ;
99
10- @WebSocketGateway ( { cors : true , path : '/' } )
11- export class SocketIoGateway
12- implements OnGatewayConnection , OnGatewayDisconnect
13- {
10+ @WebSocketGateway ( {
11+ cors : {
12+ origin : "*" ,
13+ methods : [ "GET" , "POST" ] ,
14+ } ,
15+ path : "/socket.io" ,
16+ transports : [ "websocket" ] ,
17+ } )
18+ export class SocketIoGateway implements OnGatewayConnection {
1419 @WebSocketServer ( )
1520 server : Server ;
1621
17- constructor ( private readonly socketIoService : SocketIoService ) { }
22+ constructor (
23+ private readonly socketIoService : SocketIoService ,
24+ private readonly websocketService : WebSocketService ,
25+ ) { }
1826
19- /**
20- * Handle WebSocket connection from the frontend with `tabid`.
21- */
22- async handleConnection ( client : Socket ) {
23- const { url, namespace, tabid, headers } = client . handshake . query ;
27+ async afterInit ( ) {
28+ console . log ( "Socket.io Handler Gateway initialized!" ) ;
29+ }
30+
31+ async handleConnection ( proxySocketIO : SocketServer ) {
32+ const { targetUrl, namespace, headers, targetType } =
33+ proxySocketIO . handshake . query ;
2434
25- if ( ! url || ! namespace || ! tabid ) {
26- client . disconnect ( ) ;
35+ if ( ! targetUrl || ! namespace ) {
36+ proxySocketIO . disconnect ( ) ;
2737 console . error (
28- ' Missing required query parameters: url, namespace, or tabid' ,
38+ " Missing required query parameters: url, namespace, or tabid" ,
2939 ) ;
3040 return ;
3141 }
3242
3343 try {
34- const parsedHeaders = headers ? JSON . parse ( headers as string ) : { } ;
35-
36- // Register frontend client
37- this . socketIoService . registerFrontendClient ( tabid as string , client ) ;
38-
39- // Connect to the real Socket.IO server
40- await this . socketIoService . connectToRealSocket (
41- tabid as string ,
42- url as string ,
43- namespace as string ,
44- parsedHeaders ,
44+ const parsedHeaders = JSON . parse ( headers as string ) ;
45+ const headersObject : { [ key : string ] : string } = parsedHeaders . reduce (
46+ (
47+ acc : Record < string , string > ,
48+ { key, value } : { key : string ; value : string } ,
49+ ) => {
50+ acc [ key ] = value ;
51+ return acc ;
52+ } ,
53+ { } as { [ key : string ] : string } ,
4554 ) ;
4655
47- console . log ( `Proxy connection established for TabID=${ tabid } ` ) ;
56+ if ( targetType === "socketio" ) {
57+ // Establish a connection to the real Socket.IO server
58+ const targetSocketIO =
59+ await this . socketIoService . connectToTargetSocketIO (
60+ proxySocketIO ,
61+ targetUrl as string ,
62+ namespace as string ,
63+ headersObject ,
64+ ) ;
65+
66+ proxySocketIO . on ( "disconnect" , async ( ) => {
67+ // Disconnecting target Socket.IO will automatically disconnects proxy Socket.IO in chain.
68+ targetSocketIO ?. disconnect ( ) ;
69+ } ) ;
4870
49- // Listen for all dynamic events from the frontend and forward them
50- client . onAny ( async ( event : string , ...args : any [ ] ) => {
51- console . log (
52- `Received event from frontend for TabID=${ tabid } : ${ event } ` ,
53- args ,
71+ // Listen for all dynamic events from the frontend and forward them to target Socket.IO.
72+ proxySocketIO . onAny ( async ( event : string , args : any ) => {
73+ try {
74+ if ( event === "sparrow_internal_disconnect" ) {
75+ // Disconnecting target Socket.IO will automatically disconnects proxy Socket.IO in chain.
76+ targetSocketIO ?. disconnect ( ) ;
77+ } else {
78+ targetSocketIO ?. emit ( event , args ) ;
79+ }
80+ } catch ( err ) {
81+ console . error (
82+ `Failed to forward event ${ event } for ${ err . message } ` ,
83+ ) ;
84+ }
85+ } ) ;
86+ } else if ( targetType === "websocket" ) {
87+ // Establish a connection to the real Socket.IO server
88+ const targetWebSocket = await this . websocketService . establishConnection (
89+ proxySocketIO ,
90+ targetUrl as string ,
91+ headersObject ,
5492 ) ;
5593
56- try {
57- // Forward the dynamic event and its arguments to the real server
58- await this . socketIoService . emitToRealSocket (
59- tabid as string ,
60- event ,
61- args ,
62- ) ;
63- } catch ( err ) {
64- console . error (
65- `Failed to forward event ${ event } for TabID=${ tabid } : ${ err . message } ` ,
66- ) ;
67- }
68- } ) ;
94+ proxySocketIO . on ( "disconnect" , async ( ) => {
95+ // Disconnecting target Socket.IO will automatically disconnects proxy Socket.IO in chain.
96+ targetWebSocket ?. close ( ) ;
97+ } ) ;
98+
99+ // Listen for all dynamic events from the frontend and forward them to target Socket.IO.
100+ proxySocketIO . onAny ( async ( event : string , args : any ) => {
101+ try {
102+ if ( event === "sparrow_internal_disconnect" ) {
103+ // Disconnecting target Socket.IO will automatically disconnects proxy Socket.IO in chain.
104+ targetWebSocket ?. close ( ) ;
105+ } else {
106+ targetWebSocket ?. send ( args ) ;
107+ }
108+ } catch ( err ) {
109+ console . error (
110+ `Failed to forward event ${ event } for ${ err . message } ` ,
111+ ) ;
112+ }
113+ } ) ;
114+ }
69115 } catch ( err ) {
70116 console . error (
71- `Failed to connect to real Socket.IO server for TabID= ${ tabid } : ${ err . message } ` ,
117+ `Failed to connect to real Socket.IO server for ${ err . message } ` ,
72118 ) ;
73- client . disconnect ( ) ;
119+ proxySocketIO . disconnect ( ) ;
74120 }
75121 }
76-
77- /**
78- * Handle WebSocket disconnection for a specific `tabid`.
79- */
80- async handleDisconnect ( client : Socket ) {
81- const { tabid } = client . handshake . query ;
82-
83- if ( ! tabid ) {
84- console . error ( 'TabID missing on disconnection' ) ;
85- return ;
86- }
87-
88- console . log ( `Proxy connection closed for TabID=${ tabid } ` ) ;
89- await this . socketIoService . disconnectFromRealSocket ( tabid as string ) ;
90- this . socketIoService . unregisterFrontendClient ( tabid as string ) ;
91- }
92122}
0 commit comments