Skip to content

Commit a5e3516

Browse files
committed
feat: validation
1 parent abb3e5b commit a5e3516

File tree

6 files changed

+110
-38
lines changed

6 files changed

+110
-38
lines changed

package-lock.json

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export const Versions = {
4040
};
4141

4242
export const ShoukakuDefaults: Required<ShoukakuOptions> = {
43+
validate: false,
4344
resume: false,
4445
resumeTimeout: 30,
4546
resumeByLibrary: false,

src/Shoukaku.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ export interface NodeOption {
4646
}
4747

4848
export interface ShoukakuOptions {
49+
/**
50+
* Whether to validate Lavalink responses (worse performance)
51+
*/
52+
validate?: boolean;
4953
/**
5054
* Whether to resume a connection on disconnect to Lavalink (Server Side) (Note: DOES NOT RESUME WHEN THE LAVALINK SERVER DIES)
5155
*/
@@ -173,6 +177,7 @@ export class Shoukaku extends TypedEventEmitter<ShoukakuEvents> {
173177
* @param connector A Discord library connector
174178
* @param nodes An array that conforms to the NodeOption type that specifies nodes to connect to
175179
* @param options Options to pass to create this Shoukaku instance
180+
* @param options.validate Whether to validate Lavalink responses (worse performance)
176181
* @param options.resume Whether to resume a connection on disconnect to Lavalink (Server Side) (Note: DOES NOT RESUME WHEN THE LAVALINK SERVER DIES)
177182
* @param options.resumeTimeout Time to wait before lavalink starts to destroy the players of the disconnected client
178183
* @param options.resumeByLibrary Whether to resume the players by doing it in the library side (Client Side) (Note: TRIES TO RESUME REGARDLESS OF WHAT HAPPENED ON A LAVALINK SERVER)

src/guild/Player.ts

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -612,35 +612,47 @@ export class Player extends TypedEventEmitter<PlayerEvents> {
612612
* GuildId of this player
613613
*/
614614
public readonly guildId: string;
615+
615616
/**
616617
* Lavalink node this player is connected to
617618
*/
618619
public node: Node;
620+
619621
/**
620622
* Base64 encoded data of the current track
621623
*/
622624
public track: string | null;
625+
623626
/**
624627
* Global volume of the player
625628
*/
626629
public volume: number;
630+
627631
/**
628632
* Pause status in current player
629633
*/
630634
public paused: boolean;
635+
631636
/**
632637
* Ping represents the number of milliseconds between heartbeat and ack. Could be `-1` if not connected
633638
*/
634639
public ping: number;
640+
635641
/**
636642
* Position in ms of current track
637643
*/
638644
public position: number;
645+
639646
/**
640647
* Filters on current track
641648
*/
642649
public filters: FilterOptions;
643650

651+
/**
652+
* Whether to validate Lavalink responses
653+
*/
654+
private readonly validate: boolean;
655+
644656
constructor(guildId: string, node: Node) {
645657
super();
646658
this.guildId = guildId;
@@ -651,6 +663,7 @@ export class Player extends TypedEventEmitter<PlayerEvents> {
651663
this.position = 0;
652664
this.ping = 0;
653665
this.filters = {};
666+
this.validate = this.node.manager.options.validate;
654667
}
655668

656669
public get data(): UpdatePlayerInfo {
@@ -943,10 +956,11 @@ export class Player extends TypedEventEmitter<PlayerEvents> {
943956
* Handle player update data
944957
*/
945958
public onPlayerUpdate(json: PlayerUpdate): void {
946-
const { position, ping } = json.state;
959+
const data = this.validate ? PlayerUpdate.parse(json) : json;
960+
const { position, ping } = data.state;
947961
this.position = position;
948962
this.ping = ping;
949-
this.emit('update', json);
963+
this.emit('update', data);
950964
}
951965

952966
/**
@@ -956,21 +970,23 @@ export class Player extends TypedEventEmitter<PlayerEvents> {
956970
*/
957971
public onPlayerEvent(json: TrackStartEvent | TrackEndEvent | TrackStuckEvent | TrackExceptionEvent | WebSocketClosedEvent): void {
958972
switch (json.type) {
959-
case PlayerEventType.enum.TRACK_START_EVENT:
960-
if (this.track) this.track = json.track.encoded;
961-
this.emit('start', json);
973+
case PlayerEventType.enum.TRACK_START_EVENT: {
974+
const data = this.validate ? TrackStartEvent.parse(json) : json;
975+
if (this.track) this.track = data.track.encoded;
976+
this.emit('start', data);
962977
break;
978+
}
963979
case PlayerEventType.enum.TRACK_END_EVENT:
964-
this.emit('end', json);
980+
this.emit('end', this.validate ? TrackEndEvent.parse(json) : json);
965981
break;
966982
case PlayerEventType.enum.TRACK_STUCK_EVENT:
967-
this.emit('stuck', json);
983+
this.emit('stuck', this.validate ? TrackStuckEvent.parse(json) : json);
968984
break;
969985
case PlayerEventType.enum.TRACK_EXCEPTION_EVENT:
970-
this.emit('exception', json);
986+
this.emit('exception', this.validate ? TrackExceptionEvent.parse(json) : json);
971987
break;
972988
case PlayerEventType.enum.WEBSOCKET_CLOSED_EVENT:
973-
this.emit('closed', json);
989+
this.emit('closed', this.validate ? WebSocketClosedEvent.parse(json) : json);
974990
break;
975991
default:
976992
this.node.manager.emit(

src/node/Node.ts

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -308,58 +308,77 @@ export class Node extends TypedEventEmitter<NodeEvents> {
308308
* Shoukaku class
309309
*/
310310
public readonly manager: Shoukaku;
311+
311312
/**
312313
* Lavalink rest API
313314
*/
314315
public readonly rest: Rest;
316+
315317
/**
316318
* Name of this node
317319
*/
318320
public readonly name: string;
321+
319322
/**
320323
* Group in which this node is contained
321324
*/
322325
public readonly group?: string;
326+
323327
/**
324328
* URL of Lavalink
325329
*/
326330
private readonly url: string;
331+
327332
/**
328333
* Credentials to access Lavalink
329334
*/
330335
private readonly auth: string;
336+
331337
/**
332338
* The number of reconnects to Lavalink
333339
*/
340+
334341
public reconnects: number;
335342
/**
336343
* The state of this connection
337344
*/
338345
public state: State;
346+
339347
/**
340348
* Statistics from Lavalink
341349
*/
342350
public stats: Stats | null;
351+
343352
/**
344353
* Information about lavalink node
345354
*/
346355
public info: NodeInfo | null;
356+
347357
/**
348358
* Websocket instance
349359
*/
350360
public ws: Websocket | null;
361+
351362
/**
352363
* SessionId of this Lavalink connection (not to be confused with Discord SessionId)
353364
*/
354365
public sessionId: string | null;
366+
355367
/**
356368
* Boolean that represents if the node has initialized once
357369
*/
358370
protected initialized: boolean;
371+
359372
/**
360373
* Boolean that represents if this connection is destroyed
361374
*/
362375
protected destroyed: boolean;
376+
377+
/**
378+
* Whether to validate Lavalink responses
379+
*/
380+
private readonly validate: boolean;
381+
363382
/**
364383
* @param manager Shoukaku instance
365384
* @param options Options on creating this node
@@ -385,6 +404,7 @@ export class Node extends TypedEventEmitter<NodeEvents> {
385404
this.sessionId = null;
386405
this.initialized = false;
387406
this.destroyed = false;
407+
this.validate = this.manager.options.validate;
388408
}
389409

390410
/**
@@ -439,7 +459,7 @@ export class Node extends TypedEventEmitter<NodeEvents> {
439459
this.emit('debug', `[Socket] -> [${this.name}] : Connecting to ${this.url} ...`);
440460

441461
const url = new URL(this.url);
442-
this.ws = new Websocket(url.toString(), { headers } as Websocket.ClientOptions);
462+
this.ws = new Websocket(url.toString(), { headers });
443463

444464
this.ws.once('upgrade', response => this.open(response));
445465
this.ws.once('close', (...args) => this.close(...args));
@@ -483,20 +503,22 @@ export class Node extends TypedEventEmitter<NodeEvents> {
483503
switch (json.op) {
484504
case OpCodes.enum.STATS:
485505
this.emit('debug', `[Socket] <- [${this.name}] : Node Status Update | Server Load: ${this.penalties}`);
486-
this.stats = json;
506+
this.stats = this.validate ? Stats.parse(json) : json;
487507
break;
488508
case OpCodes.enum.READY: {
489-
if (!json.sessionId) {
509+
const data = this.validate ? Ready.parse(json) : json;
510+
511+
if (!data.sessionId) {
490512
this.emit('debug', `[Socket] -> [${this.name}] : No session id found from ready op? disconnecting and reconnecting to avoid issues`);
491513
return this.internalDisconnect(1000);
492514
}
493515

494-
this.sessionId = json.sessionId;
516+
this.sessionId = data.sessionId;
495517

496518
const players = [ ...this.manager.players.values() ].filter(player => player.node.name === this.name);
497519

498520
let resumedByLibrary = false;
499-
if (!json.resumed && Boolean(this.initialized && (players.length && this.manager.options.resumeByLibrary))) {
521+
if (!data.resumed && Boolean(this.initialized && (players.length && this.manager.options.resumeByLibrary))) {
500522
try {
501523
await this.resumePlayers();
502524
resumedByLibrary = true;
@@ -506,8 +528,8 @@ export class Node extends TypedEventEmitter<NodeEvents> {
506528
}
507529

508530
this.state = State.CONNECTED;
509-
this.emit('debug', `[Socket] -> [${this.name}] : Lavalink is ready! | Lavalink resume: ${json.resumed} | Lib resume: ${resumedByLibrary}`);
510-
this.emit('ready', json.resumed, resumedByLibrary);
531+
this.emit('debug', `[Socket] -> [${this.name}] : Lavalink is ready! | Lavalink resume: ${data.resumed} | Lib resume: ${resumedByLibrary}`);
532+
this.emit('ready', data.resumed, resumedByLibrary);
511533

512534
if (this.manager.options.resume) {
513535
await this.rest.updateSession(this.manager.options.resume, this.manager.options.resumeTimeout);
@@ -518,12 +540,12 @@ export class Node extends TypedEventEmitter<NodeEvents> {
518540
}
519541
case OpCodes.enum.EVENT:
520542
case OpCodes.enum.PLAYER_UPDATE: {
521-
const player = this.manager.players.get(json.guildId);
543+
const player = 'guildId' in json && this.manager.players.get(json.guildId);
522544
if (!player) return;
523545
if (json.op === OpCodes.enum.EVENT)
524546
player.onPlayerEvent(json);
525547
else
526-
player.onPlayerUpdate(json);
548+
player.onPlayerUpdate(this.validate ? PlayerUpdate.parse(json) : json);
527549
break;
528550
}
529551
default:

0 commit comments

Comments
 (0)