lavalink-client
Version:
Easy, flexible and feature-rich lavalink@v4 Client. Both for Beginners and Proficients.
221 lines (220 loc) • 7.68 kB
JavaScript
import { EventEmitter } from "events";
import { DestroyReasons, DisconnectReasons } from "./Constants.js";
import { LavalinkNode } from "./Node.js";
import { MiniMap } from "./Utils.js";
export class NodeManager extends EventEmitter {
/**
* Emit an event
* @param event The event to emit
* @param args The arguments to pass to the event
* @returns
*/
emit(event, ...args) {
return super.emit(event, ...args);
}
/**
* Add an event listener
* @param event The event to listen to
* @param listener The listener to add
* @returns
*/
on(event, listener) {
return super.on(event, listener);
}
/**
* Add an event listener that only fires once
* @param event The event to listen to
* @param listener The listener to add
* @returns
*/
once(event, listener) {
return super.once(event, listener);
}
/**
* Remove an event listener
* @param event The event to remove the listener from
* @param listener The listener to remove
* @returns
*/
off(event, listener) {
return super.off(event, listener);
}
/**
* Remove an event listener
* @param event The event to remove the listener from
* @param listener The listener to remove
* @returns
*/
removeListener(event, listener) {
return super.removeListener(event, listener);
}
/**
* The LavalinkManager that created this NodeManager
*/
LavalinkManager;
/**
* A map of all nodes in the nodeManager
*/
nodes = new MiniMap();
/**
* @param LavalinkManager The LavalinkManager that created this NodeManager
*/
constructor(LavalinkManager) {
super();
this.LavalinkManager = LavalinkManager;
if (this.LavalinkManager.options.nodes)
this.LavalinkManager.options.nodes.forEach(node => {
this.createNode(node);
});
}
/**
* Disconnects all Nodes from lavalink ws sockets
* @param deleteAllNodes if the nodes should also be deleted from nodeManager.nodes
* @param destroyPlayers if the players should be destroyed
* @returns amount of disconnected Nodes
*/
async disconnectAll(deleteAllNodes = false, destroyPlayers = true) {
if (!this.nodes.size)
throw new Error("There are no nodes to disconnect (no nodes in the nodemanager)");
if (!this.nodes.filter(v => v.connected).size)
throw new Error("There are no nodes to disconnect (all nodes disconnected)");
let counter = 0;
for (const node of this.nodes.values()) {
if (!node.connected)
continue;
if (destroyPlayers) {
await node.destroy(DestroyReasons.DisconnectAllNodes, deleteAllNodes);
}
else {
await node.disconnect(DisconnectReasons.DisconnectAllNodes);
}
counter++;
}
return counter;
}
/**
* Connects all not connected nodes
* @returns Amount of connected Nodes
*/
async connectAll() {
if (!this.nodes.size)
throw new Error("There are no nodes to connect (no nodes in the nodemanager)");
if (!this.nodes.filter(v => !v.connected).size)
throw new Error("There are no nodes to connect (all nodes connected)");
let counter = 0;
for (const node of this.nodes.values()) {
if (node.connected)
continue;
await node.connect();
counter++;
}
return counter;
}
/**
* Forcefully reconnects all nodes
* @returns amount of nodes
*/
async reconnectAll() {
if (!this.nodes.size)
throw new Error("There are no nodes to reconnect (no nodes in the nodemanager)");
let counter = 0;
for (const node of this.nodes.values()) {
const sessionId = node.sessionId ? `${node.sessionId}` : undefined;
await node.destroy(DestroyReasons.ReconnectAllNodes, false);
await node.connect(sessionId);
counter++;
}
return counter;
}
/**
* Create a node and add it to the nodeManager
* @param options The options for the node
* @returns The node that was created
*/
createNode(options) {
if (this.nodes.has(options.id || `${options.host}:${options.port}`))
return this.nodes.get(options.id || `${options.host}:${options.port}`);
const newNode = new LavalinkNode(options, this);
this.nodes.set(newNode.id, newNode);
return newNode;
}
/**
* Get the nodes sorted for the least usage, by a sorttype
* @param sortType The type of sorting to use
* @returns
*/
leastUsedNodes(sortType = "players") {
const connectedNodes = Array.from(this.nodes.values()).filter((node) => node.connected);
switch (sortType) {
case "memory":
{
return connectedNodes
.sort((a, b) => (a.stats?.memory?.used || 0) - (b.stats?.memory?.used || 0)); // sort after memor
}
break;
case "cpuLavalink":
{
return connectedNodes
.sort((a, b) => (a.stats?.cpu?.lavalinkLoad || 0) - (b.stats?.cpu?.lavalinkLoad || 0)); // sort after memor
}
break;
case "cpuSystem":
{
return connectedNodes
.sort((a, b) => (a.stats?.cpu?.systemLoad || 0) - (b.stats?.cpu?.systemLoad || 0)); // sort after memor
}
break;
case "calls":
{
return connectedNodes
.sort((a, b) => a.calls - b.calls); // client sided sorting
}
break;
case "playingPlayers":
{
return connectedNodes
.sort((a, b) => (a.stats?.playingPlayers || 0) - (b.stats?.playingPlayers || 0));
}
break;
case "players":
{
return connectedNodes
.sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
}
break;
default:
{
return connectedNodes
.sort((a, b) => (a.stats?.players || 0) - (b.stats?.players || 0));
}
break;
}
}
/**
* Delete a node from the nodeManager and destroy it
* @param node The node to delete
* @param movePlayers whether to movePlayers to different connected node before deletion. @default false
* @returns
*
* @example
* Deletes the node
* ```ts
* client.lavalink.nodeManager.deleteNode("nodeId to delete");
* ```
* Moves players to a different node before deleting
* ```ts
* client.lavalink.nodeManager.deleteNode("nodeId to delete", true);
* ```
*/
deleteNode(node, movePlayers = false) {
const decodeNode = typeof node === "string" ? this.nodes.get(node) : node || this.leastUsedNodes()[0];
if (!decodeNode)
throw new Error("Node was not found");
if (movePlayers)
decodeNode.destroy(DestroyReasons.NodeDeleted, true, true);
else
decodeNode.destroy(DestroyReasons.NodeDeleted);
this.nodes.delete(decodeNode.id);
return;
}
}