Skip to content

Commit

Permalink
WIP - Create client adapter skeleton
Browse files Browse the repository at this point in the history
  • Loading branch information
mariusbegby committed Aug 12, 2024
1 parent 42a8e6a commit 10f7b07
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 33 deletions.
29 changes: 21 additions & 8 deletions packages/discord-player/src/Player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { Context, createContext } from './hooks';
import { HooksCtx } from './hooks/common';
import { LrcLib } from './lrclib/LrcLib';
import { getCompatName, isClientProxy } from './compat/createErisCompat';
import type { IClientAdapter } from './clientadapter/IClientAdapter';
import { ClientAdapterFactory } from './clientadapter/ClientAdapterFactory';

const kSingleton = Symbol('InstanceDiscordPlayerSingleton');

Expand Down Expand Up @@ -61,6 +63,10 @@ export class Player extends PlayerEventsEmitter<PlayerEvents> {
* The discord.js client
*/
public readonly client!: Client;
/**
* The discord.js client
*/
public readonly clientAdapter!: IClientAdapter;
/**
* The player options
*/
Expand Down Expand Up @@ -119,6 +125,13 @@ export class Player extends PlayerEventsEmitter<PlayerEvents> {
*/
this.client = client;

/**
* The api client adapter (discord.js or eris)
* @type {IClientAdapter}
*/
this.clientAdapter = ClientAdapterFactory.createClientAdapter(client);


if (!isCompatMode) {
try {
if (!(client instanceof Client)) {
Expand All @@ -128,7 +141,7 @@ export class Player extends PlayerEventsEmitter<PlayerEvents> {
);
}

const ibf = this.client.options.intents instanceof IntentsBitField ? this.client.options.intents : new IntentsBitField(this.client.options.intents);
const ibf = this.client.options.intents instanceof IntentsBitField ? this.client.options.intents : new IntentsBitField(this.client.options.intents); // TODO: USE CLIENTADAPTER

if (!ibf.has(IntentsBitField.Flags.GuildVoiceStates)) {
Util.warn('client is missing "GuildVoiceStates" intent', 'InvalidIntentsBitField');
Expand Down Expand Up @@ -157,8 +170,8 @@ export class Player extends PlayerEventsEmitter<PlayerEvents> {

if (!isCompatMode) {
// @ts-ignore private method
this.client.incrementMaxListeners();
this.client.on(Events.VoiceStateUpdate, this.#voiceStateUpdateListener);
this.client.incrementMaxListeners(); // TODO: USE CLIENTADAPTER
this.client.on(Events.VoiceStateUpdate, this.#voiceStateUpdateListener); // TODO: USE CLIENTADAPTER
}

if (typeof this.options.lagMonitor === 'number' && this.options.lagMonitor > 0) {
Expand Down Expand Up @@ -316,12 +329,12 @@ export class Player extends PlayerEventsEmitter<PlayerEvents> {
* ```
*/
public async destroy() {
this.nodes.cache.forEach((node) => node.delete());
this.nodes.cache.forEach((node) => node.delete()); // TODO: USE CLIENTADAPTER

if (!this.isCompatMode()) {
this.client.off(Events.VoiceStateUpdate, this.#voiceStateUpdateListener);
this.client.off(Events.VoiceStateUpdate, this.#voiceStateUpdateListener); // TODO: USE CLIENTADAPTER
// @ts-ignore private method
this.client.decrementMaxListeners();
this.client.decrementMaxListeners(); // TODO: USE CLIENTADAPTER
}

this.removeAllListeners();
Expand Down Expand Up @@ -401,7 +414,7 @@ export class Player extends PlayerEventsEmitter<PlayerEvents> {
* ```
*/
public async play<T = unknown>(channel: GuildVoiceChannelResolvable, query: TrackLike, options: PlayerNodeInitializerOptions<T> = {}): Promise<PlayerNodeInitializationResult<T>> {
const vc = this.client.channels.resolve(channel);
const vc = this.client.channels.resolve(channel); // TODO: USE CLIENTADAPTER
if (!vc?.isVoiceBased()) throw Exceptions.ERR_INVALID_ARG_TYPE('channel', 'VoiceBasedChannel', !vc ? 'undefined' : `channel type ${vc.type}`);

const originalResult = query instanceof SearchResult ? query : await this.search(query, options);
Expand Down Expand Up @@ -457,7 +470,7 @@ export class Player extends PlayerEventsEmitter<PlayerEvents> {
public async search(searchQuery: string | Track | Track[] | Playlist | SearchResult, options: SearchOptions = {}): Promise<SearchResult> {
if (searchQuery instanceof SearchResult) return searchQuery;

if (options.requestedBy != null) options.requestedBy = this.client.users.resolve(options.requestedBy)!;
if (options.requestedBy != null) options.requestedBy = this.client.users.resolve(options.requestedBy)!; // TODO: USE CLIENTADAPTER
options.blockExtractors ??= this.options.blockExtractors;
options.fallbackSearchEngine ??= QueryType.AUTO_SEARCH;

Expand Down
49 changes: 49 additions & 0 deletions packages/discord-player/src/clientadapter/ClientAdapterFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Client as DiscordJsClient } from 'discord.js';
import { Client as ErisClient } from 'eris';
import { DiscordJsClientAdapter } from './DiscordJsClientAdapter';
import { IClientAdapter } from './IClientAdapter';
import { Util } from '../utils/Util';

enum ClientType {
DiscordJs = 'DjsClient',
Eris = 'ErisClient',
Unknown = 'Unknown'
}

type SupportedClient = DiscordJsClient | ErisClient;

export class ClientAdapterFactory {
static createClientAdapter(client: SupportedClient): IClientAdapter {
try {
const clientType = this.getClientType(client);

switch (clientType) {
case ClientType.DiscordJs:
return new DiscordJsClientAdapter((client as DiscordJsClient));
case ClientType.Eris:
Util.warn(
`You are using an Eris client, some things may not work correctly. This is currently under experimental support and it is still recommended to use a discord.js client.`,
'ExperimentalClientInstance'
);
// return new ErisClientAdapter((client as ErisClient));
throw new Error('Eris client is not supported yet');
default:
throw new Error('Unsupported client type');
}
} catch (error) {
throw new Error(`Failed to create client adapter: ${error}`);
}
}

private static getClientType(client: SupportedClient): ClientType {
if (client instanceof DiscordJsClient) {
return ClientType.DiscordJs;
}

if (client instanceof ErisClient) {
return ClientType.Eris;
}

return ClientType.Unknown;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Client } from "discord.js";
import { IClientAdapter } from "./IClientAdapter";

export class DiscordJsClientAdapter implements IClientAdapter {
private client: Client;

constructor(client: Client) {
this.client = client;
}
}
3 changes: 3 additions & 0 deletions packages/discord-player/src/clientadapter/IClientAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface IClientAdapter {

}
2 changes: 1 addition & 1 deletion packages/discord-player/src/compat/createErisCompat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ function erisChannelsProxy(client: Eris.Client, eris: typeof import('eris')) {
},
resolve(resolvable: string | ErisChannelResolvable) {
if (typeof resolvable === 'string') {
return erisResolvedChannelProxy(this.client.getChannel(resolvable) as Eris.GuildChannel, client);
return erisResolvedChannelProxy(this.client.getChannel(resolvable) as Eris.GuildChannel, client); // TODO: USE CLIENTADAPTER
}

if (resolvable instanceof eris.GuildChannel) {
Expand Down
24 changes: 12 additions & 12 deletions packages/discord-player/src/fabric/Track.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,18 +191,18 @@ export class Track<T = unknown> {
...data,
requestedBy: data.requested_by
? (() => {
const res = data.requested_by as APIUser;
try {
const resolved = player.client.users.resolve(res.id);
if (resolved) return resolved;
if (player.client.users.cache.has(res.id)) return player.client.users.cache.get(res.id)!;
// @ts-expect-error
const user = new User(player.client, res);
return user;
} catch {
return null;
}
})()
const res = data.requested_by as APIUser;
try {
const resolved = player.client.users.resolve(res.id); // TODO: USE CLIENTADAPTER
if (resolved) return resolved;
if (player.client.users.cache.has(res.id)) return player.client.users.cache.get(res.id)!; // TODO: USE CLIENTADAPTER
// @ts-expect-error
const user = new User(player.client, res);
return user;
} catch {
return null;
}
})()
: null,
queryType: data.query_type ?? undefined
});
Expand Down
8 changes: 4 additions & 4 deletions packages/discord-player/src/queue/GuildNodeManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ export type NodeResolvable = GuildQueue | GuildResolvable;

export class GuildNodeManager<Meta = unknown> {
public cache = new Collection<string, GuildQueue>();
public constructor(public player: Player) {}
public constructor(public player: Player) { }

/**
* Create guild queue if it does not exist
* @param guild The guild which will be the owner of the queue
* @param options Queue initializer options
*/
public create<T = Meta>(guild: GuildResolvable, options: GuildNodeCreateOptions<T> = {}): GuildQueue<T> {
const server = this.player.client.guilds.resolve(guild);
const server = this.player.client.guilds.resolve(guild); // TODO: USE CLIENTADAPTER
if (!server) {
throw Exceptions.ERR_NO_GUILD('Invalid or unknown guild');
}
Expand Down Expand Up @@ -152,7 +152,7 @@ export class GuildNodeManager<Meta = unknown> {
* @param node Queue resolvable
*/
public has(node: NodeResolvable) {
const id = node instanceof GuildQueue ? node.id : this.player.client.guilds.resolveId(node)!;
const id = node instanceof GuildQueue ? node.id : this.player.client.guilds.resolveId(node)!; // TODO: USE CLIENTADAPTER
return this.cache.has(id);
}

Expand Down Expand Up @@ -187,7 +187,7 @@ export class GuildNodeManager<Meta = unknown> {
return node;
}

return this.cache.get(this.player.client.guilds.resolveId(node)!) as GuildQueue<T> | undefined;
return this.cache.get(this.player.client.guilds.resolveId(node)!) as GuildQueue<T> | undefined; // TODO: USE CLIENTADAPTER
}

/**
Expand Down
12 changes: 6 additions & 6 deletions packages/discord-player/src/queue/GuildQueue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ export class GuildQueue<Meta = unknown> {
throw Exceptions.ERR_VOICE_CONNECTION_DESTROYED();
}

const channel = this.player.client.channels.cache.get(connection.joinConfig.channelId!);
const channel = this.player.client.channels.cache.get(connection.joinConfig.channelId!); // TODO: USE CLIENTADAPTER
if (!channel) throw Exceptions.ERR_NO_VOICE_CHANNEL();
if (!channel.isVoiceBased()) throw Exceptions.ERR_INVALID_ARG_TYPE('channel', `VoiceBasedChannel (type ${ChannelType.GuildVoice}/${ChannelType.GuildStageVoice})`, String(channel?.type));

Expand All @@ -820,7 +820,7 @@ export class GuildQueue<Meta = unknown> {
* @param options Join config
*/
public async connect(channelResolvable: GuildVoiceChannelResolvable, options: VoiceConnectConfig = {}) {
const channel = this.player.client.channels.resolve(channelResolvable);
const channel = this.player.client.channels.resolve(channelResolvable); // TODO: USE CLIENTADAPTER
if (!channel || !channel.isVoiceBased()) {
throw Exceptions.ERR_INVALID_ARG_TYPE('channel', `VoiceBasedChannel (type ${ChannelType.GuildVoice}/${ChannelType.GuildStageVoice})`, String(channel?.type));
}
Expand All @@ -839,7 +839,7 @@ export class GuildQueue<Meta = unknown> {
maxTime: options?.timeout ?? this.options.connectionTimeout ?? 120_000,
queue: this,
audioPlayer: options?.audioPlayer,
group: options.group ?? this.player.client.user?.id
group: options.group ?? this.player.client.user?.id // TODO: USE CLIENTADAPTER
});

this.emit(GuildQueueEvent.connection, this);
Expand Down Expand Up @@ -1138,9 +1138,9 @@ export class GuildQueue<Meta = unknown> {
resolver(
tracks.length
? (() => {
const unique = tracks.filter((tr) => !this.history.tracks.find((t) => t.url === tr.url));
return unique?.[0] ?? Util.randomChoice(tracks.slice(0, 5));
})()
const unique = tracks.filter((tr) => !this.history.tracks.find((t) => t.url === tr.url));
return unique?.[0] ?? Util.randomChoice(tracks.slice(0, 5));
})()
: null
);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/discord-player/src/queue/VoiceReceiverNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface VoiceReceiverOptions {
export type RawTrackInit = Partial<Omit<RawTrackData, 'author' | 'playlist' | 'source' | 'engine' | 'raw' | 'queryType' | 'description' | 'views'>>;

export class VoiceReceiverNode {
public constructor(public dispatcher: StreamDispatcher) {}
public constructor(public dispatcher: StreamDispatcher) { }

public createRawTrack(stream: Readable, data: RawTrackInit = {}) {
data.title ??= `Recording ${Date.now()}`;
Expand Down Expand Up @@ -62,7 +62,7 @@ export class VoiceReceiverNode {
silenceDuration: 1000
}
) {
const _user = this.dispatcher.queue.player.client.users.resolveId(user);
const _user = this.dispatcher.queue.player.client.users.resolveId(user); // TODO: USE CLIENTADAPTER

const passThrough = new PassThrough();
const receiver = this.dispatcher.voiceConnection.receiver;
Expand Down

0 comments on commit 10f7b07

Please sign in to comment.