aqualink 1.8.1-beta2 → 1.8.1-beta3
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.
- package/README.md +6 -2
- package/build/structures/Aqua.js +3 -3
- package/build/structures/Connection.js +1 -1
- package/build/structures/Node.js +41 -74
- package/build/structures/Rest.js +17 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,8 +31,12 @@ This code is based in riffy, but its an 100% Rewrite made from scratch...
|
|
|
31
31
|
|
|
32
32
|
# Brick by brick, 1.8.0 Update (yay)
|
|
33
33
|
|
|
34
|
-
-
|
|
34
|
+
### 1.8.1-beta3 Update:
|
|
35
|
+
- Use pool for connections (Experimental, help me improve it.)
|
|
36
|
+
- Remade some stuff on node related to caching
|
|
35
37
|
|
|
38
|
+
### 1.8.0
|
|
39
|
+
- Misc changes on FetchImage (improves the overall checking and speed)
|
|
36
40
|
- Rewrite `AQUA` module
|
|
37
41
|
- Remade the resolve logic (improves the speed by a lot)
|
|
38
42
|
- Fixes many memory usages related to nodes
|
|
@@ -109,7 +113,7 @@ const nodes = [
|
|
|
109
113
|
}
|
|
110
114
|
];
|
|
111
115
|
|
|
112
|
-
const aqua =
|
|
116
|
+
const aqua = Aqua(client, nodes, {
|
|
113
117
|
defaultSearchPlatform: "ytsearch",
|
|
114
118
|
restVersion: "v4",
|
|
115
119
|
autoResume: false,
|
package/build/structures/Aqua.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const { EventEmitter } = require("node:events");
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
4
|
+
const Node = require("./Node");
|
|
5
|
+
const Player = require("./Player");
|
|
6
|
+
const Track = require("./Track");
|
|
7
7
|
const { version: pkgVersion } = require("../../package.json");
|
|
8
8
|
const URL_REGEX = /^https?:\/\//;
|
|
9
9
|
|
package/build/structures/Node.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
2
|
const WebSocket = require("ws");
|
|
4
|
-
const
|
|
3
|
+
const Rest = require("./Rest");
|
|
5
4
|
|
|
6
5
|
class Node {
|
|
7
6
|
#ws = null;
|
|
8
|
-
#lastStatsRequest = 0;
|
|
9
7
|
#reconnectAttempted = 0;
|
|
10
8
|
#reconnectTimeoutId = null;
|
|
9
|
+
static BACKOFF_MULTIPLIER = 1.5;
|
|
10
|
+
static MAX_BACKOFF = 60000;
|
|
11
11
|
|
|
12
12
|
constructor(aqua, connOptions, options = {}) {
|
|
13
13
|
const {
|
|
@@ -38,15 +38,15 @@ class Node {
|
|
|
38
38
|
this.infiniteReconnects = options.infiniteReconnects || false;
|
|
39
39
|
this.connected = false;
|
|
40
40
|
this.info = null;
|
|
41
|
-
this.
|
|
42
|
-
|
|
41
|
+
this.defaultStats = this.#createDefaultStats();
|
|
42
|
+
this.stats = { ...this.defaultStats };
|
|
43
43
|
this._onOpen = this.#onOpen.bind(this);
|
|
44
44
|
this._onError = this.#onError.bind(this);
|
|
45
45
|
this._onMessage = this.#onMessage.bind(this);
|
|
46
46
|
this._onClose = this.#onClose.bind(this);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
#
|
|
49
|
+
#createDefaultStats() {
|
|
50
50
|
return {
|
|
51
51
|
players: 0,
|
|
52
52
|
playingPlayers: 0,
|
|
@@ -62,14 +62,11 @@ class Node {
|
|
|
62
62
|
this.#ws = new WebSocket(this.wsUrl.href, {
|
|
63
63
|
headers: this.#constructHeaders(),
|
|
64
64
|
perMessageDeflate: false,
|
|
65
|
-
handshakeTimeout: 30000
|
|
66
65
|
});
|
|
67
|
-
|
|
68
66
|
this.#ws.once("open", this._onOpen);
|
|
69
67
|
this.#ws.once("error", this._onError);
|
|
70
68
|
this.#ws.on("message", this._onMessage);
|
|
71
69
|
this.#ws.once("close", this._onClose);
|
|
72
|
-
this.aqua.emit("debug", this.name, "Connecting...");
|
|
73
70
|
}
|
|
74
71
|
|
|
75
72
|
#constructHeaders() {
|
|
@@ -86,30 +83,46 @@ class Node {
|
|
|
86
83
|
this.connected = true;
|
|
87
84
|
this.#reconnectAttempted = 0;
|
|
88
85
|
this.aqua.emit("debug", this.name, `Connected to ${this.wsUrl.href}`);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
this.
|
|
86
|
+
|
|
87
|
+
if (this.autoResume) {
|
|
88
|
+
try {
|
|
89
|
+
this.info = await this.rest.makeRequest("GET", "/v4/info");
|
|
90
|
+
await this.resumePlayers();
|
|
91
|
+
} catch (err) {
|
|
92
|
+
this.info = null;
|
|
93
|
+
if (!this.aqua.bypassChecks?.nodeFetchInfo) {
|
|
94
|
+
this.aqua.emit("error", `Failed to fetch node info: ${err.message}`);
|
|
95
|
+
}
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
async getStats() {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
const stats = await this.rest.makeRequest("GET", "/v4/stats");
|
|
102
|
+
this.stats = { ...this.defaultStats, ...stats };
|
|
103
|
+
return this.stats;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async #onMessage(msg) {
|
|
107
|
+
let payload;
|
|
105
108
|
try {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
109
|
+
payload = JSON.parse(msg);
|
|
110
|
+
} catch {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const op = payload?.op;
|
|
114
|
+
if (!op) return;
|
|
115
|
+
|
|
116
|
+
switch (op) {
|
|
117
|
+
case "stats":
|
|
118
|
+
this.#updateStats(payload);
|
|
119
|
+
break;
|
|
120
|
+
case "ready":
|
|
121
|
+
this.#handleReadyOp(payload);
|
|
122
|
+
break;
|
|
123
|
+
default:
|
|
124
|
+
this.#handlePlayerOp(payload);
|
|
111
125
|
}
|
|
112
|
-
return this.stats;
|
|
113
126
|
}
|
|
114
127
|
|
|
115
128
|
#updateStats(payload) {
|
|
@@ -120,7 +133,7 @@ class Node {
|
|
|
120
133
|
memory: this.#updateMemoryStats(payload.memory),
|
|
121
134
|
cpu: this.#updateCpuStats(payload.cpu),
|
|
122
135
|
frameStats: this.#updateFrameStats(payload.frameStats)
|
|
123
|
-
};
|
|
136
|
+
};
|
|
124
137
|
}
|
|
125
138
|
|
|
126
139
|
#updateMemoryStats(memory = {}) {
|
|
@@ -156,30 +169,6 @@ class Node {
|
|
|
156
169
|
};
|
|
157
170
|
}
|
|
158
171
|
|
|
159
|
-
#onMessage(msg) {
|
|
160
|
-
let payload;
|
|
161
|
-
try {
|
|
162
|
-
payload = JSON.parse(msg);
|
|
163
|
-
} catch {
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const op = payload?.op;
|
|
168
|
-
if (!op) return;
|
|
169
|
-
|
|
170
|
-
// Use switch for better performance with multiple conditions
|
|
171
|
-
switch (op) {
|
|
172
|
-
case "stats":
|
|
173
|
-
this.#updateStats(payload);
|
|
174
|
-
break;
|
|
175
|
-
case "ready":
|
|
176
|
-
this.#handleReadyOp(payload);
|
|
177
|
-
break;
|
|
178
|
-
default:
|
|
179
|
-
this.#handlePlayerOp(payload);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
172
|
#handleReadyOp(payload) {
|
|
184
173
|
if (this.sessionId !== payload.sessionId) {
|
|
185
174
|
this.sessionId = payload.sessionId;
|
|
@@ -209,22 +198,18 @@ class Node {
|
|
|
209
198
|
setTimeout(() => this.connect(), 10000);
|
|
210
199
|
return;
|
|
211
200
|
}
|
|
212
|
-
|
|
213
201
|
if (this.#reconnectAttempted >= this.reconnectTries) {
|
|
214
202
|
this.aqua.emit("nodeError", this,
|
|
215
203
|
new Error(`Max reconnection attempts reached (${this.reconnectTries})`));
|
|
216
204
|
this.destroy(true);
|
|
217
205
|
return;
|
|
218
206
|
}
|
|
219
|
-
|
|
220
207
|
clearTimeout(this.#reconnectTimeoutId);
|
|
221
|
-
|
|
222
208
|
const jitter = Math.random() * 10000;
|
|
223
209
|
const backoffTime = Math.min(
|
|
224
210
|
this.reconnectTimeout * Math.pow(Node.BACKOFF_MULTIPLIER, this.#reconnectAttempted) + jitter,
|
|
225
211
|
Node.MAX_BACKOFF
|
|
226
212
|
);
|
|
227
|
-
|
|
228
213
|
this.#reconnectTimeoutId = setTimeout(() => {
|
|
229
214
|
this.#reconnectAttempted++;
|
|
230
215
|
this.aqua.emit("nodeReconnect", {
|
|
@@ -236,22 +221,6 @@ class Node {
|
|
|
236
221
|
}, backoffTime);
|
|
237
222
|
}
|
|
238
223
|
|
|
239
|
-
get penalties() {
|
|
240
|
-
if (!this.connected) return Number.MAX_SAFE_INTEGER;
|
|
241
|
-
|
|
242
|
-
let penalties = this.stats.players;
|
|
243
|
-
|
|
244
|
-
const { cpu, frameStats } = this.stats;
|
|
245
|
-
if (cpu?.systemLoad) {
|
|
246
|
-
penalties += Math.round(Math.pow(1.05, 100 * cpu.systemLoad) * 10 - 10);
|
|
247
|
-
}
|
|
248
|
-
if (frameStats) {
|
|
249
|
-
penalties += frameStats.deficit + (frameStats.nulled * 2);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
return penalties;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
224
|
destroy(clean = false) {
|
|
256
225
|
if (clean) {
|
|
257
226
|
this.aqua.emit("nodeDestroy", this);
|
|
@@ -269,9 +238,7 @@ class Node {
|
|
|
269
238
|
this.aqua.nodeMap.delete(this.name);
|
|
270
239
|
this.aqua.emit("nodeDestroy", this);
|
|
271
240
|
this.info = null;
|
|
272
|
-
this.#lastStatsRequest = 0;
|
|
273
|
-
this.stats = this.#createStats();
|
|
274
241
|
}
|
|
275
242
|
}
|
|
276
243
|
|
|
277
|
-
module.exports = Node
|
|
244
|
+
module.exports = Node;
|
package/build/structures/Rest.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const {
|
|
2
|
+
const { Pool } = require("undici");
|
|
3
3
|
|
|
4
4
|
class Rest {
|
|
5
|
-
constructor(aqua, { secure, host, port, sessionId, password
|
|
5
|
+
constructor(aqua, { secure, host, port, sessionId, password,}) {
|
|
6
6
|
this.aqua = aqua;
|
|
7
7
|
this.sessionId = sessionId;
|
|
8
8
|
this.version = "v4";
|
|
@@ -11,6 +11,9 @@ class Rest {
|
|
|
11
11
|
"Content-Type": "application/json",
|
|
12
12
|
Authorization: password,
|
|
13
13
|
};
|
|
14
|
+
this.client = new Pool(this.baseUrl, {
|
|
15
|
+
pipelining: 1,
|
|
16
|
+
});
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
setSessionId(sessionId) {
|
|
@@ -19,21 +22,15 @@ class Rest {
|
|
|
19
22
|
|
|
20
23
|
async makeRequest(method, endpoint, body = null) {
|
|
21
24
|
const options = {
|
|
25
|
+
path: endpoint,
|
|
22
26
|
method,
|
|
23
27
|
headers: this.headers,
|
|
24
|
-
body
|
|
28
|
+
...(body && { body: JSON.stringify(body) }),
|
|
25
29
|
};
|
|
26
|
-
|
|
27
30
|
try {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (statusCode === 204) {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const data = await responseBody.text();
|
|
36
|
-
return data ? JSON.parse(data) : null;
|
|
31
|
+
const response = await this.client.request(options);
|
|
32
|
+
const { statusCode } = response;
|
|
33
|
+
return statusCode === 204 ? null : await response.body.json();
|
|
37
34
|
} catch (error) {
|
|
38
35
|
throw new Error(`Request to ${endpoint} failed: ${error.message}`);
|
|
39
36
|
}
|
|
@@ -43,16 +40,21 @@ class Rest {
|
|
|
43
40
|
const validSegments = segments.filter(segment => segment && segment.trim());
|
|
44
41
|
return '/' + validSegments.join('/');
|
|
45
42
|
}
|
|
43
|
+
|
|
46
44
|
validateSessionId() {
|
|
47
45
|
if (!this.sessionId) {
|
|
48
46
|
throw new Error("Session ID is not set.");
|
|
49
47
|
}
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
updatePlayer({ guildId, data }) {
|
|
53
|
-
|
|
50
|
+
async updatePlayer({ guildId, data }) {
|
|
51
|
+
const hasEncodedTrack = data.track?.encoded && data.track?.identifier;
|
|
52
|
+
const hasEncodedTrackAlt = data.encodedTrack && data.identifier;
|
|
53
|
+
|
|
54
|
+
if (hasEncodedTrack || hasEncodedTrackAlt) {
|
|
54
55
|
throw new Error("Cannot provide both 'encoded' and 'identifier' for track");
|
|
55
56
|
}
|
|
57
|
+
|
|
56
58
|
this.validateSessionId();
|
|
57
59
|
const endpoint = this.buildEndpoint(this.version, "sessions", this.sessionId, "players", guildId) + "?noReplace=false";
|
|
58
60
|
return this.makeRequest("PATCH", endpoint, data);
|