diff --git a/package.json b/package.json index 7cb2bd8..f30fa46 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "main": "dist/index.js", "module": "dist/index.mjs", "description": "Kirishima is extendable, fast, flexible, asynchronous lavalink client", - "version": "0.5.0", + "version": "0.6.0", "license": "GPL-3.0", "repository": { "url": "https://github.com/kirishima-ship/core" diff --git a/src/Base/BaseKirishima.ts b/src/Base/BaseKirishima.ts new file mode 100644 index 0000000..0bd7f93 --- /dev/null +++ b/src/Base/BaseKirishima.ts @@ -0,0 +1,71 @@ +/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ +import Collection from '@discordjs/collection'; +import EventEmitter from 'node:events'; +import { KirishimaPlayer, KirishimaPlayerOptions } from '..'; +import { KirishimaNode } from '../Structures/KirishimaNode'; +import { Structure } from '../Structures/Structure'; +import { KirishimaOptions, LoadTrackResponse } from '../typings'; + +export class BaseKirishima extends EventEmitter { + public nodes: Collection = new Collection(); + public players?: Collection; + public constructor(public options: KirishimaOptions) { + super(); + + if (typeof options.send !== 'function') throw Error('Send function must be present and must be a function.'); + + if ( + typeof options.spawnPlayer !== 'function' || + (typeof options.spawnPlayer === undefined && (typeof options.fetchPlayer !== 'function' || typeof options.fetchPlayer === undefined)) + ) { + this.players = new Collection(); + options.spawnPlayer = this.defaultSpawnPlayerHandler.bind(this); + } + + if ( + typeof options.fetchPlayer !== 'function' || + (typeof options.fetchPlayer === undefined && (typeof options.spawnPlayer !== 'function' || typeof options.spawnPlayer === undefined)) + ) { + options.fetchPlayer = this.defaultFetchPlayerHandler.bind(this); + } + + if (!options.nodes.length) throw new Error('Nodes option must not a empty array'); + } + + public resolveNode(identifierOrGroup?: string) { + const resolveIdenfitierNode = this.nodes.filter((x) => x.connected).find((x) => x.options.identifier === identifierOrGroup); + if (resolveIdenfitierNode) return resolveIdenfitierNode; + const resolveGroupedNode = this.nodes.filter((x) => x.connected).find((x) => x.options.group?.includes(identifierOrGroup!)!); + if (resolveGroupedNode) return resolveGroupedNode; + return this.resolveBestNode().first(); + } + + public resolveBestNode() { + return this.nodes + .filter((x) => x.connected) + .sort((x, y) => { + const XLoad = x.stats?.cpu ? (x.stats.cpu.systemLoad / x.stats.cpu.cores) * 100 : 0; + const YLoad = y.stats?.cpu ? (y.stats.cpu.systemLoad / y.stats.cpu.cores) * 100 : 0; + return XLoad - YLoad; + }); + } + + public async resolveTracks(options: string | { source?: string | undefined; query: string }, node?: KirishimaNode): Promise { + node ??= this.resolveNode(); + const resolveTracks = await node!.rest.loadTracks(options); + if (resolveTracks?.tracks.length) resolveTracks.tracks = resolveTracks.tracks.map((x) => new (Structure.get('KirishimaTrack'))(x)); + return resolveTracks as unknown as LoadTrackResponse; + } + + private defaultSpawnPlayerHandler(guildId: string, options: KirishimaPlayerOptions, node: KirishimaNode) { + const player = this.players!.has(guildId); + if (player) return this.players!.get(guildId)!; + const kirishimaPlayer = new (Structure.get('KirishimaPlayer'))(options, this, node); + this.players!.set(guildId, kirishimaPlayer); + return kirishimaPlayer; + } + + private defaultFetchPlayerHandler(guildId: string) { + return this.players!.get(guildId); + } +} diff --git a/src/Structures/BasePlayer.ts b/src/Base/BasePlayer.ts similarity index 84% rename from src/Structures/BasePlayer.ts rename to src/Base/BasePlayer.ts index 6ea03c0..0a4623e 100644 --- a/src/Structures/BasePlayer.ts +++ b/src/Base/BasePlayer.ts @@ -1,12 +1,13 @@ import { GatewayVoiceServerUpdateDispatch, GatewayVoiceStateUpdateDispatch } from 'discord-api-types/gateway/v9'; import { WebsocketOpEnum } from 'lavalink-api-types'; -import { KirishimaPlayerOptions, Kirishima, KirishimaNode, createVoiceChannelJoinPayload } from '..'; +import { KirishimaPlayerOptions, KirishimaNode, createVoiceChannelJoinPayload } from '..'; +import { BaseKirishima } from './BaseKirishima'; export class BasePlayer { public voiceServer: GatewayVoiceServerUpdateDispatch['d'] | undefined; public voiceState: GatewayVoiceStateUpdateDispatch['d'] | undefined; - public constructor(public options: KirishimaPlayerOptions, public kirishima: Kirishima, public node: KirishimaNode) {} + public constructor(public options: KirishimaPlayerOptions, public kirishima: BaseKirishima, public node: KirishimaNode) {} public async connect() { await this.kirishima.options.send(this.options, createVoiceChannelJoinPayload(this.options)); diff --git a/src/Structures/Kirishima.ts b/src/Structures/Kirishima.ts index 71ff322..4a5ba50 100644 --- a/src/Structures/Kirishima.ts +++ b/src/Structures/Kirishima.ts @@ -1,40 +1,11 @@ -/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ -import { EventEmitter } from 'node:events'; -import type { KirishimaNodeOptions, KirishimaOptions, KirishimaPlayerOptions, LoadTrackResponse } from '../typings'; +import type { KirishimaNodeOptions, KirishimaPlayerOptions } from '../typings'; import crypto from 'node:crypto'; import { KirishimaNode } from './KirishimaNode'; import { GatewayVoiceServerUpdateDispatch, GatewayVoiceStateUpdateDispatch } from 'discord-api-types/gateway/v9'; -import Collection from '@discordjs/collection'; -import { KirishimaPlayer } from './KirishimaPlayer'; import { Structure } from './Structure'; -export class Kirishima extends EventEmitter { - public nodes: Collection = new Collection(); - public players?: Collection; - public constructor(public options: KirishimaOptions) { - super(); - - if (typeof options.send !== 'function') throw Error('Send function must be present and must be a function.'); - - if ( - typeof options.spawnPlayer !== 'function' || - (typeof options.spawnPlayer === undefined && (typeof options.fetchPlayer !== 'function' || typeof options.fetchPlayer === undefined)) - ) { - this.players = new Collection(); - options.spawnPlayer = this.defaultSpawnPlayerHandler.bind(this); - } - - if ( - typeof options.fetchPlayer !== 'function' || - (typeof options.fetchPlayer === undefined && (typeof options.spawnPlayer !== 'function' || typeof options.spawnPlayer === undefined)) - ) { - options.fetchPlayer = this.defaultFetchPlayerHandler.bind(this); - } - - if (!options.nodes.length) throw new Error('Nodes option must not a empty array'); - } - +export class Kirishima extends Structure.get('BaseKirishima') { public async initialize(clientId?: string) { if (!clientId && !this.options.clientId) throw new Error('Invalid clientId provided'); if (clientId && !this.options.clientId) this.options.clientId = clientId; @@ -72,31 +43,6 @@ export class Kirishima extends EventEmitter { return this; } - public resolveNode(identifierOrGroup?: string) { - const resolveGroupedNode = this.nodes.filter((x) => x.connected).find((x) => x.options.group?.includes(identifierOrGroup!)!); - if (resolveGroupedNode) return resolveGroupedNode; - const resolveIdenfitierNode = this.nodes.filter((x) => x.connected).find((x) => x.options.identifier === identifierOrGroup); - if (resolveIdenfitierNode) return resolveIdenfitierNode; - return this.resolveBestNode().first(); - } - - public resolveBestNode() { - return this.nodes - .filter((x) => x.connected) - .sort((x, y) => { - const XLoad = x.stats?.cpu ? (x.stats.cpu.systemLoad / x.stats.cpu.cores) * 100 : 0; - const YLoad = y.stats?.cpu ? (y.stats.cpu.systemLoad / y.stats.cpu.cores) * 100 : 0; - return XLoad - YLoad; - }); - } - - public async resolveTracks(options: string | { source?: string | undefined; query: string }, node?: KirishimaNode): Promise { - node ??= this.resolveNode(); - const resolveTracks = await node!.rest.loadTracks(options); - if (resolveTracks?.tracks.length) resolveTracks.tracks = resolveTracks.tracks.map((x) => new (Structure.get('KirishimaTrack'))(x)); - return resolveTracks as unknown as LoadTrackResponse; - } - public spawnPlayer(options: KirishimaPlayerOptions, node?: KirishimaNode) { return this.options.spawnPlayer!(options.guildId, options, node ?? this.resolveNode()!); } @@ -121,16 +67,4 @@ export class Kirishima extends EventEmitter { await this.handleVoiceServerUpdate(packet as GatewayVoiceServerUpdateDispatch); } } - - private defaultSpawnPlayerHandler(guildId: string, options: KirishimaPlayerOptions, node: KirishimaNode) { - const player = this.players!.has(guildId); - if (player) return this.players!.get(guildId)!; - const kirishimaPlayer = new (Structure.get('KirishimaPlayer'))(options, this, node); - this.players!.set(guildId, kirishimaPlayer); - return kirishimaPlayer; - } - - private defaultFetchPlayerHandler(guildId: string) { - return this.players!.get(guildId); - } } diff --git a/src/Structures/KirishimaNode.ts b/src/Structures/KirishimaNode.ts index dd76947..c6c41f9 100644 --- a/src/Structures/KirishimaNode.ts +++ b/src/Structures/KirishimaNode.ts @@ -5,7 +5,7 @@ import type { KirishimaNodeOptions } from '../typings'; import type { Kirishima } from './Kirishima'; import { GatewayVoiceServerUpdateDispatch, GatewayVoiceStateUpdateDispatch } from 'discord-api-types/gateway/v9'; import { LavalinkStatsPayload, WebsocketOpEnum } from 'lavalink-api-types'; -import { BasePlayer } from './BasePlayer'; +import { BasePlayer } from '../Base/BasePlayer'; export class KirishimaNode { public ws!: Gateway; diff --git a/src/Structures/KirishimaPlayer.ts b/src/Structures/KirishimaPlayer.ts index 118dc88..d891dab 100644 --- a/src/Structures/KirishimaPlayer.ts +++ b/src/Structures/KirishimaPlayer.ts @@ -1,4 +1,3 @@ -import { Kirishima } from './Kirishima'; import type { KirishimaPlayerOptions } from '../typings/index'; import { isTrack, KirishimaNode } from '../index'; @@ -17,13 +16,14 @@ import { import { KirishimaTrack } from './Track/KirishimaTrack'; import { KirishimaFilter, KirishimaFilterOptions } from './KirishimaFilter'; import { Structure } from './Structure'; +import { BaseKirishima } from '../Base/BaseKirishima'; export class KirishimaPlayer extends Structure.get('BasePlayer') { public filters = new (Structure.get('KirishimaFilter'))(); public paused = false; public playing = false; - public constructor(public options: KirishimaPlayerOptions, public kirishima: Kirishima, public node: KirishimaNode) { + public constructor(public options: KirishimaPlayerOptions, public kirishima: BaseKirishima, public node: KirishimaNode) { super(options, kirishima, node); } diff --git a/src/Structures/Structure.ts b/src/Structures/Structure.ts index 87eb414..558dac4 100644 --- a/src/Structures/Structure.ts +++ b/src/Structures/Structure.ts @@ -1,12 +1,13 @@ /* eslint-disable @typescript-eslint/no-extraneous-class */ import type { Extendable } from '../typings'; -import { BasePlayer } from './BasePlayer'; +import { BasePlayer } from '../Base/BasePlayer'; import { KirishimaFilter } from './KirishimaFilter'; import { KirishimaNode } from './KirishimaNode'; import { KirishimaPlayer } from './KirishimaPlayer'; import { KirishimaPartialTrack } from './Track/KirishimaPartialTrack'; import { KirishimaTrack } from './Track/KirishimaTrack'; +import { BaseKirishima } from '../Base/BaseKirishima'; const structures = { KirishimaNode, @@ -14,7 +15,8 @@ const structures = { KirishimaPartialTrack, KirishimaTrack, KirishimaFilter, - BasePlayer + BasePlayer, + BaseKirishima }; export abstract class Structure { diff --git a/src/index.ts b/src/index.ts index a368a21..392b4fe 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,6 @@ export * from './Structures/Track/KirishimaPartialTrack'; export * from './Structures/Track/KirishimaTrack'; export * from './Structures/KirishimaFilter'; export * from './Structures/KirishimaPlugin'; -export * from './Structures/BasePlayer'; +export * from './Base/BasePlayer'; export * from './typings/index'; export * from './Util'; diff --git a/src/typings/index.ts b/src/typings/index.ts index 2e1d61d..c9d21ea 100644 --- a/src/typings/index.ts +++ b/src/typings/index.ts @@ -6,8 +6,9 @@ import type { KirishimaTrack } from '../Structures/Track/KirishimaTrack'; import type { KirishimaPartialTrack } from '../Structures/Track/KirishimaPartialTrack'; import { KirishimaFilter } from '../Structures/KirishimaFilter'; import { KirishimaPlugin } from '../Structures/KirishimaPlugin'; -import { BasePlayer } from '../Structures/BasePlayer'; +import { BasePlayer } from '../Base/BasePlayer'; import { LoadTrackResponse as OLoadTrackResponse } from 'lavalink-api-types'; +import { BaseKirishima } from '../Base/BaseKirishima'; export interface KirishimaOptions { clientId?: string; @@ -69,6 +70,7 @@ export interface Extendable { KirishimaPartialTrack: typeof KirishimaPartialTrack; KirishimaFilter: typeof KirishimaFilter; BasePlayer: typeof BasePlayer; + BaseKirishima: typeof BaseKirishima; } export interface LoadTrackResponse extends OLoadTrackResponse {