Skip to content

Commit 2d4ea8a

Browse files
committed
Use better socket implementation, update deps
1 parent f03ea6f commit 2d4ea8a

File tree

5 files changed

+170
-97
lines changed

5 files changed

+170
-97
lines changed

.eslintrc.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,32 @@ const prettierOptions = JSON.parse(
55
fs.readFileSync(path.resolve(__dirname, '.prettierrc'), 'utf8')
66
);
77

8+
/** @type {import("@types/eslint").Linter.Config} */
89
module.exports = {
910
env: {
10-
es2021: true,
11-
node: true,
11+
es2022: true,
12+
node: true
1213
},
1314
extends: [
1415
'eslint:recommended',
1516
'plugin:@typescript-eslint/recommended',
16-
'plugin:prettier/recommended',
17+
'plugin:prettier/recommended'
1718
],
1819
parser: '@typescript-eslint/parser',
1920
parserOptions: {
20-
ecmaVersion: 12,
21-
sourceType: 'module',
21+
ecmaVersion: 'latest',
22+
sourceType: 'module'
2223
},
2324
plugins: ['@typescript-eslint', 'prettier', 'eslint-plugin-tsdoc'],
2425
ignorePatterns: ['dist', '.eslintrc.js'],
2526
rules: {
2627
'prettier/prettier': ['error', prettierOptions],
27-
'tsdoc/syntax': 'warn',
28+
'tsdoc/syntax': 'warn'
2829
},
2930
overrides: [
3031
{
3132
files: ['**/*.ts'],
32-
rules: { 'prettier/prettier': ['error', prettierOptions] },
33-
},
34-
],
33+
rules: { 'prettier/prettier': ['error', prettierOptions] }
34+
}
35+
]
3536
};

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@
3636
},
3737
"homepage": "https://jspteroapi.linux123123.com",
3838
"dependencies": {
39-
"sockette": "^2.0.6",
4039
"undici": "^5.9.1",
4140
"ws": "^8.8.1"
4241
},
4342
"devDependencies": {
4443
"@microsoft/tsdoc-config": "^0.16.1",
45-
"@types/node": "^18.7.8",
46-
"@typescript-eslint/eslint-plugin": "^5.33.1",
47-
"@typescript-eslint/parser": "^5.33.1",
44+
"@types/node": "^18.7.11",
45+
"@types/ws": "^8.5.3",
46+
"@typescript-eslint/eslint-plugin": "^5.34.0",
47+
"@typescript-eslint/parser": "^5.34.0",
4848
"eslint": "^8.22.0",
4949
"eslint-config-prettier": "^8.5.0",
5050
"eslint-plugin-prettier": "^4.2.1",

src/client/Websocket.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
11
/** @module ClientWebsocket */
22

3-
import Sockette from 'sockette';
43
import { EventEmitter } from 'events';
54
import { WebsocketAuthData } from './interfaces/WebsocketAuthData';
65
import { JSPteroAPIError } from '../modules/Error';
6+
import { Socket } from '../modules/Socket';
77

88
const reconnectErrors = [
99
'jwt: exp claim is invalid',
1010
'jwt: created too far in past (denylist)'
1111
];
1212

13-
global.WebSocket = require('ws');
14-
15-
// Code mostly from pterodactyl websocket implementation
16-
1713
export class WebsocketClient extends EventEmitter {
1814
constructor(
1915
errorHandler: (error: JSPteroAPIError) => void,
@@ -59,7 +55,7 @@ export class WebsocketClient extends EventEmitter {
5955
private backoff = 5000;
6056

6157
// The socket instance being tracked.
62-
private socket: Sockette | null = null;
58+
private socket: Socket | null = null;
6359

6460
// The URL being connected to for the socket.
6561
private url: string | null = null;
@@ -75,10 +71,10 @@ export class WebsocketClient extends EventEmitter {
7571
private connect(url: string): this {
7672
this.url = url;
7773

78-
this.socket = new Sockette(this.url, {
74+
this.socket = new Socket(this.url, {
7975
onmessage: (e) => {
8076
try {
81-
const { event, args } = JSON.parse(e.data);
77+
const { event, args } = JSON.parse(e.data.toString());
8278
args ? this.emit(event, ...args) : this.emit(event);
8379
} catch (ex) {
8480
console.warn('Failed to parse incoming websocket message.', ex);
@@ -97,13 +93,16 @@ export class WebsocketClient extends EventEmitter {
9793
this.authenticate();
9894
},
9995
onclose: () => this.emit('SOCKET_CLOSE'),
100-
onerror: (event: Event) => {
96+
onerror: (event) => {
10197
if (
102-
(event as ErrorEvent).message ===
98+
event.message ===
10399
'WebSocket was closed before the connection was established'
104100
)
105101
return;
106-
throw new Error((event as ErrorEvent).message);
102+
throw new Error(event.message);
103+
},
104+
onmaximum: () => {
105+
return;
107106
}
108107
});
109108

src/modules/Socket.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { WebSocket, Event, MessageEvent, CloseEvent, ErrorEvent } from 'ws';
2+
3+
export class Socket {
4+
constructor(
5+
private readonly url: string,
6+
private readonly options: {
7+
onopen: (this: Socket, ev: Event) => void;
8+
onmessage: (this: Socket, ev: MessageEvent) => void;
9+
onreconnect: (this: Socket, ev: Event | CloseEvent | ErrorEvent) => void;
10+
onmaximum: (this: Socket, ev: CloseEvent | ErrorEvent) => void;
11+
onclose: (this: Socket, ev: CloseEvent) => void;
12+
onerror: (this: Socket, ev: ErrorEvent) => void;
13+
}
14+
) {
15+
this.open();
16+
}
17+
18+
declare ws: WebSocket;
19+
declare timer: NodeJS.Timeout;
20+
private reconnectNum = 0;
21+
22+
public open = () => {
23+
const options = this.options;
24+
const reconnect = this.reconnect;
25+
this.ws = new WebSocket(this.url);
26+
27+
this.ws.onmessage = options.onmessage;
28+
29+
const onOpen = options.onopen.bind(this);
30+
this.ws.onopen = (e) => {
31+
onOpen(e);
32+
this.reconnectNum = 0;
33+
};
34+
35+
const onClose = options.onclose.bind(this);
36+
this.ws.onclose = function (e) {
37+
e.code === 1e3 || e.code === 1001 || e.code === 1005 || reconnect(e);
38+
onClose(e);
39+
};
40+
41+
const onError = options.onerror.bind(this);
42+
this.ws.onerror = function (e) {
43+
e && (e as unknown as Record<string, string>).code === 'ECONNREFUSED'
44+
? reconnect(e)
45+
: onError(e);
46+
};
47+
};
48+
49+
private reconnect = (e: CloseEvent | ErrorEvent) => {
50+
const onReconnect = this.options.onreconnect.bind(this);
51+
const onMaximum = this.options.onmaximum.bind(this);
52+
53+
const open = this.open;
54+
if (this.timer && this.reconnectNum++ < Infinity) {
55+
this.timer = setTimeout(function () {
56+
onReconnect(e);
57+
open();
58+
}, 1e3);
59+
} else {
60+
onMaximum(e);
61+
}
62+
};
63+
64+
public json = (x: unknown) => {
65+
this.ws.send(JSON.stringify(x));
66+
};
67+
68+
public send = (x: unknown) => {
69+
this.ws.send(x);
70+
};
71+
72+
public close = (x?: number, y?: string | Buffer) => {
73+
clearTimeout(this.timer);
74+
this.ws.close(x || 1e3, y);
75+
};
76+
}

0 commit comments

Comments
 (0)