aqualink 1.8.1-beta2 → 1.8.1-beta4
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 +7 -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/Player.js +9 -10
- package/build/structures/Rest.js +17 -15
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -31,8 +31,13 @@ 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-beta4 Update:
|
|
35
|
+
- Use pool for connections (Experimental, help me improve it. Undici pool)
|
|
36
|
+
- Default will not leave the VC anymore (leaveOnEnd: false default)
|
|
37
|
+
- Misc optimizations on node and player
|
|
35
38
|
|
|
39
|
+
### 1.8.0
|
|
40
|
+
- Misc changes on FetchImage (improves the overall checking and speed)
|
|
36
41
|
- Rewrite `AQUA` module
|
|
37
42
|
- Remade the resolve logic (improves the speed by a lot)
|
|
38
43
|
- Fixes many memory usages related to nodes
|
|
@@ -109,7 +114,7 @@ const nodes = [
|
|
|
109
114
|
}
|
|
110
115
|
];
|
|
111
116
|
|
|
112
|
-
const aqua =
|
|
117
|
+
const aqua = Aqua(client, nodes, {
|
|
113
118
|
defaultSearchPlatform: "ytsearch",
|
|
114
119
|
restVersion: "v4",
|
|
115
120
|
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;
|
|
@@ -45,11 +45,15 @@ class Player extends EventEmitter {
|
|
|
45
45
|
this.nowPlayingMessage = null;
|
|
46
46
|
this.previousTracks = [];
|
|
47
47
|
this.shouldDeleteMessage = options.shouldDeleteMessage ?? false;
|
|
48
|
-
this.leaveOnEnd = options.leaveOnEnd ??
|
|
48
|
+
this.leaveOnEnd = options.leaveOnEnd ?? false;
|
|
49
49
|
|
|
50
50
|
this.onPlayerUpdate = ({ state } = {}) => {
|
|
51
51
|
if (!state) return;
|
|
52
|
-
|
|
52
|
+
for (const key in state) {
|
|
53
|
+
if (state.hasOwnProperty(key)) {
|
|
54
|
+
this[key] = state[key];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
53
57
|
this.aqua.emit("playerUpdate", this, { state });
|
|
54
58
|
};
|
|
55
59
|
this.handleEvent = async (payload) => {
|
|
@@ -64,7 +68,6 @@ class Player extends EventEmitter {
|
|
|
64
68
|
};
|
|
65
69
|
this.on("playerUpdate", this.onPlayerUpdate);
|
|
66
70
|
this.on("event", this.handleEvent);
|
|
67
|
-
this.#dataStore = new Map();
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
get previous() {
|
|
@@ -308,8 +311,7 @@ class Player extends EventEmitter {
|
|
|
308
311
|
this.aqua.send({ op: 4, d: data });
|
|
309
312
|
}
|
|
310
313
|
|
|
311
|
-
|
|
312
|
-
#dataStore;
|
|
314
|
+
#dataStore = new Map();
|
|
313
315
|
|
|
314
316
|
set(key, value) {
|
|
315
317
|
this.#dataStore.set(key, value);
|
|
@@ -324,11 +326,8 @@ class Player extends EventEmitter {
|
|
|
324
326
|
return this;
|
|
325
327
|
}
|
|
326
328
|
|
|
327
|
-
|
|
328
|
-
return this.nodes.rest.updatePlayer({
|
|
329
|
-
guildId: this.guildId,
|
|
330
|
-
data,
|
|
331
|
-
});
|
|
329
|
+
updatePlayer(data) {
|
|
330
|
+
return this.nodes.rest.updatePlayer({ guildId: this.guildId, data });
|
|
332
331
|
}
|
|
333
332
|
|
|
334
333
|
handleUnknownEvent(payload) {
|
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);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aqualink",
|
|
3
|
-
"version": "1.8.1-
|
|
3
|
+
"version": "1.8.1-beta4",
|
|
4
4
|
"description": "An Lavalink wrapper, focused in speed, performance, and features, Based in Riffy!",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"license": "ISC",
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"undici": "^7.3.0",
|
|
41
|
-
"ws": "^8.18.
|
|
41
|
+
"ws": "^8.18.1"
|
|
42
42
|
},
|
|
43
43
|
"repository": {
|
|
44
44
|
"type": "git",
|