Skip to content

Commit

Permalink
V2.3.1 - Debug Event and minor improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Tomato6966 committed Sep 12, 2024
1 parent 05625eb commit 56bfa0c
Show file tree
Hide file tree
Showing 15 changed files with 629 additions and 76 deletions.
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -504,3 +504,34 @@ if(previousTrack) {
- *This is technically better than skipping to a track but i wanted to point it out.*
- You can play with clientTrack like this: `player.play({ clientTrack: searchResult.tracks[0] })`
- You can play with just track like this: `player.play({ track: { encoded: "base64string..." }, requester: interaction.user })`
## **Version 2.3.1**
- Fixed Export, where types of Manager weren't exported correctly
- Fixed Dist Folder containing old, left over not needed files
## **Version 2.3.2**
- Added Missing function calls for the QueueWatcher of tracksRemoved within the queue.remove() function:
- Added new DestroyReasons:
- TrackStuckMaxTracksErroredPerTime
- TrackErrorMaxTracksErroredPerTime
- Added new Prevention Systems for CrashbackLoop recognitions:
- `this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime`:
- object: `{ threshold: number, maxAmount: number }` (set threshold to 0 or maxAmount to -1 to disable)
- Default: `{ threshold: 10_000, maxAmount: 3 }`
- If there are trackError or trackStuck Events > maxAmount within the given treshhold, the player will be destroyed prevent more errors and thus potential ratelimits.
- `this.NodeManager.LavalinkManager.options.playerOptions.minAutoPlayMs`:
- number: `10_000` (default)
- If there is an AutoplayFunction, and it get's executed before that threshold, than it won't trigger the autoplay function again. *(this is ignored for when the player is skipped)*
- This prevents autoplays from happeneing on a crashbackloop
- Set to `0` to disable
- **Added new Event "debug":**
- `LavalinkManager#debug(event:DebugEvents, data:{ state: "log" | "warn" | "error", message:string, functionLayer:string, error?:Error })`
- This function Event will emit, when the following option is set to **` true `**: `LavalinkManager.options.advancedOptions.enableDebugEvents`
- You can use the **` DebugEvents `** Enum to listen to specific events and only show those you care
- You can filter for the **` data.state `** to only show the certain log-level state
- The **` functionLayer `** string will show you where the debug event was triggered from
- The **` message `** string will show what is debugged
- The **` error `** object will show you the error that happened, if there was one.
- *This took quite some time to code, and i am sure there are still many logs you might want, feel free to open an issue or commit with an PR, if you think something is missing!*
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lavalink-client",
"version": "2.3.1",
"version": "2.3.2",
"description": "Easy, flexible and feature-rich lavalink@v4 Client. Both for Beginners and Proficients.",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
Expand Down
58 changes: 57 additions & 1 deletion src/structures/Constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,58 @@
import type { AudioOutputs, ChannelMixFilter, EQBand } from "./Types/Filters";

export enum DebugEvents {
SetSponsorBlock = "SetSponsorBlock",
DeleteSponsorBlock = "DeleteSponsorBlock",
TrackEndReplaced = "TrackEndReplaced",

AutoplayNoSongsAdded = "AutoplayNoSongsAdded",
AutoplayThresholdSpamLimiter = "AutoplayThresholdSpamLimiter",
TriggerQueueEmptyInterval = "TriggerQueueEmptyInterval",
QueueEnded = "QueueEnded",
TrackStartNewSongsOnly = "TrackStartNewSongsOnly",
TrackStartNoTrack = "TrackStartNoTrack",

ResumingFetchingError = "ResumingFetchingError",

PlayerUpdateNoPlayer = "PlayerUpdateNoPlayer",
PlayerUpdateFilterFixApply = "PlayerUpdateFilterFixApply",
PlayerUpdateSuccess = "PlayerUpdateSuccess",

HeartBeatTriggered = "HeartBeatTriggered",
NoSocketOnDestroy = "NoSocketOnDestroy",
SocketTerminateHeartBeatTimeout = "SocketTerminateHeartBeatTimeout",

TryingConnectWhileConnected = "TryingConnectWhileConnected",

LavaSearchNothingFound = "LavaSearchNothingFound",
SearchNothingFound = "SearchNothingFound",

ValidatingBlacklistLinks = "ValidatingBlacklistLinks",
ValidatingWhitelistLinks = "ValidatingWhitelistLinks",

TrackErrorMaxTracksErroredPerTime = "TrackErrorMaxTracksErroredPerTime",
TrackStuckMaxTracksErroredPerTime = "TrackStuckMaxTracksErroredPerTime",

PlayerDestroyingSomewhereElse = "PlayerDestroyingSomewhereElse",
PlayerCreateNodeNotFound = "PlayerCreateNodeNotFound",
PlayerPlayQueueEmptyTimeoutClear = "PlayerPlayQueueEmptyTimeoutClear",
PlayerPlayWithTrackReplace = "PlayerPlayWithTrackReplace",
PlayerPlayUnresolvedTrack = "PlayerPlayUnresolvedTrack",
PlayerPlayUnresolvedTrackFailed = "PlayerPlayUnresolvedTrackFailed",
PlayerVolumeAsFilter = "PlayerVolumeAsFilter",
BandcampSearchLokalEngine = "BandcampSearchLokalEngine",
PlayerChangeNode = "PlayerChangeNode",

BuildTrackError = "BuildTrackError",
TransformRequesterFunctionFailed = "TransformRequesterFunctionFailed",
GetClosestTrackFailed = "GetClosestTrackFailed",
PlayerDeleteInsteadOfDestroy = "PlayerDeleteInsteadOfDestroy",
FailedToConnectToNodes = "FailedToConnectToNodes",
NoAudioDebug = "NoAudioDebug",
PlayerAutoReconnect = "PlayerAutoReconnect"
}


export enum DestroyReasons {
QueueEmpty = "QueueEmpty",
NodeDestroy = "NodeDestroy",
Expand All @@ -10,7 +63,10 @@ export enum DestroyReasons {
PlayerReconnectFail = "PlayerReconnectFail",
ChannelDeleted = "ChannelDeleted",
DisconnectAllNodes = "DisconnectAllNodes",
ReconnectAllNodes = "ReconnectAllNodes"
ReconnectAllNodes = "ReconnectAllNodes",

TrackErrorMaxTracksErroredPerTime = "TrackErrorMaxTracksErroredPerTime",
TrackStuckMaxTracksErroredPerTime = "TrackStuckMaxTracksErroredPerTime",
};


Expand Down
87 changes: 83 additions & 4 deletions src/structures/LavalinkManager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EventEmitter } from "events";

import { DestroyReasons } from "./Constants";
import { DebugEvents, DestroyReasons } from "./Constants";
import { NodeManager } from "./NodeManager";
import { Player } from "./Player";
import { DefaultQueueStore } from "./Queue";
Expand Down Expand Up @@ -104,9 +104,15 @@ export class LavalinkManager extends EventEmitter {
volumeDecrementer: options?.playerOptions?.volumeDecrementer ?? 1,
requesterTransformer: options?.playerOptions?.requesterTransformer ?? null,
useUnresolvedData: options?.playerOptions?.useUnresolvedData ?? false,
minAutoPlayMs: options?.playerOptions?.minAutoPlayMs ?? 10_000,
maxErrorsPerTime: {
threshold: options?.playerOptions?.maxErrorsPerTime?.threshold ?? 35_000,
maxAmount: options?.playerOptions?.maxErrorsPerTime?.maxAmount ?? 3
}
},
linksWhitelist: options?.linksWhitelist ?? [],
linksBlacklist: options?.linksBlacklist ?? [],
linksAllowed: options?.linksAllowed ?? true,
autoSkip: options?.autoSkip ?? true,
autoSkipOnResolveError: options?.autoSkipOnResolveError ?? true,
emitNewSongsOnly: options?.emitNewSongsOnly ?? false,
Expand All @@ -116,6 +122,7 @@ export class LavalinkManager extends EventEmitter {
queueStore: options?.queueOptions?.queueStore ?? new DefaultQueueStore(),
},
advancedOptions: {
enableDebugEvents: options?.advancedOptions?.enableDebugEvents ?? false,
maxFilterFixDuration: options?.advancedOptions?.maxFilterFixDuration ?? 600_000,
debugOptions: {
logCustomSearches: options?.advancedOptions?.debugOptions?.logCustomSearches ?? false,
Expand Down Expand Up @@ -327,7 +334,13 @@ export class LavalinkManager extends EventEmitter {
// oldPlayer.connected is operational. you could also do oldPlayer.voice?.token
if (oldPlayer.voiceChannelId === "string" && oldPlayer.connected && !oldPlayer.get("internal_destroywithoutdisconnect")) {
if (!this.options?.advancedOptions?.debugOptions?.playerDestroy?.dontThrowError) throw new Error(`Use Player#destroy() not LavalinkManager#deletePlayer() to stop the Player ${JSON.stringify(oldPlayer.toJSON?.())}`)
else console.error("Use Player#destroy() not LavalinkManager#deletePlayer() to stop the Player", oldPlayer.toJSON?.())
else if(this.options?.advancedOptions?.enableDebugEvents) {
this.emit("debug", DebugEvents.PlayerDeleteInsteadOfDestroy, {
state: "warn",
message: "Use Player#destroy() not LavalinkManager#deletePlayer() to stop the Player",
functionLayer: "LavalinkManager > deletePlayer()",
})
}
}
return this.players.delete(guildId);
}
Expand Down Expand Up @@ -380,7 +393,13 @@ export class LavalinkManager extends EventEmitter {
}
}
if (success > 0) this.initiated = true;
else console.error("Could not connect to at least 1 Node");
else if(this.options?.advancedOptions?.enableDebugEvents) {
this.emit("debug", DebugEvents.FailedToConnectToNodes, {
state: "error",
message: "Failed to connect to at least 1 Node",
functionLayer: "LavalinkManager > init()",
})
}
return this;
}

Expand All @@ -401,11 +420,25 @@ export class LavalinkManager extends EventEmitter {
*/
public async sendRawData(data: VoicePacket | VoiceServer | VoiceState | ChannelDeletePacket): Promise<void> {
if (!this.initiated) {
if(this.options?.advancedOptions?.enableDebugEvents) {
this.emit("debug", DebugEvents.NoAudioDebug, {
state: "log",
message: "Manager is not initated yet",
functionLayer: "LavalinkManager > sendRawData()",
})
}
if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, manager is not initated yet");
return;
}

if (!("t" in data)) {
if(this.options?.advancedOptions?.enableDebugEvents) {
this.emit("debug", DebugEvents.NoAudioDebug, {
state: "error",
message: "No 't' in payload-data of the raw event:",
functionLayer: "LavalinkManager > sendRawData()",
})
}
if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no 't' in payload-data of the raw event:", data);
return;
}
Expand All @@ -422,20 +455,48 @@ export class LavalinkManager extends EventEmitter {
if (["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(data.t)) {
const update = ("d" in data ? data.d : data) as VoiceServer | VoiceState;
if (!update) {
if(this.options?.advancedOptions?.enableDebugEvents) {
this.emit("debug", DebugEvents.NoAudioDebug, {
state: "warn",
message: `No Update data found in payload :: ${JSON.stringify(data, null, 2)}`,
functionLayer: "LavalinkManager > sendRawData()",
})
}
if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no update data found in payload:", data);
return;
}
if (!("token" in update) && !("session_id" in update)) {
if(this.options?.advancedOptions?.enableDebugEvents) {
this.emit("debug", DebugEvents.NoAudioDebug, {
state: "error",
message: `No 'token' nor 'session_id' found in payload :: ${JSON.stringify(data, null, 2)}`,
functionLayer: "LavalinkManager > sendRawData()",
})
}
if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no 'token' nor 'session_id' found in payload:", data);
return;
}

const player = this.getPlayer(update.guild_id) as Player;
if (!player) {
if(this.options?.advancedOptions?.enableDebugEvents) {
this.emit("debug", DebugEvents.NoAudioDebug, {
state: "warn",
message: `No Lavalink Player found via key: 'guild_id' of update-data :: ${JSON.stringify(update, null, 2)}`,
functionLayer: "LavalinkManager > sendRawData()",
})
}
if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, No Lavalink Player found via key: 'guild_id' of update-data:", update);
return;
}
if (player.get("internal_destroystatus") === true) {
if(this.options?.advancedOptions?.enableDebugEvents) {
this.emit("debug", DebugEvents.NoAudioDebug, {
state: "warn",
message: `Player is in a destroying state. can't signal the voice states`,
functionLayer: "LavalinkManager > sendRawData()",
})
}
if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Player is in a destroying state. can't signal the voice states")
return;
}
Expand All @@ -452,12 +513,24 @@ export class LavalinkManager extends EventEmitter {
}
}
});
if(this.options?.advancedOptions?.enableDebugEvents) {
this.emit("debug", DebugEvents.NoAudioDebug, {
state: "log",
message: `Sent updatePlayer for voice token session :: ${JSON.stringify({ voice: { token: update.token, endpoint: update.endpoint, sessionId: player.voice?.sessionId, }, update }, null, 2)}`,
functionLayer: "LavalinkManager > sendRawData()",
})
}
if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Sent updatePlayer for voice token session", { voice: { token: update.token, endpoint: update.endpoint, sessionId: player.voice?.sessionId, } });
return
}

/* voice state update */
if (update.user_id !== this.options?.client.id) {
this.emit("debug", DebugEvents.NoAudioDebug, {
state: "warn",
message: `voice update user is not equal to provided client id of the LavalinkManager.options.client.id :: user: "${update.user_id}" manager client id: "${this.options?.client.id}"`,
functionLayer: "LavalinkManager > sendRawData()",
})
if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, voice update user is not equal to provided client id of the manageroptions#client#id", "user:", update.user_id, "manager client id:", this.options?.client.id);
return;
}
Expand All @@ -476,7 +549,13 @@ export class LavalinkManager extends EventEmitter {
if (this.options?.playerOptions?.onDisconnect?.autoReconnect === true) {
try {
const positionPrevios = player.position;
console.debug("Auto reconnect", positionPrevios, player.lastPosition);

this.emit("debug", DebugEvents.PlayerAutoReconnect, {
state: "log",
message: `Auto reconnecting player because LavalinkManager.options.playerOptions.onDisconnect.autoReconnect is true`,
functionLayer: "LavalinkManager > sendRawData()",
})

await player.connect();
// replay the current playing stream
await player.play({
Expand Down
Loading

0 comments on commit 56bfa0c

Please sign in to comment.