diff --git a/.eslintrc.js b/.eslintrc.js index f584458d..6cde6081 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,31 +5,32 @@ const prettierOptions = JSON.parse( fs.readFileSync(path.resolve(__dirname, '.prettierrc'), 'utf8') ); +/** @type {import("@types/eslint").Linter.Config} */ module.exports = { env: { - es2021: true, - node: true, + es2022: true, + node: true }, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', - 'plugin:prettier/recommended', + 'plugin:prettier/recommended' ], parser: '@typescript-eslint/parser', parserOptions: { - ecmaVersion: 12, - sourceType: 'module', + ecmaVersion: 'latest', + sourceType: 'module' }, plugins: ['@typescript-eslint', 'prettier', 'eslint-plugin-tsdoc'], ignorePatterns: ['dist', '.eslintrc.js'], rules: { 'prettier/prettier': ['error', prettierOptions], - 'tsdoc/syntax': 'warn', + 'tsdoc/syntax': 'warn' }, overrides: [ { files: ['**/*.ts'], - rules: { 'prettier/prettier': ['error', prettierOptions] }, - }, - ], + rules: { 'prettier/prettier': ['error', prettierOptions] } + } + ] }; diff --git a/package.json b/package.json index 4e430d38..c67c362b 100644 --- a/package.json +++ b/package.json @@ -36,15 +36,15 @@ }, "homepage": "https://jspteroapi.linux123123.com", "dependencies": { - "sockette": "^2.0.6", "undici": "^5.9.1", "ws": "^8.8.1" }, "devDependencies": { "@microsoft/tsdoc-config": "^0.16.1", - "@types/node": "^18.7.8", - "@typescript-eslint/eslint-plugin": "^5.33.1", - "@typescript-eslint/parser": "^5.33.1", + "@types/node": "^18.7.11", + "@types/ws": "^8.5.3", + "@typescript-eslint/eslint-plugin": "^5.34.0", + "@typescript-eslint/parser": "^5.34.0", "eslint": "^8.22.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-prettier": "^4.2.1", diff --git a/src/client/Websocket.ts b/src/client/Websocket.ts index c186a8e3..2f472aaa 100644 --- a/src/client/Websocket.ts +++ b/src/client/Websocket.ts @@ -1,19 +1,15 @@ /** @module ClientWebsocket */ -import Sockette from 'sockette'; import { EventEmitter } from 'events'; import { WebsocketAuthData } from './interfaces/WebsocketAuthData'; import { JSPteroAPIError } from '../modules/Error'; +import { Socket } from '../modules/Socket'; const reconnectErrors = [ 'jwt: exp claim is invalid', 'jwt: created too far in past (denylist)' ]; -global.WebSocket = require('ws'); - -// Code mostly from pterodactyl websocket implementation - export class WebsocketClient extends EventEmitter { constructor( errorHandler: (error: JSPteroAPIError) => void, @@ -59,7 +55,7 @@ export class WebsocketClient extends EventEmitter { private backoff = 5000; // The socket instance being tracked. - private socket: Sockette | null = null; + private socket: Socket | null = null; // The URL being connected to for the socket. private url: string | null = null; @@ -75,10 +71,10 @@ export class WebsocketClient extends EventEmitter { private connect(url: string): this { this.url = url; - this.socket = new Sockette(this.url, { + this.socket = new Socket(this.url, { onmessage: (e) => { try { - const { event, args } = JSON.parse(e.data); + const { event, args } = JSON.parse(e.data.toString()); args ? this.emit(event, ...args) : this.emit(event); } catch (ex) { console.warn('Failed to parse incoming websocket message.', ex); @@ -97,13 +93,16 @@ export class WebsocketClient extends EventEmitter { this.authenticate(); }, onclose: () => this.emit('SOCKET_CLOSE'), - onerror: (event: Event) => { + onerror: (event) => { if ( - (event as ErrorEvent).message === + event.message === 'WebSocket was closed before the connection was established' ) return; - throw new Error((event as ErrorEvent).message); + throw new Error(event.message); + }, + onmaximum: () => { + return; } }); diff --git a/src/modules/Socket.ts b/src/modules/Socket.ts new file mode 100644 index 00000000..817e18f3 --- /dev/null +++ b/src/modules/Socket.ts @@ -0,0 +1,76 @@ +import { WebSocket, Event, MessageEvent, CloseEvent, ErrorEvent } from 'ws'; + +export class Socket { + constructor( + private readonly url: string, + private readonly options: { + onopen: (this: Socket, ev: Event) => void; + onmessage: (this: Socket, ev: MessageEvent) => void; + onreconnect: (this: Socket, ev: Event | CloseEvent | ErrorEvent) => void; + onmaximum: (this: Socket, ev: CloseEvent | ErrorEvent) => void; + onclose: (this: Socket, ev: CloseEvent) => void; + onerror: (this: Socket, ev: ErrorEvent) => void; + } + ) { + this.open(); + } + + declare ws: WebSocket; + declare timer: NodeJS.Timeout; + private reconnectNum = 0; + + public open = () => { + const options = this.options; + const reconnect = this.reconnect; + this.ws = new WebSocket(this.url); + + this.ws.onmessage = options.onmessage; + + const onOpen = options.onopen.bind(this); + this.ws.onopen = (e) => { + onOpen(e); + this.reconnectNum = 0; + }; + + const onClose = options.onclose.bind(this); + this.ws.onclose = function (e) { + e.code === 1e3 || e.code === 1001 || e.code === 1005 || reconnect(e); + onClose(e); + }; + + const onError = options.onerror.bind(this); + this.ws.onerror = function (e) { + e && (e as unknown as Record).code === 'ECONNREFUSED' + ? reconnect(e) + : onError(e); + }; + }; + + private reconnect = (e: CloseEvent | ErrorEvent) => { + const onReconnect = this.options.onreconnect.bind(this); + const onMaximum = this.options.onmaximum.bind(this); + + const open = this.open; + if (this.timer && this.reconnectNum++ < Infinity) { + this.timer = setTimeout(function () { + onReconnect(e); + open(); + }, 1e3); + } else { + onMaximum(e); + } + }; + + public json = (x: unknown) => { + this.ws.send(JSON.stringify(x)); + }; + + public send = (x: unknown) => { + this.ws.send(x); + }; + + public close = (x?: number, y?: string | Buffer) => { + clearTimeout(this.timer); + this.ws.close(x || 1e3, y); + }; +} diff --git a/yarn.lock b/yarn.lock index 156cdd78..9402d463 100644 --- a/yarn.lock +++ b/yarn.lock @@ -166,15 +166,10 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== -"@types/node@*": - version "18.7.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.3.tgz#432c89796eab539b7a30b7b8801a727b585238a4" - integrity sha512-LJgzOEwWuMTBxHzgBR/fhhBOWrvBjvO+zPteUgbbuQi80rYIZHrk1mNbRUqPZqSLP2H7Rwt1EFLL/tNLD1Xx/w== - -"@types/node@^18.7.8": - version "18.7.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.8.tgz#6bbf2be6fbf9c187a5040d4277d24a06a18957a1" - integrity sha512-/YP55EMK2341JkODUb8DM9O0x1SIz2aBvyF33Uf1c76St3VpsMXEIW0nxuKkq/5cxnbz0RD9cfwNZHEAZQD3ag== +"@types/node@*", "@types/node@^18.7.11": + version "18.7.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.11.tgz#486e72cfccde88da24e1f23ff1b7d8bfb64e6250" + integrity sha512-KZhFpSLlmK/sdocfSAjqPETTMd0ug6HIMIAwkwUpU79olnZdQtMxpQP+G1wDzCH7na+FltSIhbaZuKdwZ8RDrw== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -193,14 +188,21 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^5.33.1": - version "5.33.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.1.tgz#c0a480d05211660221eda963cc844732fe9b1714" - integrity sha512-S1iZIxrTvKkU3+m63YUOxYPKaP+yWDQrdhxTglVDVEVBf+aCSw85+BmJnyUaQQsk5TXFG/LpBu9fa+LrAQ91fQ== +"@types/ws@^8.5.3": + version "8.5.3" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" + integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w== + dependencies: + "@types/node" "*" + +"@typescript-eslint/eslint-plugin@^5.34.0": + version "5.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.34.0.tgz#d690f60e335596f38b01792e8f4b361d9bd0cb35" + integrity sha512-eRfPPcasO39iwjlUAMtjeueRGuIrW3TQ9WseIDl7i5UWuFbf83yYaU7YPs4j8+4CxUMIsj1k+4kV+E+G+6ypDQ== dependencies: - "@typescript-eslint/scope-manager" "5.33.1" - "@typescript-eslint/type-utils" "5.33.1" - "@typescript-eslint/utils" "5.33.1" + "@typescript-eslint/scope-manager" "5.34.0" + "@typescript-eslint/type-utils" "5.34.0" + "@typescript-eslint/utils" "5.34.0" debug "^4.3.4" functional-red-black-tree "^1.0.1" ignore "^5.2.0" @@ -208,69 +210,69 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.33.1": - version "5.33.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.33.1.tgz#e4b253105b4d2a4362cfaa4e184e2d226c440ff3" - integrity sha512-IgLLtW7FOzoDlmaMoXdxG8HOCByTBXrB1V2ZQYSEV1ggMmJfAkMWTwUjjzagS6OkfpySyhKFkBw7A9jYmcHpZA== +"@typescript-eslint/parser@^5.34.0": + version "5.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.34.0.tgz#ca710858ea85dbfd30c9b416a335dc49e82dbc07" + integrity sha512-SZ3NEnK4usd2CXkoV3jPa/vo1mWX1fqRyIVUQZR4As1vyp4fneknBNJj+OFtV8WAVgGf+rOHMSqQbs2Qn3nFZQ== dependencies: - "@typescript-eslint/scope-manager" "5.33.1" - "@typescript-eslint/types" "5.33.1" - "@typescript-eslint/typescript-estree" "5.33.1" + "@typescript-eslint/scope-manager" "5.34.0" + "@typescript-eslint/types" "5.34.0" + "@typescript-eslint/typescript-estree" "5.34.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.33.1": - version "5.33.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.33.1.tgz#8d31553e1b874210018ca069b3d192c6d23bc493" - integrity sha512-8ibcZSqy4c5m69QpzJn8XQq9NnqAToC8OdH/W6IXPXv83vRyEDPYLdjAlUx8h/rbusq6MkW4YdQzURGOqsn3CA== +"@typescript-eslint/scope-manager@5.34.0": + version "5.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.34.0.tgz#14efd13dc57602937e25f188fd911f118781e527" + integrity sha512-HNvASMQlah5RsBW6L6c7IJ0vsm+8Sope/wu5sEAf7joJYWNb1LDbJipzmdhdUOnfrDFE6LR1j57x1EYVxrY4ow== dependencies: - "@typescript-eslint/types" "5.33.1" - "@typescript-eslint/visitor-keys" "5.33.1" + "@typescript-eslint/types" "5.34.0" + "@typescript-eslint/visitor-keys" "5.34.0" -"@typescript-eslint/type-utils@5.33.1": - version "5.33.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.33.1.tgz#1a14e94650a0ae39f6e3b77478baff002cec4367" - integrity sha512-X3pGsJsD8OiqhNa5fim41YtlnyiWMF/eKsEZGsHID2HcDqeSC5yr/uLOeph8rNF2/utwuI0IQoAK3fpoxcLl2g== +"@typescript-eslint/type-utils@5.34.0": + version "5.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.34.0.tgz#7a324ab9ddd102cd5e1beefc94eea6f3eb32d32d" + integrity sha512-Pxlno9bjsQ7hs1pdWRUv9aJijGYPYsHpwMeCQ/Inavhym3/XaKt1ZKAA8FIw4odTBfowBdZJDMxf2aavyMDkLg== dependencies: - "@typescript-eslint/utils" "5.33.1" + "@typescript-eslint/utils" "5.34.0" debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.33.1": - version "5.33.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.33.1.tgz#3faef41793d527a519e19ab2747c12d6f3741ff7" - integrity sha512-7K6MoQPQh6WVEkMrMW5QOA5FO+BOwzHSNd0j3+BlBwd6vtzfZceJ8xJ7Um2XDi/O3umS8/qDX6jdy2i7CijkwQ== +"@typescript-eslint/types@5.34.0": + version "5.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.34.0.tgz#217bf08049e9e7b86694d982e88a2c1566330c78" + integrity sha512-49fm3xbbUPuzBIOcy2CDpYWqy/X7VBkxVN+DC21e0zIm3+61Z0NZi6J9mqPmSW1BDVk9FIOvuCFyUPjXz93sjA== -"@typescript-eslint/typescript-estree@5.33.1": - version "5.33.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.1.tgz#a573bd360790afdcba80844e962d8b2031984f34" - integrity sha512-JOAzJ4pJ+tHzA2pgsWQi4804XisPHOtbvwUyqsuuq8+y5B5GMZs7lI1xDWs6V2d7gE/Ez5bTGojSK12+IIPtXA== +"@typescript-eslint/typescript-estree@5.34.0": + version "5.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.34.0.tgz#ba7b83f4bf8ccbabf074bbf1baca7a58de3ccb9a" + integrity sha512-mXHAqapJJDVzxauEkfJI96j3D10sd567LlqroyCeJaHnu42sDbjxotGb3XFtGPYKPD9IyLjhsoULML1oI3M86A== dependencies: - "@typescript-eslint/types" "5.33.1" - "@typescript-eslint/visitor-keys" "5.33.1" + "@typescript-eslint/types" "5.34.0" + "@typescript-eslint/visitor-keys" "5.34.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.33.1": - version "5.33.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.33.1.tgz#171725f924fe1fe82bb776522bb85bc034e88575" - integrity sha512-uphZjkMaZ4fE8CR4dU7BquOV6u0doeQAr8n6cQenl/poMaIyJtBu8eys5uk6u5HiDH01Mj5lzbJ5SfeDz7oqMQ== +"@typescript-eslint/utils@5.34.0": + version "5.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.34.0.tgz#0cae98f48d8f9e292e5caa9343611b6faf49e743" + integrity sha512-kWRYybU4Rn++7lm9yu8pbuydRyQsHRoBDIo11k7eqBWTldN4xUdVUMCsHBiE7aoEkFzrUEaZy3iH477vr4xHAQ== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.33.1" - "@typescript-eslint/types" "5.33.1" - "@typescript-eslint/typescript-estree" "5.33.1" + "@typescript-eslint/scope-manager" "5.34.0" + "@typescript-eslint/types" "5.34.0" + "@typescript-eslint/typescript-estree" "5.34.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/visitor-keys@5.33.1": - version "5.33.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.1.tgz#0155c7571c8cd08956580b880aea327d5c34a18b" - integrity sha512-nwIxOK8Z2MPWltLKMLOEZwmfBZReqUdbEoHQXeCpa+sRVARe5twpJGHCB4dk9903Yaf0nMAlGbQfaAH92F60eg== +"@typescript-eslint/visitor-keys@5.34.0": + version "5.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.34.0.tgz#d0fb3e31033e82ddd5de048371ad39eb342b2d40" + integrity sha512-O1moYjOSrab0a2fUvFpsJe0QHtvTC+cR+ovYpgKrAVXzqQyc74mv76TgY6z+aEtjQE2vgZux3CQVtGryqdcOAw== dependencies: - "@typescript-eslint/types" "5.33.1" + "@typescript-eslint/types" "5.34.0" eslint-visitor-keys "^3.3.0" acorn-jsx@^5.3.2: @@ -1086,9 +1088,9 @@ flat-cache@^3.0.4: rimraf "^3.0.2" flatted@^3.1.0: - version "3.2.6" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2" - integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ== + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== from@~0: version "0.1.7" @@ -1659,9 +1661,9 @@ keyv@^3.0.0: json-buffer "3.0.0" keyv@^4.0.0: - version "4.3.3" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.3.3.tgz#6c1bcda6353a9e96fc1b4e1aeb803a6e35090ba9" - integrity sha512-AcysI17RvakTh8ir03+a3zJr5r0ovnAH/XTXei/4HIv3bL2K/jzvgivLK9UuI/JbU1aJjM3NSAnVvVVd3n+4DQ== + version "4.4.1" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.4.1.tgz#5d97bae8dfbb6788ebc9330daf5eb6582e2d3d1c" + integrity sha512-PzByhNxfBLnSBW2MZi1DF+W5+qB/7BMpOokewqIvqS8GFtP7xHm2oeGU72Y1fhtfOv/FiEnI4+nyViYDmUChnw== dependencies: compress-brotli "^1.3.8" json-buffer "3.0.1" @@ -1855,9 +1857,9 @@ map-stream@~0.1.0: integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g== marked@^4.0.18: - version "4.0.18" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.18.tgz#cd0ac54b2e5610cfb90e8fd46ccaa8292c9ed569" - integrity sha512-wbLDJ7Zh0sqA0Vdg6aqlbT+yPxqLblpAZh1mK2+AO2twQkPywvvqQNfEPVwSSRjZ7dZcdeVBIAgiO7MMp3Dszw== + version "4.0.19" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.19.tgz#d36198d1ac1255525153c351c68c75bc1d7aee46" + integrity sha512-rgQF/OxOiLcvgUAj1Q1tAf4Bgxn5h5JZTp04Fx4XUkVhs7B+7YA9JEWJhJpoO8eJt8MkZMwqLCNeNqj1bCREZQ== meow@^8.1.0: version "8.1.2" @@ -2625,11 +2627,6 @@ slice-ansi@0.0.4: resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" integrity sha512-up04hB2hR92PgjpyU3y/eg91yIBILyjVY26NvvciY3EVVPjybkMszMpXQ9QAkcS3I5rtJBDLoTxxg+qvW8c7rw== -sockette@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/sockette/-/sockette-2.0.6.tgz#63b533f3cfe3b592fc84178beea6577fa18cebf3" - integrity sha512-W6iG8RGV6Zife3Cj+FhuyHV447E6fqFM2hKmnaQrTvg3OydINV3Msj3WPFbX76blUlUxvQSMMMdrJxce8NqI5Q== - spdx-correct@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" @@ -2652,9 +2649,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.11" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" - integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== + version "3.0.12" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz#69077835abe2710b65f03969898b6637b505a779" + integrity sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA== split@0.3: version "0.3.3"