Skip to content

Commit

Permalink
feat: validation
Browse files Browse the repository at this point in the history
  • Loading branch information
0t4u committed Nov 4, 2024
1 parent 2d2b63c commit d9f533d
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 38 deletions.
12 changes: 11 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const Versions = {
};

export const ShoukakuDefaults: Required<ShoukakuOptions> = {
validate: false,
resume: false,
resumeTimeout: 30,
resumeByLibrary: false,
Expand Down
5 changes: 5 additions & 0 deletions src/Shoukaku.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ export interface NodeOption {
}

export interface ShoukakuOptions {
/**
* Whether to validate Lavalink responses (worse performance)
*/
validate?: boolean;
/**
* Whether to resume a connection on disconnect to Lavalink (Server Side) (Note: DOES NOT RESUME WHEN THE LAVALINK SERVER DIES)
*/
Expand Down Expand Up @@ -173,6 +177,7 @@ export class Shoukaku extends TypedEventEmitter<ShoukakuEvents> {
* @param connector A Discord library connector
* @param nodes An array that conforms to the NodeOption type that specifies nodes to connect to
* @param options Options to pass to create this Shoukaku instance
* @param options.validate Whether to validate Lavalink responses (worse performance)
* @param options.resume Whether to resume a connection on disconnect to Lavalink (Server Side) (Note: DOES NOT RESUME WHEN THE LAVALINK SERVER DIES)
* @param options.resumeTimeout Time to wait before lavalink starts to destroy the players of the disconnected client
* @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)
Expand Down
34 changes: 25 additions & 9 deletions src/guild/Player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -612,35 +612,47 @@ export class Player extends TypedEventEmitter<PlayerEvents> {
* GuildId of this player
*/
public readonly guildId: string;

/**
* Lavalink node this player is connected to
*/
public node: Node;

/**
* Base64 encoded data of the current track
*/
public track: string | null;

/**
* Global volume of the player
*/
public volume: number;

/**
* Pause status in current player
*/
public paused: boolean;

/**
* Ping represents the number of milliseconds between heartbeat and ack. Could be `-1` if not connected
*/
public ping: number;

/**
* Position in ms of current track
*/
public position: number;

/**
* Filters on current track
*/
public filters: FilterOptions;

/**
* Whether to validate Lavalink responses
*/
private readonly validate: boolean;

constructor(guildId: string, node: Node) {
super();
this.guildId = guildId;
Expand All @@ -651,6 +663,7 @@ export class Player extends TypedEventEmitter<PlayerEvents> {
this.position = 0;
this.ping = 0;
this.filters = {};
this.validate = this.node.manager.options.validate;
}

public get data(): UpdatePlayerInfo {
Expand Down Expand Up @@ -943,10 +956,11 @@ export class Player extends TypedEventEmitter<PlayerEvents> {
* Handle player update data
*/
public onPlayerUpdate(json: PlayerUpdate): void {
const { position, ping } = json.state;
const data = this.validate ? PlayerUpdate.parse(json) : json;
const { position, ping } = data.state;
this.position = position;
this.ping = ping;
this.emit('update', json);
this.emit('update', data);
}

/**
Expand All @@ -956,21 +970,23 @@ export class Player extends TypedEventEmitter<PlayerEvents> {
*/
public onPlayerEvent(json: TrackStartEvent | TrackEndEvent | TrackStuckEvent | TrackExceptionEvent | WebSocketClosedEvent): void {
switch (json.type) {
case PlayerEventType.enum.TRACK_START_EVENT:
if (this.track) this.track = json.track.encoded;
this.emit('start', json);
case PlayerEventType.enum.TRACK_START_EVENT: {
const data = this.validate ? TrackStartEvent.parse(json) : json;
if (this.track) this.track = data.track.encoded;
this.emit('start', data);
break;
}
case PlayerEventType.enum.TRACK_END_EVENT:
this.emit('end', json);
this.emit('end', this.validate ? TrackEndEvent.parse(json) : json);
break;
case PlayerEventType.enum.TRACK_STUCK_EVENT:
this.emit('stuck', json);
this.emit('stuck', this.validate ? TrackStuckEvent.parse(json) : json);
break;
case PlayerEventType.enum.TRACK_EXCEPTION_EVENT:
this.emit('exception', json);
this.emit('exception', this.validate ? TrackExceptionEvent.parse(json) : json);
break;
case PlayerEventType.enum.WEBSOCKET_CLOSED_EVENT:
this.emit('closed', json);
this.emit('closed', this.validate ? WebSocketClosedEvent.parse(json) : json);
break;
default:
this.node.manager.emit(
Expand Down
40 changes: 31 additions & 9 deletions src/node/Node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,58 +309,77 @@ export class Node extends TypedEventEmitter<NodeEvents> {
* Shoukaku class
*/
public readonly manager: Shoukaku;

/**
* Lavalink rest API
*/
public readonly rest: Rest;

/**
* Name of this node
*/
public readonly name: string;

/**
* Group in which this node is contained
*/
public readonly group?: string;

/**
* URL of Lavalink
*/
private readonly url: string;

/**
* Credentials to access Lavalink
*/
private readonly auth: string;

/**
* The number of reconnects to Lavalink
*/

public reconnects: number;
/**
* The state of this connection
*/
public state: State;

/**
* Statistics from Lavalink
*/
public stats: Stats | null;

/**
* Information about lavalink node
*/
public info: NodeInfo | null;

/**
* Websocket instance
*/
public ws: Websocket | null;

/**
* SessionId of this Lavalink connection (not to be confused with Discord SessionId)
*/
public sessionId: string | null;

/**
* Boolean that represents if the node has initialized once
*/
protected initialized: boolean;

/**
* Boolean that represents if this connection is destroyed
*/
protected destroyed: boolean;

/**
* Whether to validate Lavalink responses
*/
private readonly validate: boolean;

/**
* @param manager Shoukaku instance
* @param options Options on creating this node
Expand All @@ -386,6 +405,7 @@ export class Node extends TypedEventEmitter<NodeEvents> {
this.sessionId = null;
this.initialized = false;
this.destroyed = false;
this.validate = this.manager.options.validate;
}

/**
Expand Down Expand Up @@ -440,7 +460,7 @@ export class Node extends TypedEventEmitter<NodeEvents> {
this.emit('debug', `[Socket] -> [${this.name}] : Connecting to ${this.url} ...`);

const url = new URL(this.url);
this.ws = new Websocket(url.toString(), { headers } as Websocket.ClientOptions);
this.ws = new Websocket(url.toString(), { headers });

this.ws.once('upgrade', response => this.open(response));
this.ws.once('close', (...args) => this.close(...args));
Expand Down Expand Up @@ -484,20 +504,22 @@ export class Node extends TypedEventEmitter<NodeEvents> {
switch (json.op) {
case OpCodes.enum.STATS:
this.emit('debug', `[Socket] <- [${this.name}] : Node Status Update | Server Load: ${this.penalties}`);
this.stats = json;
this.stats = this.validate ? Stats.parse(json) : json;
break;
case OpCodes.enum.READY: {
if (!json.sessionId) {
const data = this.validate ? Ready.parse(json) : json;

if (!data.sessionId) {
this.emit('debug', `[Socket] -> [${this.name}] : No session id found from ready op? disconnecting and reconnecting to avoid issues`);
return this.internalDisconnect(1000);
}

this.sessionId = json.sessionId;
this.sessionId = data.sessionId;

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

let resumedByLibrary = false;
if (!json.resumed && Boolean(this.initialized && (players.length && this.manager.options.resumeByLibrary))) {
if (!data.resumed && Boolean(this.initialized && (players.length && this.manager.options.resumeByLibrary))) {
try {
await this.resumePlayers();
resumedByLibrary = true;
Expand All @@ -507,8 +529,8 @@ export class Node extends TypedEventEmitter<NodeEvents> {
}

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

if (this.manager.options.resume) {
await this.rest.updateSession(this.manager.options.resume, this.manager.options.resumeTimeout);
Expand All @@ -519,12 +541,12 @@ export class Node extends TypedEventEmitter<NodeEvents> {
}
case OpCodes.enum.EVENT:
case OpCodes.enum.PLAYER_UPDATE: {
const player = this.manager.players.get(json.guildId);
const player = 'guildId' in json && this.manager.players.get(json.guildId);
if (!player) return;
if (json.op === OpCodes.enum.EVENT)
player.onPlayerEvent(json);
else
player.onPlayerUpdate(json);
player.onPlayerUpdate(this.validate ? PlayerUpdate.parse(json) : json);
break;
}
default:
Expand Down
Loading

0 comments on commit d9f533d

Please sign in to comment.