seyfert 4.3.0 → 4.3.1-dev-24757643741.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -22,6 +22,8 @@ export declare class Shard {
|
|
|
22
22
|
websocket: BaseSocket | null;
|
|
23
23
|
connectTimeout: ConnectTimeout;
|
|
24
24
|
heart: ShardHeart;
|
|
25
|
+
private isConnecting;
|
|
26
|
+
private reconnectPromise;
|
|
25
27
|
bucket: DynamicBucket;
|
|
26
28
|
offlineSendQueue: ((_?: unknown) => void)[];
|
|
27
29
|
pendingGuilds?: Set<string>;
|
|
@@ -44,6 +46,7 @@ export declare class Shard {
|
|
|
44
46
|
heartbeat(requested: boolean): void;
|
|
45
47
|
disconnect(code?: ShardSocketCloseCodes): void;
|
|
46
48
|
reconnect(code?: ShardSocketCloseCodes): Promise<void>;
|
|
49
|
+
private flushOfflineSendQueue;
|
|
47
50
|
onpacket(packet: GatewayReceivePayload): void | Promise<void>;
|
|
48
51
|
requestGuildMember(options: Omit<GatewayRequestGuildMembersDataWithQuery, 'nonce'> | Omit<GatewayRequestGuildMembersDataWithUserIds, 'nonce'>): Promise<{
|
|
49
52
|
members: APIGuildMember[];
|
|
@@ -22,6 +22,8 @@ class Shard {
|
|
|
22
22
|
interval: 30e3,
|
|
23
23
|
ack: true,
|
|
24
24
|
};
|
|
25
|
+
isConnecting = false;
|
|
26
|
+
reconnectPromise;
|
|
25
27
|
bucket;
|
|
26
28
|
offlineSendQueue = [];
|
|
27
29
|
pendingGuilds;
|
|
@@ -74,9 +76,15 @@ class Shard {
|
|
|
74
76
|
return this.websocket.ping();
|
|
75
77
|
}
|
|
76
78
|
async connect() {
|
|
79
|
+
if (this.isConnecting) {
|
|
80
|
+
this.debugger?.debug(`[Shard #${this.id}] Already connecting, skipping`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
this.isConnecting = true;
|
|
77
84
|
await this.connectTimeout.wait();
|
|
78
85
|
if (this.isOpen) {
|
|
79
86
|
this.debugger?.debug(`[Shard #${this.id}] Attempted to connect while open`);
|
|
87
|
+
this.isConnecting = false;
|
|
80
88
|
return;
|
|
81
89
|
}
|
|
82
90
|
clearTimeout(this.heart.nodeInterval);
|
|
@@ -90,6 +98,7 @@ class Shard {
|
|
|
90
98
|
this.websocket.onclose = (event) => this.handleClosed(event);
|
|
91
99
|
this.websocket.onerror = (event) => this.logger.error(event);
|
|
92
100
|
this.websocket.onopen = () => {
|
|
101
|
+
this.isConnecting = false;
|
|
93
102
|
this.heart.ack = true;
|
|
94
103
|
void this.options.onShardReconnect?.({ shardId: this.id });
|
|
95
104
|
};
|
|
@@ -159,14 +168,24 @@ class Shard {
|
|
|
159
168
|
clearTimeout(this.connectionTimeout);
|
|
160
169
|
this.connectionTimeout = undefined;
|
|
161
170
|
clearTimeout(this.heart.ackTimeout);
|
|
171
|
+
this.isConnecting = false;
|
|
162
172
|
this.debugger?.info(`[Shard #${this.id}] Disconnecting`);
|
|
163
173
|
this.close(code, 'Shard down request');
|
|
164
174
|
}
|
|
165
175
|
async reconnect(code = shared_1.ShardSocketCloseCodes.Reconnect) {
|
|
166
|
-
this.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
176
|
+
return (this.reconnectPromise ??= (async () => {
|
|
177
|
+
this.debugger?.info(`[Shard #${this.id}] Reconnecting`);
|
|
178
|
+
this.disconnect(code);
|
|
179
|
+
await (0, common_1.delay)(this.options.reconnectTimeout);
|
|
180
|
+
await this.connect();
|
|
181
|
+
})().finally(() => {
|
|
182
|
+
this.reconnectPromise = undefined;
|
|
183
|
+
}));
|
|
184
|
+
}
|
|
185
|
+
flushOfflineSendQueue() {
|
|
186
|
+
const queue = this.offlineSendQueue.splice(0);
|
|
187
|
+
for (const resolve of queue)
|
|
188
|
+
resolve();
|
|
170
189
|
}
|
|
171
190
|
onpacket(packet) {
|
|
172
191
|
if (packet.s !== null) {
|
|
@@ -217,8 +236,7 @@ class Shard {
|
|
|
217
236
|
clearTimeout(this.connectionTimeout);
|
|
218
237
|
this.connectionTimeout = undefined;
|
|
219
238
|
this.isReady = true;
|
|
220
|
-
|
|
221
|
-
resolve();
|
|
239
|
+
this.flushOfflineSendQueue();
|
|
222
240
|
this.options.handlePayload(this.id, packet);
|
|
223
241
|
}
|
|
224
242
|
break;
|
|
@@ -230,8 +248,7 @@ class Shard {
|
|
|
230
248
|
}
|
|
231
249
|
this.data.resume_gateway_url = packet.d.resume_gateway_url;
|
|
232
250
|
this.data.session_id = packet.d.session_id;
|
|
233
|
-
|
|
234
|
-
resolve();
|
|
251
|
+
this.flushOfflineSendQueue();
|
|
235
252
|
this.options.handlePayload(this.id, packet);
|
|
236
253
|
if (this.pendingGuilds?.size === 0) {
|
|
237
254
|
this.isReady = true;
|
|
@@ -427,7 +444,7 @@ class Shard {
|
|
|
427
444
|
}
|
|
428
445
|
close(code, reason) {
|
|
429
446
|
clearInterval(this.heart.nodeInterval);
|
|
430
|
-
if (!this.
|
|
447
|
+
if (!this.websocket) {
|
|
431
448
|
return this.debugger?.warn(`[Shard #${this.id}] Is not open, reason:`, reason);
|
|
432
449
|
}
|
|
433
450
|
this.debugger?.debug(`[Shard #${this.id}] Called close with reason:`, reason);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ClientRequest } from 'node:http';
|
|
1
2
|
import type { Socket } from 'node:net';
|
|
2
3
|
export declare class SeyfertWebSocket {
|
|
3
4
|
#private;
|
|
@@ -15,6 +16,8 @@ export declare class SeyfertWebSocket {
|
|
|
15
16
|
reason: string;
|
|
16
17
|
};
|
|
17
18
|
__closeCalled?: boolean;
|
|
19
|
+
request?: ClientRequest;
|
|
20
|
+
retryTimeout?: NodeJS.Timeout;
|
|
18
21
|
constructor(url: string);
|
|
19
22
|
private connect;
|
|
20
23
|
handleReadable(): void;
|
|
@@ -13,6 +13,9 @@ class SeyfertWebSocket {
|
|
|
13
13
|
__promises = new Map();
|
|
14
14
|
__lastError = null;
|
|
15
15
|
__closeCalled;
|
|
16
|
+
request;
|
|
17
|
+
retryTimeout;
|
|
18
|
+
#closeEmitted = false;
|
|
16
19
|
constructor(url) {
|
|
17
20
|
const urlParts = new URL(url);
|
|
18
21
|
this.hostname = urlParts.hostname || '';
|
|
@@ -33,7 +36,16 @@ class SeyfertWebSocket {
|
|
|
33
36
|
'Sec-WebSocket-Version': '13',
|
|
34
37
|
},
|
|
35
38
|
});
|
|
39
|
+
this.request = req;
|
|
36
40
|
req.on('upgrade', (res, socket) => {
|
|
41
|
+
if (this.request === req) {
|
|
42
|
+
this.request = undefined;
|
|
43
|
+
}
|
|
44
|
+
if (this.__closeCalled) {
|
|
45
|
+
socket.destroy();
|
|
46
|
+
resolve();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
37
49
|
const hash = (0, node_crypto_1.createHash)('sha1').update(`${key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11`).digest('base64');
|
|
38
50
|
const accept = res.headers['sec-websocket-accept'];
|
|
39
51
|
if (accept !== hash) {
|
|
@@ -52,20 +64,34 @@ class SeyfertWebSocket {
|
|
|
52
64
|
this.onopen();
|
|
53
65
|
});
|
|
54
66
|
req.on('close', () => {
|
|
67
|
+
if (this.request === req) {
|
|
68
|
+
this.request = undefined;
|
|
69
|
+
}
|
|
55
70
|
req.removeAllListeners();
|
|
56
71
|
});
|
|
57
72
|
req.on('error', e => {
|
|
73
|
+
if (this.request === req) {
|
|
74
|
+
this.request = undefined;
|
|
75
|
+
}
|
|
76
|
+
if (this.__closeCalled) {
|
|
77
|
+
resolve();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
58
80
|
if (retries < 5) {
|
|
59
|
-
setTimeout(() => {
|
|
81
|
+
this.retryTimeout = setTimeout(() => {
|
|
82
|
+
this.retryTimeout = undefined;
|
|
83
|
+
if (this.__closeCalled) {
|
|
84
|
+
resolve();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
60
87
|
resolve(this.connect(retries + 1));
|
|
61
88
|
}, 500);
|
|
89
|
+
return;
|
|
62
90
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}, 5e3);
|
|
68
|
-
}
|
|
91
|
+
this.onerror(e);
|
|
92
|
+
this.__lastError = { code: 1006, reason: e.message };
|
|
93
|
+
resolve();
|
|
94
|
+
this.#emitClose(this.__lastError);
|
|
69
95
|
});
|
|
70
96
|
req.end();
|
|
71
97
|
});
|
|
@@ -135,19 +161,19 @@ class SeyfertWebSocket {
|
|
|
135
161
|
this.onmessage({ data: body });
|
|
136
162
|
}
|
|
137
163
|
break;
|
|
138
|
-
//
|
|
164
|
+
// ping
|
|
139
165
|
case 0x9:
|
|
140
166
|
this.onping(body.toString());
|
|
141
167
|
break;
|
|
142
|
-
//
|
|
168
|
+
// pong
|
|
143
169
|
case 0xa:
|
|
144
170
|
this.onpong(body.toString());
|
|
145
171
|
break;
|
|
146
172
|
// close
|
|
147
173
|
case 0x8:
|
|
148
174
|
this.__lastError = {
|
|
149
|
-
code: body.readUInt16BE(0),
|
|
150
|
-
reason: body.subarray(2).toString(),
|
|
175
|
+
code: body.length >= 2 ? body.readUInt16BE(0) : 1005,
|
|
176
|
+
reason: body.length > 2 ? body.subarray(2).toString() : '',
|
|
151
177
|
};
|
|
152
178
|
break;
|
|
153
179
|
}
|
|
@@ -158,9 +184,10 @@ class SeyfertWebSocket {
|
|
|
158
184
|
this.socket = undefined;
|
|
159
185
|
if (this.__closeCalled)
|
|
160
186
|
return;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
187
|
+
this.#emitClose(this.__lastError ?? {
|
|
188
|
+
code: 1006,
|
|
189
|
+
reason: 'Socket closed without a close frame',
|
|
190
|
+
});
|
|
164
191
|
this.__lastError = null;
|
|
165
192
|
}
|
|
166
193
|
send(data) {
|
|
@@ -193,7 +220,7 @@ class SeyfertWebSocket {
|
|
|
193
220
|
this.socket?.write(frame);
|
|
194
221
|
}
|
|
195
222
|
onping(_data) {
|
|
196
|
-
|
|
223
|
+
this.pong(_data);
|
|
197
224
|
}
|
|
198
225
|
onpong(_data) {
|
|
199
226
|
//
|
|
@@ -212,6 +239,10 @@ class SeyfertWebSocket {
|
|
|
212
239
|
}
|
|
213
240
|
close(code, reason) {
|
|
214
241
|
this.__closeCalled = true;
|
|
242
|
+
clearTimeout(this.retryTimeout);
|
|
243
|
+
this.retryTimeout = undefined;
|
|
244
|
+
this.request?.destroy();
|
|
245
|
+
this.request = undefined;
|
|
215
246
|
// alloc payload length
|
|
216
247
|
const buffer = Buffer.alloc(2 + Buffer.byteLength(reason));
|
|
217
248
|
// gateway close code
|
|
@@ -221,7 +252,13 @@ class SeyfertWebSocket {
|
|
|
221
252
|
// message, close opcode
|
|
222
253
|
this._write(buffer, 0x8);
|
|
223
254
|
this.socket?.end();
|
|
224
|
-
this
|
|
255
|
+
this.#emitClose({ code, reason });
|
|
256
|
+
}
|
|
257
|
+
#emitClose(close) {
|
|
258
|
+
if (this.#closeEmitted)
|
|
259
|
+
return;
|
|
260
|
+
this.#closeEmitted = true;
|
|
261
|
+
this.onclose(close);
|
|
225
262
|
}
|
|
226
263
|
pong(data) {
|
|
227
264
|
//send pong opcode (10)
|
|
@@ -259,6 +296,8 @@ class SeyfertWebSocket {
|
|
|
259
296
|
return id;
|
|
260
297
|
}
|
|
261
298
|
get readyState() {
|
|
299
|
+
if (this.request || this.retryTimeout)
|
|
300
|
+
return 0;
|
|
262
301
|
return ['opening', 'open', 'closed', 'closed'].indexOf(this.socket?.readyState ?? 'closed');
|
|
263
302
|
}
|
|
264
303
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "seyfert",
|
|
3
|
-
"version": "4.3.0",
|
|
3
|
+
"version": "4.3.1-dev-24757643741.0",
|
|
4
4
|
"description": "The most advanced framework for discord bots",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"module": "./lib/index.js",
|
|
@@ -70,4 +70,4 @@
|
|
|
70
70
|
"esbuild"
|
|
71
71
|
]
|
|
72
72
|
}
|
|
73
|
-
}
|
|
73
|
+
}
|