Skip to content

Commit

Permalink
Added debug event
Browse files Browse the repository at this point in the history
Added debug event (manager.on("debug", stringMessage)")

for developers to see more stuff :)
  • Loading branch information
Vexify4103 committed Oct 27, 2024
1 parent 626ed65 commit 9f22fc7
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 8 deletions.
14 changes: 14 additions & 0 deletions src/structures/Manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export class Manager extends EventEmitter {

/** Loads player states from the JSON file. */
public async loadPlayerStates(nodeId: string): Promise<void> {
this.emit("debug", "[MANAGER] Loading saved players.");
// Changed to async and added Promise<void>
const node = this.nodes.get(nodeId);
if (!node) throw new Error(`Could not find node: ${nodeId}`);
Expand Down Expand Up @@ -175,6 +176,7 @@ export class Manager extends EventEmitter {
}
}
}
this.emit("debug", "[MANAGER] Finished loading saved players.");
}

/** Gets each player's JSON file */
Expand All @@ -195,6 +197,7 @@ export class Manager extends EventEmitter {
if (!player || player.state === "DISCONNECTED" || !player.voiceChannel) return this.cleanupInactivePlayers();
const serializedPlayer = this.serializePlayer(player) as unknown as Player;
fs.writeFileSync(playerStateFilePath, JSON.stringify(serializedPlayer, null, 2), "utf-8");
this.emit("debug", `[MANAGER] Saving player: ${guildId} at location: ${playerStateFilePath}`);
}

/** Serializes a Player instance to avoid circular references. */
Expand Down Expand Up @@ -249,6 +252,7 @@ export class Manager extends EventEmitter {
if (!activeGuildIds.has(guildId)) {
const filePath = path.join(playerStatesDir, file);
fs.unlinkSync(filePath);
this.emit("debug", `[MANAGER] Deleting inactive player: ${guildId}`);
}
}
}
Expand Down Expand Up @@ -439,6 +443,8 @@ export class Manager extends EventEmitter {
search = `${_source}:${search}`;
}

this.emit("debug", `[MANAGER] Performing ${_source} search for: ${_query}`);

try {
const res = (await node.rest.get(`/v4/loadtracks?identifier=${encodeURIComponent(search)}`)) as LavalinkResponse;

Expand Down Expand Up @@ -499,6 +505,7 @@ export class Manager extends EventEmitter {
}
}

this.emit("debug", `[MANAGER] Result ${_source} search for: ${_query}: ${JSON.stringify(result)}`);
return result;
} catch (err) {
throw new Error(err);
Expand Down Expand Up @@ -583,6 +590,7 @@ export class Manager extends EventEmitter {
* @param tracks
*/
public decodeTracks(tracks: string[]): Promise<TrackData[]> {
this.emit("debug", `[MANAGER] Decoding tracks: ${JSON.stringify(tracks)}`);
return new Promise(async (resolve, reject) => {
const node = this.nodes.first();
if (!node) throw new Error("No available nodes.");
Expand Down Expand Up @@ -615,6 +623,7 @@ export class Manager extends EventEmitter {
return this.players.get(options.guild);
}

this.emit("debug", `[MANAGER] Creating new player with options: ${JSON.stringify(options)}`);
return new (Structure.get("Player"))(options);
}

Expand All @@ -631,6 +640,7 @@ export class Manager extends EventEmitter {
* @param guild
*/
public destroy(guild: string): void {
this.emit("debug", `[MANAGER] Destroying player: ${guild}`);
this.players.delete(guild);
this.cleanupInactivePlayers();
}
Expand All @@ -644,6 +654,7 @@ export class Manager extends EventEmitter {
return this.nodes.get(options.identifier || options.host);
}

this.emit("debug", `[MANAGER] Creating new node with options: ${JSON.stringify(options)}`);
return new (Structure.get("Node"))(options);
}

Expand All @@ -654,6 +665,7 @@ export class Manager extends EventEmitter {
public destroyNode(identifier: string): void {
const node = this.nodes.get(identifier);
if (!node) return;
this.emit("debug", `[MANAGER] Destroying node: ${identifier}`);
node.destroy();
this.nodes.delete(identifier);
}
Expand All @@ -665,6 +677,7 @@ export class Manager extends EventEmitter {
public async updateVoiceState(data: VoicePacket | VoiceServer | VoiceState): Promise<void> {
if ("t" in data && !["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(data.t)) return;

this.emit("debug", `[MANAGER] Updating voice state: ${JSON.stringify(data)}`);
const update = "d" in data ? data.d : data;

if (!update || (!("token" in update) && !("session_id" in update))) return;
Expand Down Expand Up @@ -822,6 +835,7 @@ export interface PlaylistData {
}

export interface ManagerEvents {
debug: [info: string];
nodeCreate: [node: Node];
nodeDestroy: [node: Node];
nodeConnect: [node: Node];
Expand Down
60 changes: 58 additions & 2 deletions src/structures/Node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export class Node {

this.manager.nodes.set(this.options.identifier, this);
this.manager.emit("nodeCreate", this);
this.rest = new Rest(this);
this.rest = new Rest(this, this.manager);

this.createSessionIdsFile();
this.loadSessionIds();
Expand All @@ -129,20 +129,23 @@ export class Node {
/** Creates the sessionIds.json file if it doesn't exist. */
public createSessionIdsFile(): void {
if (!fs.existsSync(sessionIdsFilePath)) {
this.manager.emit("debug", `[NODE] Creating sessionId file at: ${sessionIdsFilePath}`);
fs.writeFileSync(sessionIdsFilePath, JSON.stringify({}), "utf-8");
}
}

/** Loads session IDs from the sessionIds.json file. */
public loadSessionIds(): void {
if (fs.existsSync(sessionIdsFilePath)) {
this.manager.emit("debug", `[NODE] Loading sessionIds from file: ${sessionIdsFilePath}`);
const sessionIdsData = fs.readFileSync(sessionIdsFilePath, "utf-8");
sessionIdsMap = new Map(Object.entries(JSON.parse(sessionIdsData)));
}
}

/** Updates the session ID in the sessionIds.json file. */
public updateSessionId(): void {
this.manager.emit("debug", `[NODE] Updating sessionIds to file: ${sessionIdsFilePath}`);
sessionIdsMap.set(this.options.identifier, this.sessionId);
fs.writeFileSync(sessionIdsFilePath, JSON.stringify(Object.fromEntries(sessionIdsMap)));
}
Expand All @@ -169,12 +172,36 @@ export class Node {
this.socket.on("close", this.close.bind(this));
this.socket.on("message", this.message.bind(this));
this.socket.on("error", this.error.bind(this));

const debugInfo = {
connected: this.connected,
address: this.address,
sessionId: this.sessionId,
options: {
clientId: this.manager.options.clientId,
clientName: this.manager.options.clientName,
secure: this.options.secure,
identifier: this.options.identifier,
},
};

this.manager.emit("debug", `[NODE] Connecting ${JSON.stringify(debugInfo)}`);
}

/** Destroys the Node and all players connected with it. */
public destroy(): void {
if (!this.connected) return;

const debugInfo = {
connected: this.connected,
identifier: this.options.identifier,
address: this.address,
sessionId: this.sessionId,
playerCount: this.manager.players.filter((p) => p.node == this).size,
};

this.manager.emit("debug", `[NODE] Destroying node: ${JSON.stringify(debugInfo)}`);

const players = this.manager.players.filter((p) => p.node == this);
if (players.size) players.forEach((p) => p.destroy());

Expand All @@ -190,13 +217,23 @@ export class Node {
}

private reconnect(): void {
const debugInfo = {
identifier: this.options.identifier,
connected: this.connected,
reconnectAttempts: this.reconnectAttempts,
retryAmount: this.options.retryAmount,
retryDelay: this.options.retryDelay,
};

this.manager.emit("debug", `[NODE] Reconnecting node: ${JSON.stringify(debugInfo)}`);

this.reconnectTimeout = setTimeout(() => {
if (this.reconnectAttempts >= this.options.retryAmount) {
const error = new Error(`Unable to connect after ${this.options.retryAmount} attempts.`);

this.manager.emit("nodeError", this, error);
return this.destroy();
}

this.socket?.removeAllListeners();
this.socket = null;
this.manager.emit("nodeReconnect", this);
Expand All @@ -207,16 +244,32 @@ export class Node {

protected open(): void {
if (this.reconnectTimeout) clearTimeout(this.reconnectTimeout);
const debugInfo = {
identifier: this.options.identifier,
connected: this.connected,
};
this.manager.emit("nodeConnect", this);
this.manager.emit("debug", `[NODE] Connected node: ${JSON.stringify(debugInfo)}`);
}

protected close(code: number, reason: string): void {
const debugInfo = {
identifier: this.options.identifier,
code,
reason,
};
this.manager.emit("nodeDisconnect", this, { code, reason });
this.manager.emit("debug", `[NODE] Disconnected node: ${JSON.stringify(debugInfo)}`);
if (code !== 1000 || reason !== "destroy") this.reconnect();
}

protected error(error: Error): void {
if (!error) return;
const debugInfo = {
identifier: this.options.identifier,
error: error.message,
};
this.manager.emit("debug", `[NODE] Error on node: ${JSON.stringify(debugInfo)}`);
this.manager.emit("nodeError", this, error);
}

Expand All @@ -241,9 +294,11 @@ export class Node {
if (player) player.position = payload.state.position || 0;
break;
case "event":
this.manager.emit("debug", `[NODE] Node message: ${JSON.stringify(payload)}`);
this.handleEvent(payload);
break;
case "ready":
this.manager.emit("debug", `[NODE] Node message: ${JSON.stringify(payload)}`);
this.rest.setSessionId(payload.sessionId);
this.sessionId = payload.sessionId;
this.updateSessionId(); // Call to update session ID
Expand Down Expand Up @@ -535,6 +590,7 @@ export class Node {

protected socketClosed(player: Player, payload: WebSocketClosedEvent): void {
this.manager.emit("socketClosed", player, payload);
this.manager.emit("debug", `[NODE] Websocket closed for player: ${player.guild} with payload: ${JSON.stringify(payload)}`);
}

private sponsorBlockSegmentLoaded(player: Player, track: Track, payload: SponsorBlockSegmentsLoaded) {
Expand Down
2 changes: 1 addition & 1 deletion src/structures/Player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export class Player {
public connect(): this {
if (!this.voiceChannel) throw new RangeError("No voice channel has been set.");
this.state = "CONNECTING";

const oldPlayer = { ...this };

this.manager.options.send(this.guild, {
Expand Down
22 changes: 18 additions & 4 deletions src/structures/Queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ export class Queue extends Array<Track | UnresolvedTrack> {
* @param [offset=null]
*/
public add(track: (Track | UnresolvedTrack) | (Track | UnresolvedTrack)[], offset?: number): void {
const trackInfo = Array.isArray(track) ? track.map((t) => JSON.stringify(t, null, 2)).join(", ") : JSON.stringify(track, null, 2);
this.manager.emit("debug", `[QUEUE] Added ${Array.isArray(track) ? track.length : 1} track(s) to queue: ${trackInfo}`);

const oldPlayer = { ...this.manager.players.get(this.guild) };
if (!TrackUtils.validate(track)) {
throw new RangeError('Track must be a "Track" or "Track[]".');
Expand Down Expand Up @@ -100,22 +103,29 @@ export class Queue extends Array<Track | UnresolvedTrack> {

public remove(startOrPosition = 0, end?: number): (Track | UnresolvedTrack)[] {
const oldPlayer = { ...this.manager.players.get(this.guild) };

if (typeof end !== "undefined") {
// Validate input for `start` and `end`
if (isNaN(Number(startOrPosition)) || isNaN(Number(end))) {
throw new RangeError(`Missing "start" or "end" parameter.`);
throw new RangeError(`Invalid "start" or "end" parameter: start = ${startOrPosition}, end = ${end}`);
}

if (startOrPosition >= end || startOrPosition >= this.length) {
throw new RangeError("Invalid start or end values.");
throw new RangeError("Invalid range: start should be less than end and within queue length.");
}

this.splice(startOrPosition, end - startOrPosition);
const removedTracks = this.splice(startOrPosition, end - startOrPosition);
this.manager.emit("debug", `[QUEUE] Removed ${removedTracks.length} track(s) from player: ${this.guild} from position ${startOrPosition} to ${end}.`);
this.manager.emit("playerStateUpdate", oldPlayer, this.manager.players.get(this.guild), "queueChange");

return;
}

this.splice(startOrPosition, 1);
// Single item removal when no end specified
const removedTrack = this.splice(startOrPosition, 1);
this.manager.emit("debug", `[QUEUE] Removed 1 track from player: ${this.guild} from position ${startOrPosition}: ${JSON.stringify(removedTrack[0], null, 2)}`);
this.manager.emit("playerStateUpdate", oldPlayer, this.manager.players.get(this.guild), "queueChange");

return;
}

Expand All @@ -124,6 +134,7 @@ export class Queue extends Array<Track | UnresolvedTrack> {
const oldPlayer = { ...this.manager.players.get(this.guild) };
this.splice(0);
this.manager.emit("playerStateUpdate", oldPlayer, this.manager.players.get(this.guild), "queueChange");
this.manager.emit("debug", `[QUEUE] Cleared the queue for: ${this.guild}`);
}

/** Shuffles the queue. */
Expand All @@ -134,6 +145,7 @@ export class Queue extends Array<Track | UnresolvedTrack> {
[this[i], this[j]] = [this[j], this[i]];
}
this.manager.emit("playerStateUpdate", oldPlayer, this.manager.players.get(this.guild), "queueChange");
this.manager.emit("debug", `[QUEUE] Shuffled the queue for: ${this.guild}`);
}

public userBlockShuffle() {
Expand Down Expand Up @@ -164,6 +176,7 @@ export class Queue extends Array<Track | UnresolvedTrack> {
this.splice(0);
this.add(shuffledQueue);
this.manager.emit("playerStateUpdate", oldPlayer, this.manager.players.get(this.guild), "queueChange");
this.manager.emit("debug", `[QUEUE] userBlockShuffled the queue for: ${this.guild}`);
}

public roundRobinShuffle() {
Expand Down Expand Up @@ -204,5 +217,6 @@ export class Queue extends Array<Track | UnresolvedTrack> {
this.splice(0);
this.add(shuffledQueue);
this.manager.emit("playerStateUpdate", oldPlayer, this.manager.players.get(this.guild), "queueChange");
this.manager.emit("debug", `[QUEUE] roundRobinShuffled the queue for: ${this.guild}`);
}
}
11 changes: 10 additions & 1 deletion src/structures/Rest.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Node } from "./Node";
import axios, { AxiosRequestConfig } from "axios";
import { Manager } from "./Manager";

/** Handles the requests sent to the Lavalink REST API. */
export class Rest {
Expand All @@ -11,12 +12,15 @@ export class Rest {
private readonly password: string;
/** The URL of the Node. */
private readonly url: string;
/** The Manager instance. */
public manager: Manager;

constructor(node: Node) {
constructor(node: Node, manager: Manager) {
this.node = node;
this.url = `http${node.options.secure ? "s" : ""}://${node.options.host}:${node.options.port}`;
this.sessionId = node.sessionId;
this.password = node.options.password;
this.manager = manager;
}

/**
Expand All @@ -30,26 +34,31 @@ export class Rest {

/** Retrieves all the players that are currently running on the node. */
public async getAllPlayers(): Promise<unknown> {
this.manager.emit("debug", `[REST] Getting all players for: ${JSON.stringify(this.node)}`);
return await this.get(`/v4/sessions/${this.sessionId}/players`);
}

/** Sends a PATCH request to update player related data. */
public async updatePlayer(options: playOptions): Promise<unknown> {
this.manager.emit("debug", `[REST] Updating player: ${options.guildId}: ${JSON.stringify(options)}`);
return await this.patch(`/v4/sessions/${this.sessionId}/players/${options.guildId}?noReplace=false`, options.data);
}

/** Sends a DELETE request to the server to destroy the player. */
public async destroyPlayer(guildId: string): Promise<unknown> {
this.manager.emit("debug", `[REST] Destroying player: ${guildId}`);
return await this.delete(`/v4/sessions/${this.sessionId}/players/${guildId}`);
}

/** Updates the session status for resuming. */
public async updateSession(resuming: boolean, timeout: number): Promise<unknown> {
this.manager.emit("debug", `[REST] Updating session: ${this.sessionId}`);
return await this.patch(`/v4/sessions/${this.sessionId}`, { resuming, timeout });
}

/* Sends a GET request to the specified endpoint and returns the response data. */
private async request(method: string, endpoint: string, body?: unknown): Promise<unknown> {
this.manager.emit("debug", `[REST] ${method} api call for endpoint: ${endpoint} with data: ${JSON.stringify(body)}`);
const config: AxiosRequestConfig = {
method,
url: this.url + endpoint,
Expand Down

0 comments on commit 9f22fc7

Please sign in to comment.