diff --git a/dist/src/@Datastore/database-960185850346471505.json b/dist/src/@Datastore/database-960185850346471505.json index 2c74db69..7a69e616 100644 --- a/dist/src/@Datastore/database-960185850346471505.json +++ b/dist/src/@Datastore/database-960185850346471505.json @@ -1,5 +1,5 @@ { "sessionId": { - "LAVALINK": "JbRiEOHpl2LbbIQB" + "LAVALINK": "a0BhFPXAGFqbCv4k" } } \ No newline at end of file diff --git a/dist/src/@Entities/MoonlinkNode.d.ts b/dist/src/@Entities/MoonlinkNode.d.ts index 2e301361..8b42f43f 100644 --- a/dist/src/@Entities/MoonlinkNode.d.ts +++ b/dist/src/@Entities/MoonlinkNode.d.ts @@ -1,7 +1,7 @@ /// import { INode, INodeStats } from "../@Typings"; import { MoonlinkWebSocket } from "../@Services/MoonlinkWebSocket"; -import { MoonlinkRestFul, MoonlinkDatabase } from "../../index"; +import { MoonlinkRestFul } from "../../index"; export declare class MoonlinkNode { private _manager; private reconnectTimeout?; @@ -12,32 +12,33 @@ export declare class MoonlinkNode { host: string; identifier?: string; password: string; - port: number | null; + port?: number; secure: boolean; - regions: string[] | null; + regions?: string[]; http: string; rest: MoonlinkRestFul; + info?: Record; + version?: string; resume?: boolean; resumed?: boolean; + autoResume?: boolean; resumeTimeout?: number; sessionId: string; socket: MoonlinkWebSocket | null; - version: any; state: string; - stats: INodeStats; - info: any; + stats: INodeStats | Record; calls: number; - db: MoonlinkDatabase; constructor(node: INode); get address(): string; - check(node: INode): void | never; + check(node: INode): void; request(endpoint: string, params: any): Promise; connect(): Promise; open(): void; - private movePlayersToNextNode; private reconnect; protected close(code: number, reason: any): void; - protected message(data: Buffer | string): Promise; protected error(error: Error): void; + protected message(data: Buffer | string): Promise; protected handleEvent(payload: any): Promise; + private movePlayers; + private get getAllPlayers(); } diff --git a/dist/src/@Entities/MoonlinkNode.js b/dist/src/@Entities/MoonlinkNode.js index 13a154cb..d4690410 100644 --- a/dist/src/@Entities/MoonlinkNode.js +++ b/dist/src/@Entities/MoonlinkNode.js @@ -4,7 +4,7 @@ exports.MoonlinkNode = void 0; const MoonlinkWebSocket_1 = require("../@Services/MoonlinkWebSocket"); const index_1 = require("../../index"); class MoonlinkNode { - _manager; + _manager = index_1.Structure.manager; reconnectTimeout; reconnectAttempts = 1; retryAmount = 6; @@ -18,55 +18,27 @@ class MoonlinkNode { regions; http; rest; + info = {}; + version; resume; resumed; + autoResume = index_1.Structure.manager.options?.autoResume; resumeTimeout = 30000; sessionId; socket; - version = ""; - state = index_1.State.DISCONNECTED; - stats; - info = {}; + state = "DISCONNECTED"; + stats = {}; calls = 0; - db = index_1.Structure.db; constructor(node) { - this._manager = index_1.Structure.manager; this.check(node); this.host = node.host; this.identifier = node.identifier || null; this.password = node.password ? node.password : "youshallnotpass"; - this.port = node.port - ? node.port - : node.secure - ? node.secure == true - ? 443 - : 80 - : null; + this.port = node.port ? node.port : node.secure == true ? 443 : 80; this.secure = node.secure || false; this.regions = node.regions; this.http = `http${node.secure ? "s" : ""}://${this.address}/v4/`; this.resume = this._manager.options?.resume; - this.stats = { - players: 0, - playingPlayers: 0, - uptime: 0, - memory: { - free: 0, - used: 0, - allocated: 0, - reservable: 0 - }, - cpu: { - cores: 0, - systemLoad: 0, - lavalinkLoad: 0 - }, - frameStats: { - sent: 0, - nulled: 0, - deficit: 0 - } - }; this.rest = new (index_1.Structure.get("MoonlinkRestFul"))(this); this.connect(); } @@ -75,29 +47,29 @@ class MoonlinkNode { } check(node) { if (typeof node.host !== "string" && typeof node.host !== "undefined") - throw new Error('[ @Moonlink/Node ]: "host" option is not configured correctly'); + throw new Error('@Moonlink(Nodes) - "host" option is not configured correctly'); if (typeof node.password !== "string" && typeof node.password !== "undefined") - throw new Error('[ @Moonlink/Node ]: the option "password" is not set correctly'); + throw new Error('@Moonlink(Nodes) - the option "password" is not set correctly'); if ((node.port && typeof node.port !== "number") || node.port > 65535 || node.port < 0) - throw new Error('[ @Moonlink/Node ]: the "port" option is not set correctly'); + throw new Error('@Moonlink(Nodes) - the "port" option is not set correctly'); if (typeof node.retryAmount !== "undefined" && typeof node.retryAmount !== "number") - throw new Error('[ @Moonlink/Node ]: the "retryAmount" option is not set correctly'); + throw new Error('@Moonlink(Nodes) - the "retryAmount" option is not set correctly'); if (typeof node.retryDelay !== "undefined" && typeof node.retryDelay !== "number") - throw new Error('[ @Moonlink/Node ]: the "retryDelay" option is not set correctly'); + throw new Error('@Moonlink(Nodes) - the "retryDelay" option is not set correctly'); } request(endpoint, params) { this.calls++; return this.rest.get(`${endpoint}?${params}`); } async connect() { - if (this.state == index_1.State.CONNECTED || this.state == index_1.State.READY) + if (this.state == "CONNECTED" || this.state == "READY") return; - this.state = index_1.State.CONNECTING; + this.state = "CONNECTING"; let headers = { Authorization: this.password, "User-Id": this._manager.options.clientId, @@ -105,8 +77,7 @@ class MoonlinkNode { }; if (this.resume) headers["Session-Id"] = - this.db.get(`sessionId.${this.identifier ?? this.host.replace(/\./g, "-")}`) ?? - null; + index_1.Structure.db.get(`sessionId.${this.identifier ?? this.host.replace(/\./g, "-")}`) ?? null; this.socket = new MoonlinkWebSocket_1.MoonlinkWebSocket(`ws${this.secure ? "s" : ""}://${this.address}/v4/websocket`, { headers }); this.socket.on("open", this.open.bind(this)); this.socket.on("close", this.close.bind(this)); @@ -116,52 +87,28 @@ class MoonlinkNode { open() { if (this.reconnectTimeout) clearTimeout(this.reconnectTimeout); - this._manager.emit("debug", `@Moonlink(Node) - The Node ${this.identifier ? this.identifier : this.host} has been connected successfully`); + this._manager.emit("debug", `@Moonlink(Node) - The Node ${this.identifier ?? this.host} has been connected successfully`); this._manager.emit("nodeCreate", this); - this.state = index_1.State.CONNECTED; - } - async movePlayersToNextNode() { - if (!this._manager.options.movePlayersToNextNode) - return; - const state = this.state; - this.state = index_1.State.MOVING; - try { - let obj = this._manager.players.all || []; - const players = Object.keys(obj); - for (const player of players) { - if (obj[player].node == this) { - let nextNode = this._manager.nodes.sortByUsage("players")[0]; - let playerClass = this._manager.players.get(obj[player].guildId); - this._manager.emit("debug", `@Moonlink(Node) - Moving player ${obj[player].guildId} to ${nextNode.identifier - ? nextNode.identifier - : nextNode.host}`); - playerClass.node = nextNode; - await playerClass.restart(); - } - } - this.state = state; - } - catch (err) { - throw new Error("@Moonlink(Node) - not to other connected lavalinks " + err); - } + this.state = "CONNECTED"; } reconnect() { if (this.reconnectAttempts >= this.retryAmount) { - this._manager.emit("debug", `@Moonlink(Node) - Node ${this.identifier ? this.identifier : this.host} was destroyed due to inactivity, attempts to reconnect were failed`); + this._manager.emit("debug", `@Moonlink(Node) - Node ${this.identifier ?? this.host} was destroyed due to inactivity, attempts to reconnect were failed`); this._manager.emit("nodeDestroy", this); this.socket.close(1000, "destroy"); this.socket.removeAllListeners(); - this.movePlayersToNextNode(); } else { this.reconnectTimeout = setTimeout(() => { this.socket.removeAllListeners(); this.socket = null; - this.state = index_1.State.RECONNECTING; + this.state = "RECONNECTING"; this._manager.emit("nodeReconnect", this); this.connect(); - this._manager.emit("debug", `@Moonlink(Node) - we are trying to reconnect node ${this.identifier ?? this.host}, attempted number ${this.reconnectAttempts} + this._manager.emit("debug", `@Moonlink(Node) - We are trying to reconnect node ${this.identifier ?? this.host}, attempted number ${this.reconnectAttempts} `); + if (this.getAllPlayers.length) + this.movePlayers(); this.reconnectAttempts++; }, this.retryDelay); } @@ -169,22 +116,19 @@ class MoonlinkNode { close(code, reason) { if (code !== 1000 || reason !== "destroy") this.reconnect(); - this._manager.emit("debug", `@Moonlink(Node) - The node connection ${this.identifier ? this.identifier : this.host} has been closed`); + this._manager.emit("debug", `@Moonlink(Node) - The node connection ${this.identifier ?? this.host} has been closed`); this._manager.emit("nodeClose", this, code, reason); - if (this.state !== index_1.State.DISCONNECTED || - this.state !== index_1.State.RECONNECTING) { - let obj = this._manager.players.all || []; - if (obj.length !== 0) { - const players = Object.keys(obj); - for (const player of players) { - if (obj[player].node == this) { - this._manager.players.get(obj[player].guildId).playing = - false; - } - } - } - } - this.state = index_1.State.DISCONNECTED; + this.getAllPlayers.forEach(player => { + player.playing = false; + }); + this.state = "DISCONNECTED"; + } + error(error) { + if (!error) + return; + this._manager.emit("nodeError", this, error); + this._manager.emit("debug", `@Moonlink(Nodes) - The ${this.identifier ?? this.host} an error has occurred: + ${error}`); } async message(data) { if (Array.isArray(data)) @@ -199,16 +143,15 @@ class MoonlinkNode { case "ready": this.sessionId = payload.sessionId; this.resume - ? this.db.set(`sessionId.${this.identifier ?? this.host.replace(/\./g, "-")}`, this.sessionId) + ? index_1.Structure.db.set(`sessionId.${this.identifier ?? this.host.replace(/\./g, "-")}`, this.sessionId) : null; this.resumed = payload.resumed; - this._manager.nodes.map.set("sessionId", payload.sessionId); this.rest.setSessionId(this.sessionId); if (!this._manager.initiated && !this.resumed) { - this.db.delete("queue"); - this.db.delete("players"); + index_1.Structure.db.delete("queue"); + index_1.Structure.db.delete("players"); } - this._manager.emit("debug", `@Moonlink(Node) - ${this.resumed ? ` session was resumed, ` : ``} session is currently ${this.sessionId}`); + this._manager.emit("debug", `@Moonlink(Node) - ${this.resumed ? ` session was resumed,` : ``} session is currently ${this.sessionId}`); if (this.resume) { this.rest.patch(`sessions/${this.sessionId}`, { data: { @@ -216,45 +159,33 @@ class MoonlinkNode { timeout: this.resumeTimeout } }); - this._manager.emit("debug", `[ @Moonlink/Node ]: Resuming configured on Lavalink`); + this._manager.emit("debug", `@Moonlink(Nodes) - Resuming configured`); } this.version = await this.rest.getVersion(); this.info = await this.rest.getInfo(); - if (this._manager.options.autoResume) { - this.state = index_1.State.AUTORESUMING; - let obj = this._manager.players.all || []; - const players = Object.keys(obj); - for (const player of players) { - if (obj[player].node == this) { - await this._manager.players.attemptConnection(obj[player].guildId); - this._manager.players - .get(obj[player].guildId) - .restart(); - } + if (this.autoResume) { + let resumePlayers = this.getAllPlayers; + for (const resumePlayer of resumePlayers) { + resumePlayer.restart(); } } if (this.resumed) { - this.state = index_1.State.RESUMING; - let players = await this.rest.get(`sessions/${this.sessionId}/players`); - for (const player of players) { - let previousInfosPlayer = this.db.get(`players.${player.guildId}`) || {}; - let playerClass = this._manager.players.create({ - guildId: player.guildId, + const resumedPlayers = await this.rest.get(`sessions/${this.sessionId}/players`); + for (const resumedPlayer of resumedPlayers) { + const previousInfosPlayer = index_1.Structure.db.get(`players.${resumedPlayer.guildId}`) || {}; + const player = this._manager.players.create({ + guildId: resumedPlayer.guildId, voiceChannel: previousInfosPlayer.voiceChannel, textChannel: previousInfosPlayer.textChannel, - node: this.host - }); - playerClass.connect({ - setDeaf: true, - setMute: false + node: this.identifier ?? this.host }); - playerClass.playing = true; - playerClass.connected = true; - let track = new (index_1.Structure.get("MoonlinkTrack"))(player.track); - playerClass.current = track; + player.playing = true; + player.connected = true; + const track = new (index_1.Structure.get("MoonlinkTrack"))(resumedPlayer.track); + player.current = track; } } - this.state = index_1.State.READY; + this.state = "READY"; break; case "stats": delete payload.op; @@ -263,90 +194,62 @@ class MoonlinkNode { case "playerUpdate": let player = this._manager.players.get(payload.guildId); player.ping = payload.state.ping; - if (player.current instanceof index_1.MoonlinkTrack) { - player.current - .setPosition(payload.state.position) - .setTime(payload.state.time); - } - else if (player.current) { - player.current.position = payload.state.position; - player.current.time = payload.state.time; - } + player.current.position = payload.state.position; + player.current.time = payload.state.time; break; case "event": this.handleEvent(payload); break; default: - this._manager.emit("nodeError", this, new Error(`[ @Moonlink/Nodes ]: Unexpected op "${payload.op}" with data: ${payload}`)); + this._manager.emit("nodeError", this, new Error(`@Moonlink(Nodes) - Unexpected op "${payload.op}" with data: ${payload}`)); } } - error(error) { - if (!error) - return; - this._manager.emit("nodeError", this, error); - this._manager.emit("debug", "[ @Moonlink/Nodes ]: An error occurred in one of the lavalink(s) server connection(s): " + - error); - } async handleEvent(payload) { if (!payload) return; if (!payload.guildId) return; - if (!this._manager.players.has(payload.guildId)) - return; let player = this._manager.players.get(payload.guildId); + if (!player) + return; switch (payload.type) { case "TrackStartEvent": { - let current = player.current; - if (!current) - return; + if (!player.current) { + player.current = new index_1.MoonlinkTrack((await this.rest.decodeTrack(payload.track))); + } player.playing = true; player.paused = false; - this._manager.emit("trackStart", player, current); + this._manager.emit("trackStart", player, player.current); break; } case "TrackEndEvent": { - let track = player.current; - let queue = player.queue.all; - player.playing = false; if (this._manager.options.previousTracksInArray) - player.previous.push(track); + player.previous.push(player.current); else - player.previous = track; - if (["loadFailed", "cleanup"].includes(payload.reason)) { - if (!queue) { - player.queue.clear(); - return this._manager.emit("queueEnd", player, track); - } - player.play(); - return; - } + player.previous = player.current; + player.playing = false; if (payload.reason === "replaced") { - this._manager.emit("trackEnd", player, track, payload); + this._manager.emit("trackEnd", player, player.current, payload); return; } - if (track && player.loop) { + if (player.current && [1, 2].includes(player.loop)) { if (player.loop == 1) { await this.rest.update({ guildId: payload.guildId, - data: { track: { encoded: track.encoded } } + data: { track: { encoded: player.current.encoded } } }); return; } if (player.loop == 2) { player.queue.add(player.current); - if (!queue || queue.length === 0) - return this._manager.emit("trackEnd", player, track, payload); + if (!player.queue.all || !player.queue.size) + return this._manager.emit("trackEnd", player, player.current, payload); player.play(); return; } - else { - this._manager.emit("trackEnd", player, track); - this._manager.emit("debug", "@Manager(Nodes) - invalid loop value will be ignored!"); - } } if (player.queue.size) { - this._manager.emit("trackEnd", player, track); + this._manager.emit("trackEnd", player, player.current, payload); player.play(); return; } @@ -354,8 +257,7 @@ class MoonlinkNode { player.autoPlay === true) { if (payload.reason == "stopped") return; - let uri = `https://www.youtube.com/watch?v=${track.identifier}&list=RD${track.identifier}`; - let req = await this._manager.search(uri); + let req = await this._manager.search(`https://www.youtube.com/watch?v=${player.current.identifier}&list=RD${player.current.identifier}`); if (!req || !req.tracks || ["loadFailed", "cleanup"].includes(req.loadType)) @@ -367,13 +269,12 @@ class MoonlinkNode { } if (player.autoLeave) { player.destroy(); - this._manager.emit("autoLeaved", player, track); + this._manager.emit("autoLeaved", player, player.current); } if (!player.queue.size) { - this._manager.emit("debug", "[ @Moonlink/Nodes ]: The queue is empty"); + this._manager.emit("debug", "@Moonlink(Nodes) - The queue is empty"); this._manager.emit("queueEnd", player); player.current = null; - player.queue.clear(); } break; } @@ -392,10 +293,22 @@ class MoonlinkNode { break; } default: { - const error = new Error(`[ @Moonlink/Nodes ] unknown event '${payload.type}'.`); + const error = new Error(`@Moonlink(Nodes) - unknown event '${payload.type}'.`); this._manager.emit("nodeError", this, error); } } } + movePlayers() { + this.getAllPlayers.forEach(player => { + let anotherNode = this._manager.nodes.sortByUsage(this._manager.options?.sortNode ?? "players")[0]; + this._manager.emit("debug", `@Moonlink(Node) - Moving player ${player.guildId} to ${anotherNode.identifier ?? anotherNode.host}`); + player.node = anotherNode; + player.restart(); + }); + return true; + } + get getAllPlayers() { + return Object.values(this._manager.players.all).filter(player => player.node === this); + } } exports.MoonlinkNode = MoonlinkNode; diff --git a/src/@Entities/MoonlinkNode.ts b/src/@Entities/MoonlinkNode.ts index f4530345..545e2432 100644 --- a/src/@Entities/MoonlinkNode.ts +++ b/src/@Entities/MoonlinkNode.ts @@ -4,19 +4,20 @@ import { SearchResult, PreviousInfosPlayer } from "../@Typings"; + import { MoonlinkWebSocket } from "../@Services/MoonlinkWebSocket"; + import { MoonlinkManager, MoonlinkTrack, MoonlinkPlayer, MoonlinkRestFul, MoonlinkDatabase, - Structure, - State + Structure } from "../../index"; export class MoonlinkNode { - private _manager: MoonlinkManager; + private _manager: MoonlinkManager = Structure.manager; private reconnectTimeout?: NodeJS.Timeout; private reconnectAttempts: number = 1; private retryAmount: number = 6; @@ -26,22 +27,22 @@ export class MoonlinkNode { public host: string; public identifier?: string; public password: string; - public port: number | null; + public port?: number; public secure: boolean; - public regions: string[] | null; + public regions?: string[]; public http: string; public rest: MoonlinkRestFul; - public resume?: boolean; + public info?: Record = {}; + public version?: string; + public resume?: boolean = Structure.manager.options?.resume; public resumed?: boolean; + public autoResume?: boolean = Structure.manager.options?.autoResume; public resumeTimeout?: number = 30000; public sessionId: string; public socket: MoonlinkWebSocket | null; - public version: any = ""; - public state: string = State.DISCONNECTED; - public stats: INodeStats; - public info: any = {}; + public state: string = "DISCONNECTED"; + public stats: INodeStats | Record = {}; public calls: number = 0; - public db: MoonlinkDatabase = Structure.db; /** * Initializes a new MoonlinkNode instance with the provided configuration. @@ -49,37 +50,14 @@ export class MoonlinkNode { */ constructor(node: INode) { - this._manager = Structure.manager; this.check(node); this.host = node.host; this.identifier = node.identifier || null; this.password = node.password ? node.password : "youshallnotpass"; - this.port = node.port ?? node.secure == true ? 443 : 80; + this.port = node.port ? node.port : node.secure == true ? 443 : 80; this.secure = node.secure || false; this.regions = node.regions; this.http = `http${node.secure ? "s" : ""}://${this.address}/v4/`; - this.resume = this._manager.options?.resume; - this.stats = { - players: 0, - playingPlayers: 0, - uptime: 0, - memory: { - free: 0, - used: 0, - allocated: 0, - reservable: 0 - }, - cpu: { - cores: 0, - systemLoad: 0, - lavalinkLoad: 0 - }, - frameStats: { - sent: 0, - nulled: 0, - deficit: 0 - } - }; this.rest = new (Structure.get("MoonlinkRestFul"))(this); this.connect(); @@ -99,7 +77,7 @@ export class MoonlinkNode { * @param node - The configuration object for the Lavalink node. */ - public check(node: INode): void | never { + public check(node: INode): void { if (typeof node.host !== "string" && typeof node.host !== "undefined") throw new Error( '@Moonlink(Nodes) - "host" option is not configured correctly' @@ -154,8 +132,8 @@ export class MoonlinkNode { */ public async connect(): Promise { - if (this.state == State.CONNECTED || this.state == State.READY) return; - this.state = State.CONNECTING; + if (this.state == "CONNECTED" || this.state == "READY") return; + this.state = "CONNECTING"; let headers = { Authorization: this.password, @@ -164,7 +142,7 @@ export class MoonlinkNode { }; if (this.resume) headers["Session-Id"] = - this.db.get( + Structure.db.get( `sessionId.${ this.identifier ?? this.host.replace(/\./g, "-") }` @@ -188,8 +166,7 @@ export class MoonlinkNode { } has been connected successfully` ); this._manager.emit("nodeCreate", this); - - this.state = State.CONNECTED; + this.state = "CONNECTED"; } private reconnect(): void { @@ -207,7 +184,7 @@ export class MoonlinkNode { this.reconnectTimeout = setTimeout(() => { this.socket.removeAllListeners(); this.socket = null; - this.state = State.RECONNECTING; + this.state = "RECONNECTING"; this._manager.emit("nodeReconnect", this); this.connect(); this._manager.emit( @@ -217,10 +194,12 @@ export class MoonlinkNode { }, attempted number ${this.reconnectAttempts} ` ); + if (this.getAllPlayers.length) this.movePlayers(); this.reconnectAttempts++; }, this.retryDelay); } } + protected close(code: number, reason: any): void { if (code !== 1000 || reason !== "destroy") this.reconnect(); this._manager.emit( @@ -230,8 +209,26 @@ export class MoonlinkNode { } has been closed` ); this._manager.emit("nodeClose", this, code, reason); - this.state = State.DISCONNECTED; + + this.getAllPlayers.forEach(player => { + player.playing = false; + }); + + this.state = "DISCONNECTED"; } + + protected error(error: Error): void { + if (!error) return; + this._manager.emit("nodeError", this, error); + this._manager.emit( + "debug", + `@Moonlink(Nodes) - The ${ + this.identifier ?? this.host + } an error has occurred: + ${error}` + ); + } + protected async message(data: Buffer | string): Promise { if (Array.isArray(data)) data = Buffer.concat(data); else if (data instanceof ArrayBuffer) data = Buffer.from(data); @@ -244,7 +241,7 @@ export class MoonlinkNode { case "ready": this.sessionId = payload.sessionId; this.resume - ? this.db.set( + ? Structure.db.set( `sessionId.${ this.identifier ?? this.host.replace(/\./g, "-") }`, @@ -254,13 +251,13 @@ export class MoonlinkNode { this.resumed = payload.resumed; this.rest.setSessionId(this.sessionId); if (!this._manager.initiated && !this.resumed) { - this.db.delete("queue"); - this.db.delete("players"); + Structure.db.delete("queue"); + Structure.db.delete("players"); } this._manager.emit( "debug", `@Moonlink(Node) - ${ - this.resumed ? ` session was resumed, ` : `` + this.resumed ? ` session was resumed,` : `` } session is currently ${this.sessionId}` ); if (this.resume) { @@ -278,7 +275,37 @@ export class MoonlinkNode { this.version = await this.rest.getVersion(); this.info = await this.rest.getInfo(); - this.state = State.READY; + if (this.autoResume) { + let resumePlayers = this.getAllPlayers; + for (const resumePlayer of resumePlayers) { + resumePlayer.restart(); + } + } + if (this.resumed) { + const resumedPlayers: any[] = await this.rest.get( + `sessions/${this.sessionId}/players` + ); + + for (const resumedPlayer of resumedPlayers) { + const previousInfosPlayer: PreviousInfosPlayer = + Structure.db.get( + `players.${resumedPlayer.guildId}` + ) || {}; + const player = this._manager.players.create({ + guildId: resumedPlayer.guildId, + voiceChannel: previousInfosPlayer.voiceChannel, + textChannel: previousInfosPlayer.textChannel, + node: this.identifier ?? this.host + }); + player.playing = true; + player.connected = true; + const track = new (Structure.get("MoonlinkTrack"))( + resumedPlayer.track + ); + player.current = track; + } + } + this.state = "READY"; break; case "stats": delete payload.op; @@ -304,15 +331,7 @@ export class MoonlinkNode { ); } } - protected error(error: Error): void { - if (!error) return; - this._manager.emit("nodeError", this, error); - this._manager.emit( - "debug", - "@Moonlink(Nodes) - An error occurred in one of the lavalink(s) server connection(s): " + - error - ); - } + protected async handleEvent(payload: any): Promise { if (!payload) return; if (!payload.guildId) return; @@ -321,10 +340,10 @@ export class MoonlinkNode { switch (payload.type) { case "TrackStartEvent": { - if (player.current) { + if (!player.current) { player.current = new MoonlinkTrack( - await this.rest.decodeTrack(payload.track) - ); + (await this.rest.decodeTrack(payload.track)) as any + ) as MoonlinkTrack; } player.playing = true; player.paused = false; @@ -334,7 +353,7 @@ export class MoonlinkNode { case "TrackEndEvent": { if (this._manager.options.previousTracksInArray) (player.previous as MoonlinkTrack[]).push( - track as MoonlinkTrack + player.current as MoonlinkTrack ); else player.previous = player.current; player.playing = false; @@ -386,7 +405,7 @@ export class MoonlinkNode { ) { if (payload.reason == "stopped") return; let req: SearchResult = await this._manager.search( - `https://www.youtube.com/watch?v=${player.curren.identifier}&list=RD${player.current.identifier}` + `https://www.youtube.com/watch?v=${player.current.identifier}&list=RD${player.current.identifier}` ); if ( !req || @@ -443,4 +462,27 @@ export class MoonlinkNode { } } } + + private movePlayers(): boolean { + this.getAllPlayers.forEach(player => { + let anotherNode = this._manager.nodes.sortByUsage( + this._manager.options?.sortNode ?? "players" + )[0]; + this._manager.emit( + "debug", + `@Moonlink(Node) - Moving player ${player.guildId} to ${ + anotherNode.identifier ?? anotherNode.host + }` + ); + player.node = anotherNode; + player.restart(); + }); + return true; + } + + private get getAllPlayers(): MoonlinkPlayer[] { + return Object.values(this._manager.players.all).filter( + player => player.node === this + ); + } }