fix: temporally using ws

This commit is contained in:
MARCROCK22 2024-08-09 16:18:27 +00:00
parent a337862938
commit 983043f9c3
6 changed files with 108 additions and 55 deletions

View File

@ -22,7 +22,8 @@
"author": "MARCROCK22", "author": "MARCROCK22",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"magic-bytes.js": "^1.10.0" "magic-bytes.js": "^1.10.0",
"ws": "^8.18.0"
}, },
"lint-staged": { "lint-staged": {
"*.ts": [ "*.ts": [
@ -34,6 +35,7 @@
"@commitlint/cli": "^19.3.0", "@commitlint/cli": "^19.3.0",
"@commitlint/config-conventional": "^19.2.2", "@commitlint/config-conventional": "^19.2.2",
"@types/node": "^20.14.11", "@types/node": "^20.14.11",
"@types/ws": "^8.5.12",
"husky": "^9.1.1", "husky": "^9.1.1",
"lint-staged": "^15.2.7", "lint-staged": "^15.2.7",
"rimraf": "5.0.9", "rimraf": "5.0.9",

27
pnpm-lock.yaml generated
View File

@ -11,6 +11,9 @@ importers:
magic-bytes.js: magic-bytes.js:
specifier: ^1.10.0 specifier: ^1.10.0
version: 1.10.0 version: 1.10.0
ws:
specifier: ^8.18.0
version: 8.18.0
optionalDependencies: optionalDependencies:
chokidar: chokidar:
specifier: ^3.6.0 specifier: ^3.6.0
@ -37,6 +40,9 @@ importers:
'@types/node': '@types/node':
specifier: ^20.14.11 specifier: ^20.14.11
version: 20.14.11 version: 20.14.11
'@types/ws':
specifier: ^8.5.12
version: 8.5.12
husky: husky:
specifier: ^9.1.1 specifier: ^9.1.1
version: 9.1.1 version: 9.1.1
@ -203,6 +209,9 @@ packages:
'@types/node@20.14.11': '@types/node@20.14.11':
resolution: {integrity: sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==} resolution: {integrity: sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==}
'@types/ws@8.5.12':
resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==}
JSONStream@1.3.5: JSONStream@1.3.5:
resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==}
hasBin: true hasBin: true
@ -865,6 +874,18 @@ packages:
resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==}
engines: {node: '>=18'} engines: {node: '>=18'}
ws@8.18.0:
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
y18n@5.0.8: y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -1071,6 +1092,10 @@ snapshots:
dependencies: dependencies:
undici-types: 5.26.5 undici-types: 5.26.5
'@types/ws@8.5.12':
dependencies:
'@types/node': 20.14.11
JSONStream@1.3.5: JSONStream@1.3.5:
dependencies: dependencies:
jsonparse: 1.3.1 jsonparse: 1.3.1
@ -1682,6 +1707,8 @@ snapshots:
string-width: 7.2.0 string-width: 7.2.0
strip-ansi: 7.1.0 strip-ansi: 7.1.0
ws@8.18.0: {}
y18n@5.0.8: {} y18n@5.0.8: {}
yaml@2.4.5: {} yaml@2.4.5: {}

View File

@ -1,58 +1,60 @@
import { randomUUID } from 'node:crypto'; import { randomUUID } from 'node:crypto';
import { SeyfertWebSocket } from './socket/custom'; // import { SeyfertWebSocket } from './socket/custom';
import { WebSocket as NodeJSWebSocket } from 'ws';
export class BaseSocket { export class BaseSocket {
private internal: SeyfertWebSocket | WebSocket; private internal: NodeJSWebSocket | WebSocket;
ping?: () => Promise<number>; ping?: () => Promise<number>;
constructor(kind: 'ws' | 'bun', url: string) { constructor(kind: 'ws' | 'bun', url: string) {
this.internal = kind === 'ws' ? new SeyfertWebSocket(url) : new WebSocket(url); this.internal = kind === 'ws' ? new NodeJSWebSocket(url) : new WebSocket(url);
// this.internal = kind === 'ws' ? new SeyfertWebSocket(url) : new WebSocket(url);
if (kind === 'ws') { // if (kind === 'ws') {
const ws = this.internal as SeyfertWebSocket; // const ws = this.internal as NodeJSWebSocket;
this.ping = ws.waitPing.bind(ws); // this.ping = ws.waitPing.bind(ws);
ws.onpong = data => { // ws.onpong = data => {
const promise = ws.__promises.get(data); // const promise = ws.__promises.get(data);
if (promise) { // if (promise) {
ws.__promises.delete(data); // ws.__promises.delete(data);
promise?.resolve(); // promise?.resolve();
} // }
}; // };
} else { // } else {
const ws = this.internal as WebSocket; const ws = this.internal as WebSocket;
this.ping = () => { this.ping = () => {
return new Promise<number>(res => { return new Promise<number>(res => {
const nonce = randomUUID(); const nonce = randomUUID();
const start = performance.now(); const start = performance.now();
const listener = (data: Buffer) => { const listener = (data: Buffer) => {
if (data.toString() !== nonce) return; if (data.toString() !== nonce) return;
//@ts-expect-error bun support
ws.removeListener('pong', listener);
res(performance.now() - start);
};
//@ts-expect-error bun support //@ts-expect-error bun support
ws.on('pong', listener); ws.removeListener('pong', listener);
//@ts-expect-error bun support res(performance.now() - start);
ws.ping(nonce); };
}); //@ts-expect-error bun support
}; ws.on('pong', listener);
} //@ts-expect-error bun support
ws.ping(nonce);
});
};
// }
} }
set onopen(callback: SeyfertWebSocket['onopen']) { set onopen(callback: NodeJSWebSocket['onopen']) {
this.internal.onopen = callback; this.internal.onopen = callback;
} }
set onmessage(callback: SeyfertWebSocket['onmessage']) { set onmessage(callback: NodeJSWebSocket['onmessage']) {
this.internal.onmessage = callback; this.internal.onmessage = callback;
} }
set onclose(callback: SeyfertWebSocket['onclose']) { set onclose(callback: NodeJSWebSocket['onclose']) {
this.internal.onclose = callback; this.internal.onclose = callback;
} }
set onerror(callback: SeyfertWebSocket['onerror']) { set onerror(callback: NodeJSWebSocket['onerror']) {
this.internal.onerror = callback; this.internal.onerror = callback;
} }
@ -60,7 +62,8 @@ export class BaseSocket {
return this.internal.send(data); return this.internal.send(data);
} }
close(...args: Parameters<SeyfertWebSocket['close']>) { close(...args: Parameters<NodeJSWebSocket['close']>) {
//@ts-expect-error
return this.internal.close(...args); return this.internal.close(...args);
} }

View File

@ -25,7 +25,7 @@ export interface ShardHeart {
export class Shard { export class Shard {
debugger?: Logger; debugger?: Logger;
data: Partial<ShardData> | ShardData = { data: Partial<ShardData> | ShardData = {
resumeSeq: null, resume_seq: null,
}; };
websocket: BaseSocket | null = null; websocket: BaseSocket | null = null;
@ -95,18 +95,20 @@ export class Shard {
return; return;
} }
clearTimeout(this.heart.nodeInterval);
this.debugger?.debug(`[Shard #${this.id}] Connecting to ${this.currentGatewayURL}`); this.debugger?.debug(`[Shard #${this.id}] Connecting to ${this.currentGatewayURL}`);
// @ts-expect-error @types/bun cause erros in compile // @ts-expect-error @types/bun cause erros in compile
// biome-ignore lint/correctness/noUndeclaredVariables: /\ bun lol // biome-ignore lint/correctness/noUndeclaredVariables: /\ bun lol
this.websocket = new BaseSocket(typeof Bun === 'undefined' ? 'ws' : 'bun', this.currentGatewayURL); this.websocket = new BaseSocket(typeof Bun === 'undefined' ? 'ws' : 'bun', this.currentGatewayURL);
//@ts-expect-error
this.websocket!.onmessage = ({ data }: { data: string | Buffer }) => { this.websocket!.onmessage = ({ data }: { data: string | Buffer }) => {
this.handleMessage(data); this.handleMessage(data);
}; };
this.websocket!.onclose = (event: { code: number; reason: string }) => this.handleClosed(event); this.websocket!.onclose = (event: { code: number; reason: string }) => this.handleClosed(event);
//@ts-expect-error
this.websocket!.onerror = (event: ErrorEvent) => this.debugger?.error(event); this.websocket!.onerror = (event: ErrorEvent) => this.debugger?.error(event);
this.websocket!.onopen = () => { this.websocket!.onopen = () => {
@ -150,14 +152,14 @@ export class Shard {
} }
get resumable() { get resumable() {
return !!(this.data.resume_gateway_url && this.data.session_id && this.data.resumeSeq !== null); return !!(this.data.resume_gateway_url && this.data.session_id && this.data.resume_seq !== null);
} }
async resume() { async resume() {
await this.send(true, { await this.send(true, {
op: GatewayOpcodes.Resume, op: GatewayOpcodes.Resume,
d: { d: {
seq: this.data.resumeSeq!, seq: this.data.resume_seq!,
session_id: this.data.session_id!, session_id: this.data.session_id!,
token: `Bot ${this.options.token}`, token: `Bot ${this.options.token}`,
}, },
@ -181,7 +183,7 @@ export class Shard {
this.websocket!.send( this.websocket!.send(
JSON.stringify({ JSON.stringify({
op: GatewayOpcodes.Heartbeat, op: GatewayOpcodes.Heartbeat,
d: this.data.resumeSeq ?? null, d: this.data.resume_seq ?? null,
}), }),
); );
} }
@ -199,10 +201,10 @@ export class Shard {
async onpacket(packet: GatewayReceivePayload) { async onpacket(packet: GatewayReceivePayload) {
if (packet.s !== null) { if (packet.s !== null) {
this.data.resumeSeq = packet.s; this.data.resume_seq = packet.s;
} }
this.debugger?.debug(`[Shard #${this.id}]`, packet.t ? packet.t : GatewayOpcodes[packet.op], this.data.resumeSeq); this.debugger?.debug(`[Shard #${this.id}]`, packet.t ? packet.t : GatewayOpcodes[packet.op], this.data.resume_seq);
switch (packet.op) { switch (packet.op) {
case GatewayOpcodes.Hello: case GatewayOpcodes.Hello:
@ -237,7 +239,7 @@ export class Shard {
} }
await this.resume(); await this.resume();
} else { } else {
this.data.resumeSeq = 0; this.data.resume_seq = 0;
this.data.session_id = undefined; this.data.session_id = undefined;
await this.identify(); await this.identify();
} }
@ -277,17 +279,22 @@ export class Shard {
//Force disconnect, ignore //Force disconnect, ignore
break; break;
case 1000: case 1000:
case GatewayCloseCodes.UnknownOpcode:
case GatewayCloseCodes.InvalidSeq:
case GatewayCloseCodes.SessionTimedOut:
this.data.resume_seq = 0;
this.data.session_id = undefined;
this.data.resume_gateway_url = undefined;
await this.reconnect();
break;
case 1001: case 1001:
case 1006: case 1006:
case ShardSocketCloseCodes.ZombiedConnection: case ShardSocketCloseCodes.ZombiedConnection:
case GatewayCloseCodes.UnknownError: case GatewayCloseCodes.UnknownError:
case GatewayCloseCodes.UnknownOpcode:
case GatewayCloseCodes.DecodeError: case GatewayCloseCodes.DecodeError:
case GatewayCloseCodes.NotAuthenticated: case GatewayCloseCodes.NotAuthenticated:
case GatewayCloseCodes.AlreadyAuthenticated: case GatewayCloseCodes.AlreadyAuthenticated:
case GatewayCloseCodes.InvalidSeq:
case GatewayCloseCodes.RateLimited: case GatewayCloseCodes.RateLimited:
case GatewayCloseCodes.SessionTimedOut:
this.debugger?.info(`[Shard #${this.id}] Trying to reconnect`); this.debugger?.info(`[Shard #${this.id}] Trying to reconnect`);
await this.reconnect(); await this.reconnect();
break; break;

View File

@ -66,7 +66,7 @@ export interface WorkerManagerOptions extends Omit<ShardManagerOptions, 'handleP
export interface ShardData { export interface ShardData {
/** resume seq to resume connections */ /** resume seq to resume connections */
resumeSeq: number | null; resume_seq: number | null;
/** /**
* resume_gateway_url is the url to resume the connection * resume_gateway_url is the url to resume the connection

View File

@ -15,6 +15,10 @@ export class SeyfertWebSocket {
reject: (reason?: any) => void; reject: (reason?: any) => void;
} }
>(); >();
__lastError: null | {
code: number;
reason: string;
} = null;
constructor( constructor(
url: string, url: string,
@ -55,6 +59,10 @@ export class SeyfertWebSocket {
this.handleReadable(); this.handleReadable();
}); });
socket.on('close', () => {
this.handleClose();
});
socket.on('error', err => { socket.on('error', err => {
this.onerror(err); this.onerror(err);
}); });
@ -135,15 +143,21 @@ export class SeyfertWebSocket {
break; break;
// close // close
case 0x8: case 0x8:
{ this.__lastError = {
const code = body.readUInt16BE(0); code: body.readUInt16BE(0),
const reason = body.subarray(2).toString(); reason: body.subarray(2).toString(),
this.onclose({ code, reason }); };
} this.socket?.destroy();
break; break;
} }
} }
handleClose() {
if (!this.__lastError) return this.connect();
this.onclose(this.__lastError);
this.__lastError = null;
}
send(data: string) { send(data: string) {
this._write(Buffer.from(data), 1); this._write(Buffer.from(data), 1);
} }