Skip to content

Commit bed5f44

Browse files
committed
♻️ Migrate 'veza' to 'socket.io'
1 parent 23ac04a commit bed5f44

File tree

4 files changed

+94
-108
lines changed

4 files changed

+94
-108
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
API_PORT=3300
2+
IPC_PORT=3200
23

34
CLIENT_ID=""
45
CLIENT_SECRET=""

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
"jsonwebtoken": "^8.5.1",
2222
"morgan": "^1.10.0",
2323
"node-fetch": "^2.6.1",
24-
"socket.io": "^4.0.0",
25-
"veza": "^1.2.0"
24+
"socket.io": "^4.0.0"
2625
},
2726
"devDependencies": {
2827
"@types/express": "^4.17.11",

src/ipc-server.ts

Lines changed: 92 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,39 @@
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';
45
import { 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

1138
interface ChannelData {
1239
id: string;
@@ -29,59 +56,77 @@ interface UserData {
2956
}
3057

3158
export 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

5389
export 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

65104
export 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

76119
export 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

104151
type NotificationType = 'verification' | 'subscribed' | 'paid' | 'dms' | 'cancelled';
105152

106153
export 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+
};

yarn.lock

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -463,11 +463,6 @@ binary-extensions@^2.0.0:
463463
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522"
464464
integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
465465

466-
binarytf@^2.1.1:
467-
version "2.1.3"
468-
resolved "https://registry.yarnpkg.com/binarytf/-/binarytf-2.1.3.tgz#87ab823725526d14bb13ffab4ff5256875fba10e"
469-
integrity sha512-3r/lCKKXhyh06cIrFI0OlZmTcVyB2D4Nf87uGs0mfYeRhsv67z/MeIzDCmSeXo7kglBx0c3grfmbcsz5cSo0rQ==
470-
471466
472467
version "1.20.2"
473468
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
@@ -2426,13 +2421,6 @@ vary@^1, vary@~1.1.2:
24262421
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
24272422
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
24282423

2429-
veza@^1.2.0:
2430-
version "1.2.0"
2431-
resolved "https://registry.yarnpkg.com/veza/-/veza-1.2.0.tgz#8ad3ffe90b6272d513ccdff951f60e91c0544101"
2432-
integrity sha512-Ei91fQ5ymWFwwkqKA1mU4sfqgYeFVxPHSnzvXzjuCdsxSj2omesfJcBAlqHQIf8NbeS14o0eegh+0dVATavN3A==
2433-
dependencies:
2434-
binarytf "^2.1.1"
2435-
24362424
webidl-conversions@^3.0.0:
24372425
version "3.0.1"
24382426
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"

0 commit comments

Comments
 (0)