diff --git a/framework/src/client/events.ts b/framework/src/client/events.ts index 4a4659b5..164b2899 100644 --- a/framework/src/client/events.ts +++ b/framework/src/client/events.ts @@ -1,7 +1,9 @@ +import type { Guild } from "../structures/guilds/guild.ts"; import type { Message } from "../structures/mod.ts"; // ...this is gonna be very painful to fix export type ClientEvents = { messageCreate: [Message]; ready: []; + guildCreate: [Guild]; }; diff --git a/framework/src/client/mod.ts b/framework/src/client/mod.ts index cbc6c5a3..5ef60a53 100644 --- a/framework/src/client/mod.ts +++ b/framework/src/client/mod.ts @@ -48,7 +48,7 @@ export class Client extends EventEmitter { waitFor( event: K, - check: (...args: ClientEvents[K]) => boolean, + check?: (...args: ClientEvents[K]) => boolean, timeout?: number, ): Promise { return new Promise((resolve) => { @@ -60,7 +60,7 @@ export class Client extends EventEmitter { }, timeout); } const eventFunc = (...args: ClientEvents[K]): void => { - if (check(...args)) { + if (check && check(...args) || !check) { resolve(args); this.off(event, eventFunc); if (timeoutID !== undefined) clearTimeout(timeoutID); diff --git a/framework/src/gateway/guildCreate.ts b/framework/src/gateway/guildCreate.ts new file mode 100644 index 00000000..6aa2e784 --- /dev/null +++ b/framework/src/gateway/guildCreate.ts @@ -0,0 +1,15 @@ +import { GatewayHandler } from "../../types/mod.ts"; + +const guildCreate: GatewayHandler<"GUILD_CREATE"> = async ( + client, + [_, guild], +) => { + client.guilds.set(guild.id, guild); + + const guildObj = client.guilds.get(guild.id)!; + await guildObj.channels.fetchAll(); + + client.emit("guildCreate", guildObj); +}; + +export default guildCreate; diff --git a/framework/src/gateway/mod.ts b/framework/src/gateway/mod.ts index b2e690f9..d0690c86 100644 --- a/framework/src/gateway/mod.ts +++ b/framework/src/gateway/mod.ts @@ -1,4 +1,5 @@ import type { GatewayHandler } from "../../types/gateway.ts"; +import guildCreate from "./guildCreate.ts"; import messageCreate from "./messageCreate.ts"; import ready from "./ready.ts"; @@ -6,4 +7,5 @@ import ready from "./ready.ts"; export const GatewayHandlers: { [K: string]: GatewayHandler } = { MESSAGE_CREATE: messageCreate, READY: ready, + GUILD_CREATE: guildCreate, }; diff --git a/framework/src/gateway/ready.ts b/framework/src/gateway/ready.ts index ea78efc8..3a5defa9 100644 --- a/framework/src/gateway/ready.ts +++ b/framework/src/gateway/ready.ts @@ -15,6 +15,8 @@ const ready: GatewayHandler<"READY"> = ( client.guilds.set(g.id, g); }); + // TODO: implement application loading + client.emit("ready"); }; diff --git a/framework/src/managers/base.ts b/framework/src/managers/base.ts index a604ec87..d97e06ad 100644 --- a/framework/src/managers/base.ts +++ b/framework/src/managers/base.ts @@ -17,7 +17,6 @@ export class BaseManager { throw new Error("Not implemented"); } - // try _get first, if not found, fetch get(_key: string): T | undefined { throw new Error("Not implemented"); } diff --git a/framework/src/managers/channels.ts b/framework/src/managers/channels.ts index 4b806ea3..b40b8467 100644 --- a/framework/src/managers/channels.ts +++ b/framework/src/managers/channels.ts @@ -7,9 +7,8 @@ import { Channel } from "../structures/channels/channel.ts"; import { GuildTextChannel } from "../structures/channels/guildTextChannel.ts"; import { BaseManager } from "./base.ts"; -export class ChannelsManager - extends BaseManager> { - private createChannel

(payload: P) { +export class ChannelsManager extends BaseManager { + private _createChannel

(payload: P) { switch (payload.type) { case ChannelType.GUILD_TEXT: return new GuildTextChannel( @@ -43,7 +42,7 @@ export class ChannelsManager ) { const cached = this._get(id); if (!cached) return; - return this.createChannel(cached); + return this._createChannel(cached); } async fetch

( id: string, @@ -51,7 +50,7 @@ export class ChannelsManager try { const payload = await this._fetch

(id); if (!payload) return; - return this.createChannel(payload); + return this._createChannel(payload); } catch (_err) { return; } diff --git a/framework/src/managers/guildChannels.ts b/framework/src/managers/guildChannels.ts new file mode 100644 index 00000000..149e202d --- /dev/null +++ b/framework/src/managers/guildChannels.ts @@ -0,0 +1,108 @@ +import { + ChannelType, + type GuildChannelPayload, + type GuildTextChannelPayload, +} from "../../../types/mod.ts"; +import type { Client } from "../client/mod.ts"; +import { GuildChannel } from "../structures/channels/guildChannel.ts"; +import { GuildTextChannel } from "../structures/channels/guildTextChannel.ts"; +import { BaseManager } from "./base.ts"; +import { BaseChildManager } from "./baseChild.ts"; +import type { ChannelsManager } from "./channels.ts"; + +export class GuildChannelsManager + extends BaseChildManager { + guildID: string; + + constructor(client: Client, parent: ChannelsManager, guildID: string) { + super( + client, + parent as unknown as BaseManager, + ); + this.guildID = guildID; + } + + private _createChannel

(payload: P) { + switch (payload.type) { + case ChannelType.GUILD_TEXT: + return new GuildTextChannel( + this.client, + payload as unknown as GuildTextChannelPayload, + ); + default: + return new GuildChannel(this.client, payload); + } + } + + _fill(payloads: GuildChannelPayload[]) { + for (const payload of payloads) { + this.set(payload.id!, payload); + } + } + + _get(key: string): GuildChannelPayload | undefined { + const channel = this.parent._get(key); + if (!channel) return; + if (channel.guild_id !== this.guildID) return; + return channel; + } + + async _fetchAll(): Promise { + try { + const resp: GuildChannelPayload[] | undefined = await this.client.rest + .get( + `/guilds/${this.guildID}/channels`, + ); + if (!resp) return; + const channels = resp; + this._fill(channels); + return channels; + } catch (_err) { + return; + } + } + + async _fetch(id: string): Promise { + try { + const resp: GuildChannelPayload | undefined = await this.client.rest + .get( + `/channels/${id}`, + ); + if (!resp) return; + this.set(id, resp); + return resp; + } catch (_err) { + return; + } + } + + get( + id: string, + ) { + const cached = this._get(id); + if (!cached) return; + return this._createChannel(cached); + } + + async fetchAll() { + try { + const channels = await this._fetchAll(); + if (!channels) return; + return channels.map((r) => this._createChannel(r)); + } catch (_err) { + return; + } + } + + async fetch( + id: string, + ) { + try { + const payload = await this._fetch(id); + if (!payload) return; + return this._createChannel(payload); + } catch (_err) { + return; + } + } +} diff --git a/framework/src/managers/guilds.ts b/framework/src/managers/guilds.ts index 665cdc1a..8cc30571 100644 --- a/framework/src/managers/guilds.ts +++ b/framework/src/managers/guilds.ts @@ -32,6 +32,7 @@ export class GuildsManager extends BaseManager { // TODO: remove more duplication const lightGuild: LightGuildPayload = { ...value, + channels: undefined, roles: undefined, emojis: undefined, }; diff --git a/framework/src/structures/guilds/guild.ts b/framework/src/structures/guilds/guild.ts index 0433a15d..081286c1 100644 --- a/framework/src/structures/guilds/guild.ts +++ b/framework/src/structures/guilds/guild.ts @@ -11,6 +11,7 @@ import type { } from "../../../../types/mod.ts"; import { LightGuildPayload } from "../../../types/guild.ts"; import { Client } from "../../client/mod.ts"; +import { GuildChannelsManager } from "../../managers/guildChannels.ts"; import { GuildEmojisManager } from "../../managers/guildEmojis.ts"; import { GuildRolesManager } from "../../managers/guildRoles.ts"; import { UnavailableGuild } from "./unavaliable.ts"; @@ -18,6 +19,7 @@ import { UnavailableGuild } from "./unavaliable.ts"; export class Guild extends UnavailableGuild { roles: GuildRolesManager; emojis: GuildEmojisManager; + channels: GuildChannelsManager; constructor(client: Client, payload: LightGuildPayload) { // TODO: think about fill methods super(client, payload); @@ -29,6 +31,14 @@ export class Guild extends UnavailableGuild { if (payload.emojis) { this.emojis._fill(payload.emojis); } + this.channels = new GuildChannelsManager( + client, + client.channels, + payload.id, + ); + if (payload.channels) { + this.channels._fill(payload.channels); + } } get name(): string { @@ -112,9 +122,6 @@ export class Guild extends UnavailableGuild { // get members(): string[] { // return this.payload.members; // } - // get channels(): string[] { - // return this.payload.channels; - // } // get threads(): string[] { // return this.payload.threads; // } diff --git a/framework/src/structures/messages/mod.ts b/framework/src/structures/messages/mod.ts index 9e078bc7..6efa4ccd 100644 --- a/framework/src/structures/messages/mod.ts +++ b/framework/src/structures/messages/mod.ts @@ -79,4 +79,10 @@ export class Message { // return this.client.channels.get(channel.id); // }) // } + + get guild() { + return this.payload.guild_id + ? this.client.guilds.get(this.payload.guild_id) + : undefined; + } } diff --git a/framework/types/guild.ts b/framework/types/guild.ts index 2832b4db..66b871b4 100644 --- a/framework/types/guild.ts +++ b/framework/types/guild.ts @@ -3,5 +3,5 @@ import { SelectivePartial } from "./utils.ts"; export type LightGuildPayload = SelectivePartial< GuildPayload, - "roles" | "emojis" + "roles" | "emojis" | "channels" >;