1- /* This is the "veza" server. Used by the API to get data from the shards. Each shard connects to it */
1+ /* This is the Socket.IO server. Used by the API to get data from the shards. Each shard connects to it */
22
3- import { NetworkError , NodeMessage , Server , ServerSocket , ServerStatus } from 'veza' ;
3+ import { Server } from 'socket.io' ;
4+ import { createServer } from 'http' ;
45import { getShardOf } from './utils/discord' ;
56
6- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
7- const server = new Server ( process . env . IPC_SERVER_NAME ! ) ;
7+ const httpServer = createServer ( ) ;
8+ const io = new Server ( httpServer , {
9+ cors : {
10+ origin : '*' // You might want to restrict this in production
11+ }
12+ } ) ;
13+
14+ httpServer . listen ( process . env . IPC_PORT ) ;
15+
16+ // Store connected sockets by shard ID
17+ const connectedShards = new Map ( ) ;
18+
19+ io . on ( 'connection' , ( socket ) => {
20+ const { shardID } = socket . handshake . query ;
21+ connectedShards . set ( shardID , socket ) ;
22+ console . log ( `Shard ${ shardID } connected` ) ;
823
9- const getSockets = ( ) => Array . from ( server . sockets ) . filter ( c => / \d + $ / . test ( c [ 0 ] ) ) ;
24+ socket . on ( 'disconnect' , ( ) => {
25+ // Remove the disconnected shard
26+ for ( const [ shardId , s ] of connectedShards . entries ( ) ) {
27+ if ( s === socket ) {
28+ connectedShards . delete ( shardId ) ;
29+ console . log ( `Shard ${ shardId } disconnected` ) ;
30+ break ;
31+ }
32+ }
33+ } ) ;
34+ } ) ;
35+
36+ const getSockets = ( ) => Array . from ( connectedShards . entries ( ) ) ;
1037
1138interface ChannelData {
1239 id : string ;
@@ -29,59 +56,77 @@ interface UserData {
2956}
3057
3158export const getShardsStatus = async ( ) : Promise < ShardStatus [ ] > => {
59+ const statuses : ShardStatus [ ] = [ ] ;
60+ const sockets = getSockets ( ) ;
61+
3262 const results = await Promise . all (
33- getSockets ( )
34- . map ( s => s [ 1 ] . send ( {
35- event : 'getShardStatus'
36- } , { receptive : true } ) )
37- ) as ShardStatus [ ] ;
38- const statuses = [ ] ;
63+ sockets . map ( ( [ , socket ] ) =>
64+ new Promise < ShardStatus > ( ( resolve ) => {
65+ socket . once ( 'getShardStatusResponse' , ( status : ShardStatus ) => resolve ( status ) ) ;
66+ socket . emit ( 'getShardStatus' ) ;
67+ } )
68+ )
69+ ) ;
70+
71+ // Fill in results for all possible shards
3972 for ( let i = 0 ; i < ( process . env . SHARD_COUNT as unknown as number ) ; i ++ ) {
40- statuses . push (
41- results . find ( ( r ) => r . id === i ) || {
73+ const status = results . find ( s => s . id === i ) ;
74+ if ( status ) {
75+ statuses . push ( status ) ;
76+ } else {
77+ statuses . push ( {
4278 id : i ,
4379 status : 'Disconnected' ,
4480 ram : 0 ,
4581 ping : 0 ,
4682 serverCount : 0
47- }
48- ) ;
83+ } ) ;
84+ }
4985 }
5086 return statuses ;
5187} ;
5288
5389export const getChannelsOf = async ( guildID : string ) : Promise < ChannelData [ ] > => {
5490 const results = await Promise . all (
5591 getSockets ( )
56- . map ( s => s [ 1 ] . send ( {
57- event : 'getChannelsOf' ,
58- guildID,
59- shardID : getShardOf ( guildID )
60- } , { receptive : true } ) )
92+ . map ( ( [ , socket ] ) =>
93+ new Promise < ChannelData [ ] > ( ( resolve ) => {
94+ socket . once ( 'getChannelsOfResponse' , ( channels : ChannelData [ ] ) => {
95+ resolve ( channels ) ;
96+ } ) ;
97+ socket . emit ( 'getChannelsOf' , { guildID, shardID : getShardOf ( guildID ) } ) ;
98+ } )
99+ )
61100 ) ;
62101 return results . flat ( ) as ChannelData [ ] ;
63102} ;
64103
65104export const verifyGuilds = async ( guildIDs : string [ ] ) : Promise < string [ ] > => {
66105 const results = await Promise . all (
67106 getSockets ( )
68- . map ( s => s [ 1 ] . send ( {
69- event : 'verifyGuilds' ,
70- guildIDs
71- } , { receptive : true } ) )
107+ . map ( ( [ , socket ] ) =>
108+ new Promise < string [ ] > ( ( resolve ) => {
109+ socket . once ( 'verifyGuildsResponse' , ( verifiedGuilds : string [ ] ) => {
110+ resolve ( verifiedGuilds ) ;
111+ } ) ;
112+ socket . emit ( 'verifyGuilds' , { guildIDs } ) ;
113+ } )
114+ )
72115 ) ;
73116 return results . flat ( ) as string [ ] ;
74117} ;
75118
76119export const verifyPermissions = async ( userID : string , permissionName : bigint , guildIDs : string [ ] ) : Promise < string [ ] > => {
77120 const results = await Promise . all (
78121 getSockets ( )
79- . map ( s => s [ 1 ] . send ( {
80- event : 'verifyPermissions' ,
81- userID,
82- permissionName,
83- guildIDs
84- } , { receptive : true } ) )
122+ . map ( ( [ , socket ] ) =>
123+ new Promise < string [ ] > ( ( resolve ) => {
124+ socket . once ( 'verifyPermissionsResponse' , ( verifiedGuilds : string [ ] ) => {
125+ resolve ( verifiedGuilds ) ;
126+ } ) ;
127+ socket . emit ( 'verifyPermissions' , { userID, permissionName, guildIDs } ) ;
128+ } )
129+ )
85130 ) ;
86131 return results . flat ( ) as string [ ] ;
87132} ;
@@ -90,77 +135,30 @@ export const fetchUsers = async (userIDs: string[]): Promise<UserData[]> => {
90135 const shardID = parseInt ( getSockets ( ) [ 0 ] [ 0 ] . slice ( 'ManageInvite Shard #' . length ) || '0' ) ;
91136 const results = await Promise . all (
92137 getSockets ( )
93- . map ( s => s [ 1 ] . send ( {
94- event : 'fetchUsers' ,
95- userIDs,
96- shardID
97- } , { receptive : true } ) )
138+ . map ( ( [ , socket ] ) =>
139+ new Promise < UserData [ ] > ( ( resolve ) => {
140+ socket . once ( 'fetchUsersResponse' , ( users : UserData [ ] ) => {
141+ resolve ( users ) ;
142+ } ) ;
143+ socket . emit ( 'fetchUsers' , { userIDs, shardID } ) ;
144+ } )
145+ )
98146 ) ;
99147 console . log ( results ) ;
100- // https://stackoverflow.com/a/56757215/11856499
101148 return ( results . flat ( ) as UserData [ ] ) . filter ( ( v , i , a ) => a . findIndex ( t => ( t . id === v . id ) ) === i ) ;
102149} ;
103150
104151type NotificationType = 'verification' | 'subscribed' | 'paid' | 'dms' | 'cancelled' ;
105152
106153export const sendPaypalNotification = ( guildID : string , guildName : string , userID : string , notificationType : NotificationType ) : void => {
107154 getSockets ( )
108- . map ( s => s [ 1 ] . send ( {
109- event : 'paypalNotification' ,
110- notificationType,
111- guildID,
112- guildName,
113- userID,
114- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
115- shardID : getShardOf ( process . env . SUPPORT_SERVER_ID ! )
116- } ) ) ;
117- } ;
118-
119- server . on ( 'connect' , ( client : ServerSocket ) => {
120- // Disconnect clients that do not match our specified client name.
121- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
122- if ( ! client . name ?. startsWith ( process . env . IPC_CLIENT_NAME ! ) ) {
123- client . disconnect ( true ) ;
124- }
125-
126- console . log ( `[IPC] Client connected: ${ client . name } ` ) ;
127- } ) ;
128-
129- server . on ( 'disconnect' , ( client : ServerSocket ) => {
130- console . log ( `[IPC] Client disconnected: ${ client . name } ` ) ;
131- } ) ;
132-
133- server . on ( 'error' , ( error : Error | NetworkError , client : ServerSocket | null ) => {
134- console . error ( `[IPC] Client error: ${ client ?. name ?? 'unknown' } ` , error ) ;
135- } ) ;
136-
137- server . on ( 'message' , async ( message : NodeMessage ) => {
138- const { event, data } = message . data ;
139-
140- if ( event === 'collectData' ) {
141- const results = await Promise . all (
142- getSockets ( )
143- . map ( s => s [ 1 ] . send ( {
144- event : 'collectData' ,
145- data
146- } , { receptive : true } ) )
155+ . map ( ( [ , socket ] ) =>
156+ socket . emit ( 'paypalNotification' , {
157+ notificationType,
158+ guildID,
159+ guildName,
160+ userID,
161+ shardID : getShardOf ( process . env . SUPPORT_SERVER_ID ! )
162+ } )
147163 ) ;
148-
149- message . reply ( ( results as unknown as string [ ] ) . reduce ( ( a , b ) => a + b ) ) ;
150- }
151-
152- if ( event === 'sendTo' ) {
153- const reply = await server . sendTo ( message . data . to , data , { receptive : true } ) ;
154-
155- message . reply ( reply ) ;
156- }
157- } ) ;
158-
159- server . listen ( process . env . IPC_SERVER_PORT ?? 4000 ) . catch ( console . error ) ;
160-
161- setInterval ( ( ) => {
162- if ( server . status != ServerStatus . Opened ) {
163- console . log ( 'Server is not opened, trying to reopen' ) ;
164- server . listen ( process . env . IPC_SERVER_PORT ?? 4000 ) . catch ( console . error ) ;
165- }
166- } , 1000 * 10 ) ;
164+ } ;
0 commit comments