lavacord 2.2.0 → 3.0.0
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/LICENSE +24 -201
- package/README.md +473 -69
- package/dist/cjs/index.cjs +44 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +1211 -0
- package/dist/cjs/lib/LavalinkNode.cjs +423 -0
- package/dist/cjs/lib/LavalinkNode.cjs.map +1 -0
- package/dist/cjs/lib/Manager.cjs +405 -0
- package/dist/cjs/lib/Manager.cjs.map +1 -0
- package/dist/cjs/lib/Player.cjs +220 -0
- package/dist/cjs/lib/Player.cjs.map +1 -0
- package/dist/cjs/lib/Rest.cjs +192 -0
- package/dist/cjs/lib/Rest.cjs.map +1 -0
- package/dist/cjs/lib/Types.cjs +4 -0
- package/dist/cjs/lib/Types.cjs.map +1 -0
- package/dist/cjs/wrappers/cloudstorm.cjs +54 -0
- package/dist/cjs/wrappers/cloudstorm.cjs.map +1 -0
- package/dist/cjs/wrappers/detritus.cjs +57 -0
- package/dist/cjs/wrappers/detritus.cjs.map +1 -0
- package/dist/cjs/wrappers/discord.js.cjs +37 -0
- package/dist/cjs/wrappers/discord.js.cjs.map +1 -0
- package/dist/cjs/wrappers/eris.cjs +51 -0
- package/dist/cjs/wrappers/eris.cjs.map +1 -0
- package/dist/cjs/wrappers/oceanic.cjs +52 -0
- package/dist/cjs/wrappers/oceanic.cjs.map +1 -0
- package/dist/esm/chunk-PAWJFY3S.mjs +6 -0
- package/dist/esm/chunk-PAWJFY3S.mjs.map +1 -0
- package/dist/esm/index.d.mts +1211 -0
- package/dist/esm/index.mjs +12 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/lib/LavalinkNode.mjs +420 -0
- package/dist/esm/lib/LavalinkNode.mjs.map +1 -0
- package/dist/esm/lib/Manager.mjs +402 -0
- package/dist/esm/lib/Manager.mjs.map +1 -0
- package/dist/esm/lib/Player.mjs +217 -0
- package/dist/esm/lib/Player.mjs.map +1 -0
- package/dist/esm/lib/Rest.mjs +188 -0
- package/dist/esm/lib/Rest.mjs.map +1 -0
- package/dist/esm/lib/Types.mjs +3 -0
- package/dist/esm/lib/Types.mjs.map +1 -0
- package/dist/esm/wrappers/cloudstorm.mjs +45 -0
- package/dist/esm/wrappers/cloudstorm.mjs.map +1 -0
- package/dist/esm/wrappers/detritus.mjs +48 -0
- package/dist/esm/wrappers/detritus.mjs.map +1 -0
- package/dist/esm/wrappers/discord.js.mjs +28 -0
- package/dist/esm/wrappers/discord.js.mjs.map +1 -0
- package/dist/esm/wrappers/eris.mjs +42 -0
- package/dist/esm/wrappers/eris.mjs.map +1 -0
- package/dist/esm/wrappers/oceanic.mjs +43 -0
- package/dist/esm/wrappers/oceanic.mjs.map +1 -0
- package/dist/lib/LavalinkNode.d.ts +3 -3
- package/dist/lib/LavalinkNode.js +16 -26
- package/dist/lib/LavalinkNode.js.map +1 -1
- package/dist/lib/Manager.d.ts +2 -2
- package/dist/lib/Manager.js.map +1 -1
- package/dist/lib/Rest.js +5 -7
- package/dist/lib/Rest.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +109 -64
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var Rest_cjs = require('./Rest.cjs');
|
|
4
|
+
var cloudstorm = require('cloudstorm');
|
|
5
|
+
var index_cjs = require('../index.cjs');
|
|
6
|
+
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
+
var LavalinkNode = class {
|
|
10
|
+
/**
|
|
11
|
+
* Creates a new LavalinkNode instance.
|
|
12
|
+
*
|
|
13
|
+
* @summary Initializes a new Lavalink node connection
|
|
14
|
+
* @param manager - The {@link Manager} instance that controls this node
|
|
15
|
+
* @param options - Configuration options for this Lavalink node as defined in {@link LavalinkNodeOptions}
|
|
16
|
+
*/
|
|
17
|
+
constructor(manager, options) {
|
|
18
|
+
this.manager = manager;
|
|
19
|
+
this.id = options.id;
|
|
20
|
+
if (options.host) Object.defineProperty(this, "host", { value: options.host });
|
|
21
|
+
if (options.port) Object.defineProperty(this, "port", { value: options.port });
|
|
22
|
+
if (options.password) Object.defineProperty(this, "password", { value: options.password });
|
|
23
|
+
if (options.secure !== void 0) Object.defineProperty(this, "secure", { value: options.secure });
|
|
24
|
+
if (options.reconnectInterval) this.reconnectInterval = options.reconnectInterval;
|
|
25
|
+
if (options.sessionId) this.sessionId = options.sessionId;
|
|
26
|
+
if (options.resuming !== void 0) this.resuming = options.resuming;
|
|
27
|
+
if (options.resumeTimeout) this.resumeTimeout = options.resumeTimeout;
|
|
28
|
+
if (options.state) this.state = options.state;
|
|
29
|
+
}
|
|
30
|
+
static {
|
|
31
|
+
__name(this, "LavalinkNode");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The identifier for this Lavalink node. Used to distinguish between multiple nodes.
|
|
35
|
+
*
|
|
36
|
+
* @summary Unique identifier for the node
|
|
37
|
+
* @remarks
|
|
38
|
+
* This is a required property that must be unique across all nodes in your application.
|
|
39
|
+
* It's used for identifying this node in logs and when selecting nodes for new players.
|
|
40
|
+
*/
|
|
41
|
+
id;
|
|
42
|
+
/**
|
|
43
|
+
* The hostname or IP address of the Lavalink server.
|
|
44
|
+
*
|
|
45
|
+
* @summary Server hostname or IP address
|
|
46
|
+
* @remarks
|
|
47
|
+
* This can be a domain name, IPv4, or IPv6 address pointing to your Lavalink server.
|
|
48
|
+
*/
|
|
49
|
+
host = "localhost";
|
|
50
|
+
/**
|
|
51
|
+
* The port number that the Lavalink server is listening on.
|
|
52
|
+
*
|
|
53
|
+
* @summary Server port number
|
|
54
|
+
* @remarks
|
|
55
|
+
* This should match the port configured in your Lavalink server's application.yml.
|
|
56
|
+
*/
|
|
57
|
+
port = 2333;
|
|
58
|
+
/**
|
|
59
|
+
* The time in milliseconds between reconnection attempts if the connection fails.
|
|
60
|
+
*
|
|
61
|
+
* @summary Reconnection delay in milliseconds
|
|
62
|
+
* @remarks
|
|
63
|
+
* Lower values will attempt reconnections more quickly, but might
|
|
64
|
+
* cause excessive connection attempts during prolonged server outages.
|
|
65
|
+
*/
|
|
66
|
+
reconnectInterval = 1e4;
|
|
67
|
+
/**
|
|
68
|
+
* The password used for authorization with the Lavalink server.
|
|
69
|
+
*
|
|
70
|
+
* @summary Authorization password for the Lavalink server
|
|
71
|
+
* @remarks
|
|
72
|
+
* This password must match the one configured in your Lavalink server's application.yml.
|
|
73
|
+
* It's used in the Authorization header when establishing the WebSocket connection.
|
|
74
|
+
*/
|
|
75
|
+
password = "youshallnotpass";
|
|
76
|
+
/**
|
|
77
|
+
* Whether to use secure connections (HTTPS/WSS) instead of HTTP/WS.
|
|
78
|
+
*
|
|
79
|
+
* @summary Secure connection flag for SSL/TLS
|
|
80
|
+
* @remarks
|
|
81
|
+
* When true, WebSocket connections will use WSS and REST requests will use HTTPS.
|
|
82
|
+
* This is required when connecting to Lavalink servers behind SSL/TLS.
|
|
83
|
+
*/
|
|
84
|
+
secure = false;
|
|
85
|
+
/**
|
|
86
|
+
* The WebSocket instance used for communication with the Lavalink server.
|
|
87
|
+
*
|
|
88
|
+
* @summary Active WebSocket connection to the Lavalink server
|
|
89
|
+
* @remarks
|
|
90
|
+
* When not connected to Lavalink, this property will be null.
|
|
91
|
+
* You can check the {@link connected} property to determine connection status.
|
|
92
|
+
*/
|
|
93
|
+
ws = null;
|
|
94
|
+
/**
|
|
95
|
+
* The statistics received from the Lavalink server.
|
|
96
|
+
*
|
|
97
|
+
* @summary Server resource usage and player statistics
|
|
98
|
+
* @remarks
|
|
99
|
+
* Contains information about system resource usage, player counts, and audio frame statistics.
|
|
100
|
+
* This is updated whenever the Lavalink server sends a stats update (typically every minute).
|
|
101
|
+
* You can use these stats to implement node selection strategies in your application.
|
|
102
|
+
*/
|
|
103
|
+
stats = {
|
|
104
|
+
players: 0,
|
|
105
|
+
playingPlayers: 0,
|
|
106
|
+
uptime: 0,
|
|
107
|
+
memory: {
|
|
108
|
+
used: 0,
|
|
109
|
+
free: 0,
|
|
110
|
+
allocated: 0,
|
|
111
|
+
reservable: 0
|
|
112
|
+
},
|
|
113
|
+
cpu: {
|
|
114
|
+
cores: 0,
|
|
115
|
+
systemLoad: 0,
|
|
116
|
+
lavalinkLoad: 0
|
|
117
|
+
},
|
|
118
|
+
frameStats: {
|
|
119
|
+
sent: 0,
|
|
120
|
+
nulled: 0,
|
|
121
|
+
deficit: 0
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Whether this node should attempt to resume the session when reconnecting.
|
|
126
|
+
*
|
|
127
|
+
* @summary Session resumption flag
|
|
128
|
+
* @remarks
|
|
129
|
+
* When true, the node will try to resume the previous session after a disconnect,
|
|
130
|
+
* preserving player states and connections. This helps maintain playback during
|
|
131
|
+
* brief disconnections or node restarts.
|
|
132
|
+
*/
|
|
133
|
+
resuming = false;
|
|
134
|
+
/**
|
|
135
|
+
* The timeout in seconds after which a disconnected session can no longer be resumed.
|
|
136
|
+
*
|
|
137
|
+
* @summary Maximum session resumption timeout in seconds
|
|
138
|
+
* @remarks
|
|
139
|
+
* This value is sent to the Lavalink server when configuring session resuming.
|
|
140
|
+
* After this many seconds of disconnection, the session will be fully closed
|
|
141
|
+
* and cannot be resumed.
|
|
142
|
+
*/
|
|
143
|
+
resumeTimeout = 60;
|
|
144
|
+
/**
|
|
145
|
+
* Custom data that can be attached to the node instance.
|
|
146
|
+
*
|
|
147
|
+
* @summary Custom application data storage
|
|
148
|
+
* @remarks
|
|
149
|
+
* Not used internally by Lavacord, available for application-specific needs.
|
|
150
|
+
* You can use this property to store any data relevant to your implementation,
|
|
151
|
+
* such as region information, feature flags, or custom metrics.
|
|
152
|
+
*/
|
|
153
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
154
|
+
state;
|
|
155
|
+
/**
|
|
156
|
+
* The unique session identifier provided by Lavalink on successful connection.
|
|
157
|
+
*
|
|
158
|
+
* @summary Lavalink session identifier
|
|
159
|
+
* @remarks
|
|
160
|
+
* This ID is used for resuming sessions and in certain REST API calls.
|
|
161
|
+
* It's automatically assigned when connecting to the Lavalink server.
|
|
162
|
+
*/
|
|
163
|
+
sessionId;
|
|
164
|
+
/**
|
|
165
|
+
* The version of the Lavalink protocol this node is using.
|
|
166
|
+
*
|
|
167
|
+
* @summary Lavalink protocol version
|
|
168
|
+
* @remarks
|
|
169
|
+
* This is set automatically when connecting to the Lavalink server.
|
|
170
|
+
* It indicates which version of the Lavalink protocol this node supports.
|
|
171
|
+
* The default value is "4", which corresponds to the latest stable version.
|
|
172
|
+
*
|
|
173
|
+
* @defaultValue "4"
|
|
174
|
+
*/
|
|
175
|
+
version = "4";
|
|
176
|
+
/**
|
|
177
|
+
* Timeout reference used for the reconnection mechanism.
|
|
178
|
+
* This holds the NodeJS.Timeout instance used to schedule reconnection attempts.
|
|
179
|
+
*/
|
|
180
|
+
_reconnect;
|
|
181
|
+
/**
|
|
182
|
+
* Current reconnection attempt count for exponential backoff.
|
|
183
|
+
*/
|
|
184
|
+
_reconnectAttempts = 0;
|
|
185
|
+
/**
|
|
186
|
+
* Tracks whether the session has been updated with the Lavalink server.
|
|
187
|
+
* Used internally to avoid redundant session update requests.
|
|
188
|
+
*/
|
|
189
|
+
_sessionUpdated = false;
|
|
190
|
+
/**
|
|
191
|
+
* Establishes a connection to the Lavalink server.
|
|
192
|
+
*
|
|
193
|
+
* This method creates a new WebSocket connection to the configured Lavalink server.
|
|
194
|
+
* If the node is already connected, it will close the existing connection first.
|
|
195
|
+
* The method sets up event listeners for the WebSocket to handle messages, errors,
|
|
196
|
+
* and connection state changes.
|
|
197
|
+
*
|
|
198
|
+
* Note: This method is primarily used internally by the {@link Manager} class.
|
|
199
|
+
* Users typically should not call this method directly as the Manager handles
|
|
200
|
+
* node connections automatically.
|
|
201
|
+
*
|
|
202
|
+
* @returns A promise that resolves when connected or rejects if connection fails
|
|
203
|
+
* @throws {Error} If the connection fails due to network issues, authentication problems, or other errors
|
|
204
|
+
*/
|
|
205
|
+
async connect() {
|
|
206
|
+
if (this.connected) this.ws.close(1e3, "reconnecting");
|
|
207
|
+
this.version = await Rest_cjs.Rest.version(this).then((str) => str.split(".")[0]).catch(() => "4");
|
|
208
|
+
return new Promise((resolve, reject) => {
|
|
209
|
+
let isResolved = false;
|
|
210
|
+
const headers = {
|
|
211
|
+
Authorization: this.password,
|
|
212
|
+
"User-Id": this.manager.userId,
|
|
213
|
+
"Client-Name": `Lavacord/${index_cjs.VERSION}`
|
|
214
|
+
};
|
|
215
|
+
if (this.sessionId && this.resuming) headers["Session-Id"] = this.sessionId;
|
|
216
|
+
this.ws = new cloudstorm.BetterWs(this.socketURL, { headers, encoding: "json" }).on("ws_open", () => {
|
|
217
|
+
isResolved = true;
|
|
218
|
+
this.onOpen();
|
|
219
|
+
resolve(this.ws);
|
|
220
|
+
}).on("error", (error) => {
|
|
221
|
+
if (!isResolved) {
|
|
222
|
+
isResolved = true;
|
|
223
|
+
reject(new Error(error));
|
|
224
|
+
}
|
|
225
|
+
this.onError(new Error(error));
|
|
226
|
+
}).on("ws_close", (code, reason) => {
|
|
227
|
+
if (!isResolved) {
|
|
228
|
+
isResolved = true;
|
|
229
|
+
reject(new Error(`WebSocket closed during connection: ${code} ${reason.toString()}`));
|
|
230
|
+
}
|
|
231
|
+
this.onClose(code, reason);
|
|
232
|
+
}).on("ws_receive", this.onMessage.bind(this));
|
|
233
|
+
this.ws.connect();
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Gracefully closes the connection to the Lavalink server.
|
|
238
|
+
*
|
|
239
|
+
* This method closes the WebSocket connection with a normal closure code (1000)
|
|
240
|
+
* and a reason of "destroy", indicating an intentional disconnection rather
|
|
241
|
+
* than an error condition.
|
|
242
|
+
*
|
|
243
|
+
* Note: This method is primarily used internally by the {@link Manager} class.
|
|
244
|
+
* Users typically should not call this method directly as the Manager handles
|
|
245
|
+
* node disconnections automatically.
|
|
246
|
+
*
|
|
247
|
+
* @returns void
|
|
248
|
+
*/
|
|
249
|
+
destroy() {
|
|
250
|
+
if (!this.connected) return;
|
|
251
|
+
this.ws.close(1e3, "destroy");
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Indicates whether this node is currently connected to the Lavalink server.
|
|
255
|
+
*
|
|
256
|
+
* @summary Connection status check
|
|
257
|
+
* @remarks
|
|
258
|
+
* Checks if the {@link ws} instance exists and if its ready state is 1.
|
|
259
|
+
* This property is useful for verifying connection status before attempting operations
|
|
260
|
+
* or implementing node selection strategies.
|
|
261
|
+
*
|
|
262
|
+
* @returns `true` if connected, `false` otherwise
|
|
263
|
+
*/
|
|
264
|
+
get connected() {
|
|
265
|
+
if (!this.ws) return false;
|
|
266
|
+
return this.ws.sm.currentStateName === "connected";
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Gets the WebSocket URL for connecting to the Lavalink server.
|
|
270
|
+
*
|
|
271
|
+
* @summary WebSocket connection URL
|
|
272
|
+
* @remarks
|
|
273
|
+
* Returns either a secure (wss://) or insecure (ws://) WebSocket URL
|
|
274
|
+
* based on the {@link secure} property configuration.
|
|
275
|
+
*
|
|
276
|
+
* @returns The complete WebSocket URL including protocol, host, port, and path
|
|
277
|
+
*/
|
|
278
|
+
get socketURL() {
|
|
279
|
+
const protocol = this.secure ? "wss" : "ws";
|
|
280
|
+
return `${protocol}://${this.host}:${this.port}/v${this.version}/websocket`;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Gets the REST API base URL for the Lavalink server.
|
|
284
|
+
*
|
|
285
|
+
* @summary REST API base URL
|
|
286
|
+
* @remarks
|
|
287
|
+
* Returns either a secure (https://) or insecure (http://) REST URL
|
|
288
|
+
* based on the {@link secure} property configuration.
|
|
289
|
+
*
|
|
290
|
+
* @returns The complete REST API base URL including protocol, host, port, and path
|
|
291
|
+
*/
|
|
292
|
+
get restURL() {
|
|
293
|
+
const protocol = this.secure ? "https" : "http";
|
|
294
|
+
return `${protocol}://${this.host}:${this.port}`;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Handles the WebSocket 'open' event when a connection is established.
|
|
298
|
+
*/
|
|
299
|
+
onOpen() {
|
|
300
|
+
if (this._reconnect) clearTimeout(this._reconnect);
|
|
301
|
+
this._reconnectAttempts = 0;
|
|
302
|
+
this.manager.emit("ready", this);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Processes incoming WebSocket messages from the Lavalink server.
|
|
306
|
+
* @param msg - The raw data received from the WebSocket
|
|
307
|
+
*/
|
|
308
|
+
onMessage(msg) {
|
|
309
|
+
switch (msg.op) {
|
|
310
|
+
case "ready":
|
|
311
|
+
if (msg.sessionId) this.sessionId = msg.sessionId;
|
|
312
|
+
if (!this._sessionUpdated) {
|
|
313
|
+
this._sessionUpdated = true;
|
|
314
|
+
Rest_cjs.Rest.updateSession(this).catch((e) => this.manager.emit("error", e, this));
|
|
315
|
+
}
|
|
316
|
+
break;
|
|
317
|
+
case "stats": {
|
|
318
|
+
const { op, ...stats } = msg;
|
|
319
|
+
this.stats = stats;
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
case "event":
|
|
323
|
+
this._handleEvent(msg);
|
|
324
|
+
break;
|
|
325
|
+
case "playerUpdate": {
|
|
326
|
+
const player = this.manager.players.get(msg.guildId);
|
|
327
|
+
if (!player) break;
|
|
328
|
+
player.state = msg.state;
|
|
329
|
+
if (player.listenerCount("state")) player.emit("state", msg.state);
|
|
330
|
+
if (this.manager.listenerCount("playerState")) this.manager.emit("playerState", player, msg.state);
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
this.manager.emit("raw", msg, this);
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Handles WebSocket errors.
|
|
338
|
+
* @param error - The error received from the WebSocket
|
|
339
|
+
*/
|
|
340
|
+
onError(error) {
|
|
341
|
+
if (!error) return;
|
|
342
|
+
this.manager.emit("error", error, this);
|
|
343
|
+
this.destroy();
|
|
344
|
+
this.reconnect();
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Handles WebSocket closure.
|
|
348
|
+
*
|
|
349
|
+
* @param code - The WebSocket close code (see Lavalink API for code meanings)
|
|
350
|
+
* @param reason - The reason why the WebSocket was closed
|
|
351
|
+
*/
|
|
352
|
+
onClose(code, reason) {
|
|
353
|
+
this._sessionUpdated = false;
|
|
354
|
+
this.manager.emit("disconnect", code, reason, this);
|
|
355
|
+
this.ws?.removeAllListeners();
|
|
356
|
+
this.ws = null;
|
|
357
|
+
switch (code) {
|
|
358
|
+
case 1e3:
|
|
359
|
+
if (reason.toString() === "destroy") return clearTimeout(this._reconnect);
|
|
360
|
+
break;
|
|
361
|
+
case 4001:
|
|
362
|
+
case 4002:
|
|
363
|
+
case 4003:
|
|
364
|
+
case 4004:
|
|
365
|
+
case 4005:
|
|
366
|
+
this.manager.emit("error", new Error(`Lavalink authentication error: ${code} ${reason}`), this);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
this.reconnect();
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Initiates a reconnection attempt after a delay with exponential backoff.
|
|
373
|
+
*/
|
|
374
|
+
reconnect() {
|
|
375
|
+
this._reconnectAttempts++;
|
|
376
|
+
const delay = Math.min(this.reconnectInterval * Math.pow(2, this._reconnectAttempts - 1), 6e4);
|
|
377
|
+
this._reconnect = setTimeout(async () => {
|
|
378
|
+
this.manager.emit("reconnecting", this);
|
|
379
|
+
await this.connect().catch((error) => this.manager.emit("error", error, this));
|
|
380
|
+
}, delay);
|
|
381
|
+
}
|
|
382
|
+
_handleEvent(data) {
|
|
383
|
+
const player = this.manager.players.get(data.guildId);
|
|
384
|
+
if (!player) return;
|
|
385
|
+
switch (data.type) {
|
|
386
|
+
case "TrackStartEvent":
|
|
387
|
+
player.track = data.track;
|
|
388
|
+
player.timestamp = Date.now();
|
|
389
|
+
if (player.listenerCount("trackStart")) player.emit("trackStart", data);
|
|
390
|
+
if (this.manager.listenerCount("playerTrackStart")) this.manager.emit("playerTrackStart", player, data);
|
|
391
|
+
break;
|
|
392
|
+
case "TrackEndEvent":
|
|
393
|
+
if (data.reason !== "replaced") {
|
|
394
|
+
player.track = null;
|
|
395
|
+
player.timestamp = null;
|
|
396
|
+
}
|
|
397
|
+
if (player.listenerCount("trackEnd")) player.emit("trackEnd", data);
|
|
398
|
+
if (this.manager.listenerCount("playerTrackEnd")) this.manager.emit("playerTrackEnd", player, data);
|
|
399
|
+
break;
|
|
400
|
+
case "TrackExceptionEvent":
|
|
401
|
+
if (player.listenerCount("trackException")) player.emit("trackException", data);
|
|
402
|
+
if (this.manager.listenerCount("playerTrackException")) this.manager.emit("playerTrackException", player, data);
|
|
403
|
+
break;
|
|
404
|
+
case "TrackStuckEvent":
|
|
405
|
+
if (player.listenerCount("trackStuck")) player.emit("trackStuck", data);
|
|
406
|
+
if (this.manager.listenerCount("playerTrackStuck")) this.manager.emit("playerTrackStuck", player, data);
|
|
407
|
+
break;
|
|
408
|
+
case "WebSocketClosedEvent":
|
|
409
|
+
player.track = null;
|
|
410
|
+
player.timestamp = null;
|
|
411
|
+
if (player.listenerCount("webSocketClosed")) player.emit("webSocketClosed", data);
|
|
412
|
+
if (this.manager.listenerCount("playerWebSocketClosed")) this.manager.emit("playerWebSocketClosed", player, data);
|
|
413
|
+
break;
|
|
414
|
+
default:
|
|
415
|
+
this.manager.emit("warn", `Unexpected event type: ${data.type}`);
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
exports.LavalinkNode = LavalinkNode;
|
|
422
|
+
//# sourceMappingURL=LavalinkNode.cjs.map
|
|
423
|
+
//# sourceMappingURL=LavalinkNode.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/LavalinkNode.ts"],"names":["Rest","VERSION","BetterWs"],"mappings":";;;;;;;;AAsBO,IAAM,eAAN,MAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoLlB,WAAA,CACC,SACP,OAAA,EACC;AAFM,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAGP,IAAA,IAAA,CAAK,KAAK,OAAA,CAAQ,EAAA;AAElB,IAAA,IAAI,OAAA,CAAQ,IAAA,EAAM,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,QAAQ,EAAE,KAAA,EAAO,OAAA,CAAQ,IAAA,EAAM,CAAA;AAC7E,IAAA,IAAI,OAAA,CAAQ,IAAA,EAAM,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,QAAQ,EAAE,KAAA,EAAO,OAAA,CAAQ,IAAA,EAAM,CAAA;AAC7E,IAAA,IAAI,OAAA,CAAQ,QAAA,EAAU,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,YAAY,EAAE,KAAA,EAAO,OAAA,CAAQ,QAAA,EAAU,CAAA;AACzF,IAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,MAAA,EAAW,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,QAAA,EAAU,EAAE,KAAA,EAAO,OAAA,CAAQ,MAAA,EAAQ,CAAA;AACjG,IAAA,IAAI,OAAA,CAAQ,iBAAA,EAAmB,IAAA,CAAK,iBAAA,GAAoB,OAAA,CAAQ,iBAAA;AAChE,IAAA,IAAI,OAAA,CAAQ,SAAA,EAAW,IAAA,CAAK,SAAA,GAAY,OAAA,CAAQ,SAAA;AAChD,IAAA,IAAI,OAAA,CAAQ,QAAA,KAAa,MAAA,EAAW,IAAA,CAAK,WAAW,OAAA,CAAQ,QAAA;AAC5D,IAAA,IAAI,OAAA,CAAQ,aAAA,EAAe,IAAA,CAAK,aAAA,GAAgB,OAAA,CAAQ,aAAA;AACxD,IAAA,IAAI,OAAA,CAAQ,KAAA,EAAO,IAAA,CAAK,KAAA,GAAQ,OAAA,CAAQ,KAAA;AAAA;AACzC,EAzND;AAsB0B,IAAA,MAAA,CAAA,IAAA,EAAA,cAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASlB,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASS,IAAA,GAAO,WAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASP,IAAA,GAAwB,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUjC,iBAAA,GAAoB,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUX,QAAA,GAAW,iBAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUX,MAAA,GAAS,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUlB,EAAA,GAAsB,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWtB,KAAA,GAAe;AAAA,IACrB,OAAA,EAAS,CAAA;AAAA,IACT,cAAA,EAAgB,CAAA;AAAA,IAChB,MAAA,EAAQ,CAAA;AAAA,IACR,MAAA,EAAQ;AAAA,MACP,IAAA,EAAM,CAAA;AAAA,MACN,IAAA,EAAM,CAAA;AAAA,MACN,SAAA,EAAW,CAAA;AAAA,MACX,UAAA,EAAY;AAAA,KACb;AAAA,IACA,GAAA,EAAK;AAAA,MACJ,KAAA,EAAO,CAAA;AAAA,MACP,UAAA,EAAY,CAAA;AAAA,MACZ,YAAA,EAAc;AAAA,KACf;AAAA,IACA,UAAA,EAAY;AAAA,MACX,IAAA,EAAM,CAAA;AAAA,MACN,MAAA,EAAQ,CAAA;AAAA,MACR,OAAA,EAAS;AAAA;AACV,GACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWO,QAAA,GAAW,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWX,aAAA,GAAgB,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYhB,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,SAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,OAAA,GAAU,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMT,UAAA;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAA,GAAqB,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMrB,eAAA,GAAkB,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyC1B,MAAa,OAAA,GAA6B;AACzC,IAAA,IAAI,KAAK,SAAA,EAAW,IAAA,CAAK,EAAA,CAAI,KAAA,CAAM,KAAM,cAAc,CAAA;AAEvD,IAAA,IAAA,CAAK,UAAU,MAAMA,aAAA,CAAK,QAAQ,IAAI,CAAA,CACpC,KAAK,CAAC,GAAA,KAAQ,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAC,CAAA,CAC/B,KAAA,CAAM,MAAM,GAAG,CAAA;AAEjB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACvC,MAAA,IAAI,UAAA,GAAa,KAAA;AAGjB,MAAA,MAAM,OAAA,GAAoC;AAAA,QACzC,eAAe,IAAA,CAAK,QAAA;AAAA,QACpB,SAAA,EAAW,KAAK,OAAA,CAAQ,MAAA;AAAA,QACxB,aAAA,EAAe,YAAYC,iBAAO,CAAA;AAAA,OACnC;AAEA,MAAA,IAAI,KAAK,SAAA,IAAa,IAAA,CAAK,UAAU,OAAA,CAAQ,YAAY,IAAI,IAAA,CAAK,SAAA;AAElE,MAAA,IAAA,CAAK,EAAA,GAAK,IAAIC,mBAAA,CAAS,IAAA,CAAK,SAAA,EAAW,EAAE,OAAA,EAAS,QAAA,EAAU,MAAA,EAAQ,CAAA,CAClE,EAAA,CAAG,WAAW,MAAM;AACpB,QAAA,UAAA,GAAa,IAAA;AACb,QAAA,IAAA,CAAK,MAAA,EAAO;AACZ,QAAA,OAAA,CAAQ,KAAK,EAAG,CAAA;AAAA,OAChB,CAAA,CACA,EAAA,CAAG,OAAA,EAAS,CAAC,KAAA,KAAU;AACvB,QAAA,IAAI,CAAC,UAAA,EAAY;AAChB,UAAA,UAAA,GAAa,IAAA;AACb,UAAA,MAAA,CAAO,IAAI,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA;AAExB,QAAA,IAAA,CAAK,OAAA,CAAQ,IAAI,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA,OAC7B,CAAA,CACA,EAAA,CAAG,UAAA,EAAY,CAAC,MAAM,MAAA,KAAW;AACjC,QAAA,IAAI,CAAC,UAAA,EAAY;AAChB,UAAA,UAAA,GAAa,IAAA;AACb,UAAA,MAAA,CAAO,IAAI,MAAM,CAAA,oCAAA,EAAuC,IAAI,IAAI,MAAA,CAAO,QAAA,EAAU,CAAA,CAAE,CAAC,CAAA;AAAA;AAErF,QAAA,IAAA,CAAK,OAAA,CAAQ,MAAM,MAAM,CAAA;AAAA,OACzB,EACA,EAAA,CAAG,YAAA,EAAc,KAAK,SAAA,CAAU,IAAA,CAAK,IAAI,CAAC,CAAA;AAE5C,MAAA,IAAA,CAAK,GAAG,OAAA,EAAQ;AAAA,KAChB,CAAA;AAAA;AACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeO,OAAA,GAAgB;AACtB,IAAA,IAAI,CAAC,KAAK,SAAA,EAAW;AACrB,IAAA,IAAA,CAAK,EAAA,CAAI,KAAA,CAAM,GAAA,EAAM,SAAS,CAAA;AAAA;AAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,IAAW,SAAA,GAAqB;AAC/B,IAAA,IAAI,CAAC,IAAA,CAAK,EAAA,EAAI,OAAO,KAAA;AACrB,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,EAAA,CAAG,gBAAA,KAAqB,WAAA;AAAA;AACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,IAAW,SAAA,GAAoB;AAC9B,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,MAAA,GAAS,KAAA,GAAQ,IAAA;AACvC,IAAA,OAAO,CAAA,EAAG,QAAQ,CAAA,GAAA,EAAM,IAAA,CAAK,IAAI,IAAI,IAAA,CAAK,IAAI,CAAA,EAAA,EAAK,IAAA,CAAK,OAAO,CAAA,UAAA,CAAA;AAAA;AAChE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,IAAW,OAAA,GAAkB;AAC5B,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,MAAA,GAAS,OAAA,GAAU,MAAA;AACzC,IAAA,OAAO,GAAG,QAAQ,CAAA,GAAA,EAAM,KAAK,IAAI,CAAA,CAAA,EAAI,KAAK,IAAI,CAAA,CAAA;AAAA;AAC/C;AAAA;AAAA;AAAA,EAKQ,MAAA,GAAe;AACtB,IAAA,IAAI,IAAA,CAAK,UAAA,EAAY,YAAA,CAAa,IAAA,CAAK,UAAU,CAAA;AACjD,IAAA,IAAA,CAAK,kBAAA,GAAqB,CAAA;AAC1B,IAAA,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,OAAA,EAAS,IAAI,CAAA;AAAA;AAChC;AAAA;AAAA;AAAA;AAAA,EAMQ,UAAU,GAAA,EAA6B;AAC9C,IAAA,QAAQ,IAAI,EAAA;AAAI,MACf,KAAK,OAAA;AACJ,QAAA,IAAI,GAAA,CAAI,SAAA,EAAW,IAAA,CAAK,SAAA,GAAY,GAAA,CAAI,SAAA;AACxC,QAAA,IAAI,CAAC,KAAK,eAAA,EAAiB;AAC1B,UAAA,IAAA,CAAK,eAAA,GAAkB,IAAA;AACvB,UAAAF,aAAA,CAAK,aAAA,CAAc,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,KAAM,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,OAAA,EAAS,CAAA,EAAG,IAAI,CAAC,CAAA;AAAA;AAE1E,QAAA;AAAA,MAED,KAAK,OAAA,EAAS;AAEb,QAAA,MAAM,EAAE,EAAA,EAAI,GAAG,KAAA,EAAM,GAAI,GAAA;AACzB,QAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,QAAA;AAAA;AACD,MAEA,KAAK,OAAA;AACJ,QAAA,IAAA,CAAK,aAAa,GAAG,CAAA;AACrB,QAAA;AAAA,MACD,KAAK,cAAA,EAAgB;AACpB,QAAA,MAAM,SAAS,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,IAAI,OAAO,CAAA;AACnD,QAAA,IAAI,CAAC,MAAA,EAAQ;AACb,QAAA,MAAA,CAAO,QAAQ,GAAA,CAAI,KAAA;AACnB,QAAA,IAAI,MAAA,CAAO,cAAc,OAAO,CAAA,SAAU,IAAA,CAAK,OAAA,EAAS,IAAI,KAAK,CAAA;AACjE,QAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,aAAa,CAAA,EAAG,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,aAAA,EAAe,MAAA,EAAQ,GAAA,CAAI,KAAK,CAAA;AACjG,QAAA;AAAA;AAIA;AAGF,IAAA,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,KAAA,EAAO,GAAA,EAAK,IAAI,CAAA;AAAA;AACnC;AAAA;AAAA;AAAA;AAAA,EAMQ,QAAQ,KAAA,EAAoB;AACnC,IAAA,IAAI,CAAC,KAAA,EAAO;AAEZ,IAAA,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,OAAA,EAAS,KAAA,EAAO,IAAI,CAAA;AACtC,IAAA,IAAA,CAAK,OAAA,EAAQ;AACb,IAAA,IAAA,CAAK,SAAA,EAAU;AAAA;AAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,OAAA,CAAQ,MAAc,MAAA,EAAsB;AACnD,IAAA,IAAA,CAAK,eAAA,GAAkB,KAAA;AACvB,IAAA,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,YAAA,EAAc,IAAA,EAAM,QAAQ,IAAI,CAAA;AAElD,IAAA,IAAA,CAAK,IAAI,kBAAA,EAAmB;AAC5B,IAAA,IAAA,CAAK,EAAA,GAAK,IAAA;AAEV,IAAA,QAAQ,IAAA;AAAM,MACb,KAAK,GAAA;AACJ,QAAA,IAAI,OAAO,QAAA,EAAS,KAAM,WAAW,OAAO,YAAA,CAAa,KAAK,UAAU,CAAA;AACxE,QAAA;AAAA,MAED,KAAK,IAAA;AAAA,MACL,KAAK,IAAA;AAAA,MACL,KAAK,IAAA;AAAA,MACL,KAAK,IAAA;AAAA,MACL,KAAK,IAAA;AACJ,QAAA,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,OAAA,EAAS,IAAI,KAAA,CAAM,CAAA,+BAAA,EAAkC,IAAI,CAAA,CAAA,EAAI,MAAM,CAAA,CAAE,CAAA,EAAG,IAAI,CAAA;AAC9F,QAAA;AAEA;AAGF,IAAA,IAAA,CAAK,SAAA,EAAU;AAAA;AAChB;AAAA;AAAA;AAAA,EAKQ,SAAA,GAAkB;AACzB,IAAA,IAAA,CAAK,kBAAA,EAAA;AACL,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,iBAAA,GAAoB,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,kBAAA,GAAqB,CAAC,CAAA,EAAG,GAAK,CAAA;AAE/F,IAAA,IAAA,CAAK,UAAA,GAAa,WAAW,YAAY;AACxC,MAAA,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,cAAA,EAAgB,IAAI,CAAA;AACtC,MAAA,MAAM,IAAA,CAAK,OAAA,EAAQ,CAAE,KAAA,CAAM,CAAC,KAAA,KAAU,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,OAAA,EAAS,KAAA,EAAO,IAAI,CAAC,CAAA;AAAA,OAC3E,KAAK,CAAA;AAAA;AACT,EAEQ,aAAa,IAAA,EAAe;AACnC,IAAA,MAAM,SAAS,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,KAAK,OAAO,CAAA;AACpD,IAAA,IAAI,CAAC,MAAA,EAAQ;AAEb,IAAA,QAAQ,KAAK,IAAA;AAAM,MAClB,KAAK,iBAAA;AACJ,QAAA,MAAA,CAAO,QAAQ,IAAA,CAAK,KAAA;AACpB,QAAA,MAAA,CAAO,SAAA,GAAY,KAAK,GAAA,EAAI;AAC5B,QAAA,IAAI,OAAO,aAAA,CAAc,YAAY,GAAG,MAAA,CAAO,IAAA,CAAK,cAAc,IAAI,CAAA;AACtE,QAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,kBAAkB,CAAA,OAAQ,OAAA,CAAQ,IAAA,CAAK,kBAAA,EAAoB,MAAA,EAAQ,IAAI,CAAA;AACtG,QAAA;AAAA,MACD,KAAK,eAAA;AACJ,QAAA,IAAI,IAAA,CAAK,WAAW,UAAA,EAAY;AAC/B,UAAA,MAAA,CAAO,KAAA,GAAQ,IAAA;AACf,UAAA,MAAA,CAAO,SAAA,GAAY,IAAA;AAAA;AAEpB,QAAA,IAAI,OAAO,aAAA,CAAc,UAAU,GAAG,MAAA,CAAO,IAAA,CAAK,YAAY,IAAI,CAAA;AAClE,QAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,gBAAgB,CAAA,OAAQ,OAAA,CAAQ,IAAA,CAAK,gBAAA,EAAkB,MAAA,EAAQ,IAAI,CAAA;AAClG,QAAA;AAAA,MACD,KAAK,qBAAA;AACJ,QAAA,IAAI,OAAO,aAAA,CAAc,gBAAgB,GAAG,MAAA,CAAO,IAAA,CAAK,kBAAkB,IAAI,CAAA;AAC9E,QAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,sBAAsB,CAAA,OAAQ,OAAA,CAAQ,IAAA,CAAK,sBAAA,EAAwB,MAAA,EAAQ,IAAI,CAAA;AAC9G,QAAA;AAAA,MACD,KAAK,iBAAA;AACJ,QAAA,IAAI,OAAO,aAAA,CAAc,YAAY,GAAG,MAAA,CAAO,IAAA,CAAK,cAAc,IAAI,CAAA;AACtE,QAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,kBAAkB,CAAA,OAAQ,OAAA,CAAQ,IAAA,CAAK,kBAAA,EAAoB,MAAA,EAAQ,IAAI,CAAA;AACtG,QAAA;AAAA,MACD,KAAK,sBAAA;AACJ,QAAA,MAAA,CAAO,KAAA,GAAQ,IAAA;AACf,QAAA,MAAA,CAAO,SAAA,GAAY,IAAA;AACnB,QAAA,IAAI,OAAO,aAAA,CAAc,iBAAiB,GAAG,MAAA,CAAO,IAAA,CAAK,mBAAmB,IAAI,CAAA;AAChF,QAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,uBAAuB,CAAA,OAAQ,OAAA,CAAQ,IAAA,CAAK,uBAAA,EAAyB,MAAA,EAAQ,IAAI,CAAA;AAChH,QAAA;AAAA,MACD;AACC,QAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,MAAA,EAAQ,CAAA,uBAAA,EAA2B,IAAA,CAA0B,IAAI,CAAA,CAAE,CAAA;AACrF,QAAA;AAAA;AACF;AAEF","file":"LavalinkNode.cjs","sourcesContent":["import { Rest } from \"./Rest\";\n\nimport { BetterWs } from \"cloudstorm\";\n\nimport type { Manager } from \"./Manager\";\nimport type { LavalinkNodeOptions } from \"./Types\";\nimport { VERSION } from \"../index\";\nimport { EventOP, OutboundHandshakeHeaders, Stats, StatsOP, WebsocketMessage } from \"lavalink-types\";\n\n/**\n * The LavalinkNode class handles the connection and communication with a Lavalink server.\n *\n * @summary Manages WebSocket connections to Lavalink servers and processes server events\n *\n * This class is responsible for establishing WebSocket connections to Lavalink,\n * handling reconnection logic, and processing incoming messages from the server.\n *\n * @remarks\n * LavalinkNode instances are typically created and managed by the {@link Manager} class,\n * which handles load balancing across multiple nodes and routing player actions\n * to the appropriate node.\n */\nexport class LavalinkNode {\n\t/**\n\t * The identifier for this Lavalink node. Used to distinguish between multiple nodes.\n\t *\n\t * @summary Unique identifier for the node\n\t * @remarks\n\t * This is a required property that must be unique across all nodes in your application.\n\t * It's used for identifying this node in logs and when selecting nodes for new players.\n\t */\n\tpublic id: string;\n\n\t/**\n\t * The hostname or IP address of the Lavalink server.\n\t *\n\t * @summary Server hostname or IP address\n\t * @remarks\n\t * This can be a domain name, IPv4, or IPv6 address pointing to your Lavalink server.\n\t */\n\tpublic readonly host = \"localhost\";\n\n\t/**\n\t * The port number that the Lavalink server is listening on.\n\t *\n\t * @summary Server port number\n\t * @remarks\n\t * This should match the port configured in your Lavalink server's application.yml.\n\t */\n\tpublic readonly port: number | string = 2333;\n\n\t/**\n\t * The time in milliseconds between reconnection attempts if the connection fails.\n\t *\n\t * @summary Reconnection delay in milliseconds\n\t * @remarks\n\t * Lower values will attempt reconnections more quickly, but might\n\t * cause excessive connection attempts during prolonged server outages.\n\t */\n\tpublic reconnectInterval = 10000;\n\n\t/**\n\t * The password used for authorization with the Lavalink server.\n\t *\n\t * @summary Authorization password for the Lavalink server\n\t * @remarks\n\t * This password must match the one configured in your Lavalink server's application.yml.\n\t * It's used in the Authorization header when establishing the WebSocket connection.\n\t */\n\tpublic readonly password = \"youshallnotpass\";\n\n\t/**\n\t * Whether to use secure connections (HTTPS/WSS) instead of HTTP/WS.\n\t *\n\t * @summary Secure connection flag for SSL/TLS\n\t * @remarks\n\t * When true, WebSocket connections will use WSS and REST requests will use HTTPS.\n\t * This is required when connecting to Lavalink servers behind SSL/TLS.\n\t */\n\tpublic readonly secure = false;\n\n\t/**\n\t * The WebSocket instance used for communication with the Lavalink server.\n\t *\n\t * @summary Active WebSocket connection to the Lavalink server\n\t * @remarks\n\t * When not connected to Lavalink, this property will be null.\n\t * You can check the {@link connected} property to determine connection status.\n\t */\n\tpublic ws: BetterWs | null = null;\n\n\t/**\n\t * The statistics received from the Lavalink server.\n\t *\n\t * @summary Server resource usage and player statistics\n\t * @remarks\n\t * Contains information about system resource usage, player counts, and audio frame statistics.\n\t * This is updated whenever the Lavalink server sends a stats update (typically every minute).\n\t * You can use these stats to implement node selection strategies in your application.\n\t */\n\tpublic stats: Stats = {\n\t\tplayers: 0,\n\t\tplayingPlayers: 0,\n\t\tuptime: 0,\n\t\tmemory: {\n\t\t\tused: 0,\n\t\t\tfree: 0,\n\t\t\tallocated: 0,\n\t\t\treservable: 0\n\t\t},\n\t\tcpu: {\n\t\t\tcores: 0,\n\t\t\tsystemLoad: 0,\n\t\t\tlavalinkLoad: 0\n\t\t},\n\t\tframeStats: {\n\t\t\tsent: 0,\n\t\t\tnulled: 0,\n\t\t\tdeficit: 0\n\t\t}\n\t};\n\n\t/**\n\t * Whether this node should attempt to resume the session when reconnecting.\n\t *\n\t * @summary Session resumption flag\n\t * @remarks\n\t * When true, the node will try to resume the previous session after a disconnect,\n\t * preserving player states and connections. This helps maintain playback during\n\t * brief disconnections or node restarts.\n\t */\n\tpublic resuming = false;\n\n\t/**\n\t * The timeout in seconds after which a disconnected session can no longer be resumed.\n\t *\n\t * @summary Maximum session resumption timeout in seconds\n\t * @remarks\n\t * This value is sent to the Lavalink server when configuring session resuming.\n\t * After this many seconds of disconnection, the session will be fully closed\n\t * and cannot be resumed.\n\t */\n\tpublic resumeTimeout = 60;\n\n\t/**\n\t * Custom data that can be attached to the node instance.\n\t *\n\t * @summary Custom application data storage\n\t * @remarks\n\t * Not used internally by Lavacord, available for application-specific needs.\n\t * You can use this property to store any data relevant to your implementation,\n\t * such as region information, feature flags, or custom metrics.\n\t */\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tpublic state?: any;\n\n\t/**\n\t * The unique session identifier provided by Lavalink on successful connection.\n\t *\n\t * @summary Lavalink session identifier\n\t * @remarks\n\t * This ID is used for resuming sessions and in certain REST API calls.\n\t * It's automatically assigned when connecting to the Lavalink server.\n\t */\n\tpublic sessionId?: string;\n\t/**\n\t * The version of the Lavalink protocol this node is using.\n\t *\n\t * @summary Lavalink protocol version\n\t * @remarks\n\t * This is set automatically when connecting to the Lavalink server.\n\t * It indicates which version of the Lavalink protocol this node supports.\n\t * The default value is \"4\", which corresponds to the latest stable version.\n\t *\n\t * @defaultValue \"4\"\n\t */\n\tpublic version = \"4\";\n\n\t/**\n\t * Timeout reference used for the reconnection mechanism.\n\t * This holds the NodeJS.Timeout instance used to schedule reconnection attempts.\n\t */\n\tprivate _reconnect?: NodeJS.Timeout;\n\n\t/**\n\t * Current reconnection attempt count for exponential backoff.\n\t */\n\tprivate _reconnectAttempts = 0;\n\n\t/**\n\t * Tracks whether the session has been updated with the Lavalink server.\n\t * Used internally to avoid redundant session update requests.\n\t */\n\tprivate _sessionUpdated = false;\n\n\t/**\n\t * Creates a new LavalinkNode instance.\n\t *\n\t * @summary Initializes a new Lavalink node connection\n\t * @param manager - The {@link Manager} instance that controls this node\n\t * @param options - Configuration options for this Lavalink node as defined in {@link LavalinkNodeOptions}\n\t */\n\tpublic constructor(\n\t\tpublic manager: Manager,\n\t\toptions: LavalinkNodeOptions\n\t) {\n\t\tthis.id = options.id;\n\n\t\tif (options.host) Object.defineProperty(this, \"host\", { value: options.host });\n\t\tif (options.port) Object.defineProperty(this, \"port\", { value: options.port });\n\t\tif (options.password) Object.defineProperty(this, \"password\", { value: options.password });\n\t\tif (options.secure !== undefined) Object.defineProperty(this, \"secure\", { value: options.secure });\n\t\tif (options.reconnectInterval) this.reconnectInterval = options.reconnectInterval;\n\t\tif (options.sessionId) this.sessionId = options.sessionId;\n\t\tif (options.resuming !== undefined) this.resuming = options.resuming;\n\t\tif (options.resumeTimeout) this.resumeTimeout = options.resumeTimeout;\n\t\tif (options.state) this.state = options.state;\n\t}\n\n\t/**\n\t * Establishes a connection to the Lavalink server.\n\t *\n\t * This method creates a new WebSocket connection to the configured Lavalink server.\n\t * If the node is already connected, it will close the existing connection first.\n\t * The method sets up event listeners for the WebSocket to handle messages, errors,\n\t * and connection state changes.\n\t *\n\t * Note: This method is primarily used internally by the {@link Manager} class.\n\t * Users typically should not call this method directly as the Manager handles\n\t * node connections automatically.\n\t *\n\t * @returns A promise that resolves when connected or rejects if connection fails\n\t * @throws {Error} If the connection fails due to network issues, authentication problems, or other errors\n\t */\n\tpublic async connect(): Promise<BetterWs> {\n\t\tif (this.connected) this.ws!.close(1000, \"reconnecting\");\n\n\t\tthis.version = await Rest.version(this)\n\t\t\t.then((str) => str.split(\".\")[0])\n\t\t\t.catch(() => \"4\");\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tlet isResolved = false;\n\n\t\t\t// Prepare headers for the WebSocket connection\n\t\t\tconst headers: OutboundHandshakeHeaders = {\n\t\t\t\tAuthorization: this.password,\n\t\t\t\t\"User-Id\": this.manager.userId!,\n\t\t\t\t\"Client-Name\": `Lavacord/${VERSION}`\n\t\t\t};\n\n\t\t\tif (this.sessionId && this.resuming) headers[\"Session-Id\"] = this.sessionId;\n\n\t\t\tthis.ws = new BetterWs(this.socketURL, { headers, encoding: \"json\" })\n\t\t\t\t.on(\"ws_open\", () => {\n\t\t\t\t\tisResolved = true;\n\t\t\t\t\tthis.onOpen();\n\t\t\t\t\tresolve(this.ws!);\n\t\t\t\t})\n\t\t\t\t.on(\"error\", (error) => {\n\t\t\t\t\tif (!isResolved) {\n\t\t\t\t\t\tisResolved = true;\n\t\t\t\t\t\treject(new Error(error));\n\t\t\t\t\t}\n\t\t\t\t\tthis.onError(new Error(error));\n\t\t\t\t})\n\t\t\t\t.on(\"ws_close\", (code, reason) => {\n\t\t\t\t\tif (!isResolved) {\n\t\t\t\t\t\tisResolved = true;\n\t\t\t\t\t\treject(new Error(`WebSocket closed during connection: ${code} ${reason.toString()}`));\n\t\t\t\t\t}\n\t\t\t\t\tthis.onClose(code, reason);\n\t\t\t\t})\n\t\t\t\t.on(\"ws_receive\", this.onMessage.bind(this));\n\n\t\t\tthis.ws.connect()\n\t\t});\n\t}\n\n\t/**\n\t * Gracefully closes the connection to the Lavalink server.\n\t *\n\t * This method closes the WebSocket connection with a normal closure code (1000)\n\t * and a reason of \"destroy\", indicating an intentional disconnection rather\n\t * than an error condition.\n\t *\n\t * Note: This method is primarily used internally by the {@link Manager} class.\n\t * Users typically should not call this method directly as the Manager handles\n\t * node disconnections automatically.\n\t *\n\t * @returns void\n\t */\n\tpublic destroy(): void {\n\t\tif (!this.connected) return;\n\t\tthis.ws!.close(1000, \"destroy\");\n\t}\n\n\t/**\n\t * Indicates whether this node is currently connected to the Lavalink server.\n\t *\n\t * @summary Connection status check\n\t * @remarks\n\t * Checks if the {@link ws} instance exists and if its ready state is 1.\n\t * This property is useful for verifying connection status before attempting operations\n\t * or implementing node selection strategies.\n\t *\n\t * @returns `true` if connected, `false` otherwise\n\t */\n\tpublic get connected(): boolean {\n\t\tif (!this.ws) return false;\n\t\treturn this.ws.sm.currentStateName === \"connected\";\n\t}\n\n\t/**\n\t * Gets the WebSocket URL for connecting to the Lavalink server.\n\t *\n\t * @summary WebSocket connection URL\n\t * @remarks\n\t * Returns either a secure (wss://) or insecure (ws://) WebSocket URL\n\t * based on the {@link secure} property configuration.\n\t *\n\t * @returns The complete WebSocket URL including protocol, host, port, and path\n\t */\n\tpublic get socketURL(): string {\n\t\tconst protocol = this.secure ? \"wss\" : \"ws\";\n\t\treturn `${protocol}://${this.host}:${this.port}/v${this.version}/websocket`;\n\t}\n\n\t/**\n\t * Gets the REST API base URL for the Lavalink server.\n\t *\n\t * @summary REST API base URL\n\t * @remarks\n\t * Returns either a secure (https://) or insecure (http://) REST URL\n\t * based on the {@link secure} property configuration.\n\t *\n\t * @returns The complete REST API base URL including protocol, host, port, and path\n\t */\n\tpublic get restURL(): string {\n\t\tconst protocol = this.secure ? \"https\" : \"http\";\n\t\treturn `${protocol}://${this.host}:${this.port}`;\n\t}\n\n\t/**\n\t * Handles the WebSocket 'open' event when a connection is established.\n\t */\n\tprivate onOpen(): void {\n\t\tif (this._reconnect) clearTimeout(this._reconnect);\n\t\tthis._reconnectAttempts = 0;\n\t\tthis.manager.emit(\"ready\", this);\n\t}\n\n\t/**\n\t * Processes incoming WebSocket messages from the Lavalink server.\n\t * @param msg - The raw data received from the WebSocket\n\t */\n\tprivate onMessage(msg: WebsocketMessage): void {\n\t\tswitch (msg.op) {\n\t\t\tcase \"ready\":\n\t\t\t\tif (msg.sessionId) this.sessionId = msg.sessionId;\n\t\t\t\tif (!this._sessionUpdated) {\n\t\t\t\t\tthis._sessionUpdated = true;\n\t\t\t\t\tRest.updateSession(this).catch((e) => this.manager.emit(\"error\", e, this));\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"stats\": {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\t\t\t\tconst { op, ...stats } = msg as StatsOP;\n\t\t\t\tthis.stats = stats;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"event\":\n\t\t\t\tthis._handleEvent(msg);\n\t\t\t\tbreak;\n\t\t\tcase \"playerUpdate\": {\n\t\t\t\tconst player = this.manager.players.get(msg.guildId);\n\t\t\t\tif (!player) break;\n\t\t\t\tplayer.state = msg.state;\n\t\t\t\tif (player.listenerCount(\"state\")) player.emit(\"state\", msg.state);\n\t\t\t\tif (this.manager.listenerCount(\"playerState\")) this.manager.emit(\"playerState\", player, msg.state);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\t\tthis.manager.emit(\"raw\", msg, this);\n\t}\n\n\t/**\n\t * Handles WebSocket errors.\n\t * @param error - The error received from the WebSocket\n\t */\n\tprivate onError(error: Error): void {\n\t\tif (!error) return;\n\n\t\tthis.manager.emit(\"error\", error, this);\n\t\tthis.destroy();\n\t\tthis.reconnect();\n\t}\n\n\t/**\n\t * Handles WebSocket closure.\n\t *\n\t * @param code - The WebSocket close code (see Lavalink API for code meanings)\n\t * @param reason - The reason why the WebSocket was closed\n\t */\n\tprivate onClose(code: number, reason: string): void {\n\t\tthis._sessionUpdated = false;\n\t\tthis.manager.emit(\"disconnect\", code, reason, this);\n\n\t\tthis.ws?.removeAllListeners();\n\t\tthis.ws = null;\n\n\t\tswitch (code) {\n\t\t\tcase 1000:\n\t\t\t\tif (reason.toString() === \"destroy\") return clearTimeout(this._reconnect);\n\t\t\t\tbreak;\n\n\t\t\tcase 4001:\n\t\t\tcase 4002:\n\t\t\tcase 4003:\n\t\t\tcase 4004:\n\t\t\tcase 4005:\n\t\t\t\tthis.manager.emit(\"error\", new Error(`Lavalink authentication error: ${code} ${reason}`), this);\n\t\t\t\treturn;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\t\tthis.reconnect();\n\t}\n\n\t/**\n\t * Initiates a reconnection attempt after a delay with exponential backoff.\n\t */\n\tprivate reconnect(): void {\n\t\tthis._reconnectAttempts++;\n\t\tconst delay = Math.min(this.reconnectInterval * Math.pow(2, this._reconnectAttempts - 1), 60000);\n\n\t\tthis._reconnect = setTimeout(async () => {\n\t\t\tthis.manager.emit(\"reconnecting\", this);\n\t\t\tawait this.connect().catch((error) => this.manager.emit(\"error\", error, this));\n\t\t}, delay);\n\t}\n\n\tprivate _handleEvent(data: EventOP) {\n\t\tconst player = this.manager.players.get(data.guildId);\n\t\tif (!player) return;\n\n\t\tswitch (data.type) {\n\t\t\tcase \"TrackStartEvent\":\n\t\t\t\tplayer.track = data.track;\n\t\t\t\tplayer.timestamp = Date.now();\n\t\t\t\tif (player.listenerCount(\"trackStart\")) player.emit(\"trackStart\", data);\n\t\t\t\tif (this.manager.listenerCount(\"playerTrackStart\")) this.manager.emit(\"playerTrackStart\", player, data);\n\t\t\t\tbreak;\n\t\t\tcase \"TrackEndEvent\":\n\t\t\t\tif (data.reason !== \"replaced\") {\n\t\t\t\t\tplayer.track = null;\n\t\t\t\t\tplayer.timestamp = null;\n\t\t\t\t}\n\t\t\t\tif (player.listenerCount(\"trackEnd\")) player.emit(\"trackEnd\", data);\n\t\t\t\tif (this.manager.listenerCount(\"playerTrackEnd\")) this.manager.emit(\"playerTrackEnd\", player, data);\n\t\t\t\tbreak;\n\t\t\tcase \"TrackExceptionEvent\":\n\t\t\t\tif (player.listenerCount(\"trackException\")) player.emit(\"trackException\", data);\n\t\t\t\tif (this.manager.listenerCount(\"playerTrackException\")) this.manager.emit(\"playerTrackException\", player, data);\n\t\t\t\tbreak;\n\t\t\tcase \"TrackStuckEvent\":\n\t\t\t\tif (player.listenerCount(\"trackStuck\")) player.emit(\"trackStuck\", data);\n\t\t\t\tif (this.manager.listenerCount(\"playerTrackStuck\")) this.manager.emit(\"playerTrackStuck\", player, data);\n\t\t\t\tbreak;\n\t\t\tcase \"WebSocketClosedEvent\":\n\t\t\t\tplayer.track = null;\n\t\t\t\tplayer.timestamp = null;\n\t\t\t\tif (player.listenerCount(\"webSocketClosed\")) player.emit(\"webSocketClosed\", data);\n\t\t\t\tif (this.manager.listenerCount(\"playerWebSocketClosed\")) this.manager.emit(\"playerWebSocketClosed\", player, data);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthis.manager.emit(\"warn\", `Unexpected event type: ${(data as { type: string }).type}`);\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n"]}
|