From 36acf92ad1182b1a156194c1dc2ec7e58af5b16c Mon Sep 17 00:00:00 2001 From: Yuzu Date: Sat, 2 Jul 2022 08:52:54 -0500 Subject: [PATCH] refactor: channels --- handlers/Actions.ts | 68 ++++++++++++++++++++++++++++++++++++++ structures/BaseChannel.ts | 41 +++++++++++++++++++---- structures/GuildChannel.ts | 2 +- structures/TextChannel.ts | 20 +++++++++++ 4 files changed, 123 insertions(+), 8 deletions(-) diff --git a/handlers/Actions.ts b/handlers/Actions.ts index 032853c..9d97992 100644 --- a/handlers/Actions.ts +++ b/handlers/Actions.ts @@ -1,14 +1,24 @@ import type { + DiscordChannel, + DiscordChannelPinsUpdate, DiscordGuildMemberAdd, DiscordGuildMemberRemove, DiscordGuildMemberUpdate, DiscordInteraction, + DiscordMemberWithUser, DiscordMessage, DiscordMessageDelete, DiscordReady, + // DiscordThreadMemberUpdate, + // DiscordThreadMembersUpdate, + DiscordThreadListSync, } from "../vendor/external.ts"; import type { Snowflake } from "../util/Snowflake.ts"; import type { Session } from "../session/Session.ts"; +import type { Channel } from "../structures/BaseChannel.ts"; +import BaseChannel from "../structures/BaseChannel.ts"; +import GuildChannel from "../structures/GuildChannel.ts"; +import ThreadChannel from "../structures/ThreadChannel.ts"; import Member from "../structures/Member.ts"; import Message from "../structures/Message.ts"; import User from "../structures/User.ts"; @@ -56,6 +66,56 @@ export const INTERACTION_CREATE: RawHandler = (session, _sha session.emit("interactionCreate", new Interaction(session, interaction)); }; +export const CHANNEL_CREATE: RawHandler = (session, _shardId, channel) => { + session.emit("channelCreate", BaseChannel.from(session, channel)); +}; + +export const CHANNEL_UPDATE: RawHandler = (session, _shardId, channel) => { + session.emit("channelUpdate", BaseChannel.from(session, channel)); +}; + +export const CHANNEL_DELETE: RawHandler = (session, _shardId, channel) => { + if (!channel.guild_id) return; + + session.emit("channelDelete", new GuildChannel(session, channel, channel.guild_id)); +}; + +export const THREAD_CREATE: RawHandler = (session, _shardId, channel) => { + if (!channel.guild_id) return; + + session.emit("threadCreate", new ThreadChannel(session, channel, channel.guild_id)); +}; + +export const THREAD_UPDATE: RawHandler = (session, _shardId, channel) => { + if (!channel.guild_id) return; + + session.emit("threadUpdate", new ThreadChannel(session, channel, channel.guild_id)); +}; + +export const THREAD_DELETE: RawHandler = (session, _shardId, channel) => { + if (!channel.guild_id) return; + + session.emit("threadDelete", new ThreadChannel(session, channel, channel.guild_id)); +}; + +export const THREAD_LIST_SYNC: RawHandler = (session, _shardId, payload) => { + session.emit("threadListSync", { + guildId: payload.guild_id, + channelIds: payload.channel_ids ?? [], + threads: payload.threads.map((channel) => new ThreadChannel(session, channel, payload.guild_id)), + // @ts-ignore: TODO: thread member structure + members: payload.members.map((member) => new Member(session, member as DiscordMemberWithUser, payload.guild_id)), + }); +}; + +export const CHANNEL_PINS_UPDATE: RawHandler = (session, _shardId, payload) => { + session.emit("channelPinsUpdate", { + guildId: payload.guild_id, + channelId: payload.channel_id, + lastPinTimestamp: payload.last_pin_timestamp ? Date.parse(payload.last_pin_timestamp) : undefined, + }); +}; + export const raw: RawHandler = (session, shardId, data) => { session.emit("raw", data, shardId); }; @@ -73,6 +133,14 @@ export interface Events { "guildMemberAdd": Handler<[Member]>; "guildMemberUpdate": Handler<[Member]>; "guildMemberRemove": Handler<[User, Snowflake]>; + "channelCreate": Handler<[Channel]>; + "channelUpdate": Handler<[Channel]>; + "channelDelete": Handler<[GuildChannel]>; + "channelPinsUpdate": Handler<[{ guildId?: Snowflake, channelId: Snowflake, lastPinTimestamp?: number }]> + "threadCreate": Handler<[ThreadChannel]>; + "threadUpdate": Handler<[ThreadChannel]>; + "threadDelete": Handler<[ThreadChannel]>; + "threadListSync": Handler<[{ guildId: Snowflake, channelIds: Snowflake[], threads: ThreadChannel[], members: Member[] }]> "interactionCreate": Handler<[Interaction]>; "raw": Handler<[unknown, number]>; } diff --git a/structures/BaseChannel.ts b/structures/BaseChannel.ts index a0ed80b..f7814ae 100644 --- a/structures/BaseChannel.ts +++ b/structures/BaseChannel.ts @@ -1,13 +1,21 @@ import type { Model } from "./Base.ts"; import type { Snowflake } from "../util/Snowflake.ts"; import type { Session } from "../session/Session.ts"; -import type { ChannelTypes, DiscordChannel } from "../vendor/external.ts"; -import TextChannel from "./TextChannel.ts"; +import type { DiscordChannel } from "../vendor/external.ts"; +import { ChannelTypes } from "../vendor/external.ts"; +import TextChannel, { textBasedChannels } from "./TextChannel.ts"; import VoiceChannel from "./VoiceChannel.ts"; import DMChannel from "./DMChannel.ts"; import NewsChannel from "./NewsChannel.ts"; import ThreadChannel from "./ThreadChannel.ts"; +export type Channel = + | TextChannel + | VoiceChannel + | DMChannel + | NewsChannel + | ThreadChannel; + export abstract class BaseChannel implements Model { constructor(session: Session, data: DiscordChannel) { this.id = data.id; @@ -22,23 +30,42 @@ export abstract class BaseChannel implements Model { type: ChannelTypes; isText(): this is TextChannel { - return this instanceof TextChannel; + return textBasedChannels.includes(this.type); } isVoice(): this is VoiceChannel { - return this instanceof VoiceChannel; + return this.type === ChannelTypes.GuildVoice; } isDM(): this is DMChannel { - return this instanceof DMChannel; + return this.type === ChannelTypes.DM; } isNews(): this is NewsChannel { - return this instanceof NewsChannel; + return this.type === ChannelTypes.GuildNews; } isThread(): this is ThreadChannel { - return this instanceof ThreadChannel; + return this.type === ChannelTypes.GuildPublicThread || this.type === ChannelTypes.GuildPrivateThread; + } + + static from(session: Session, channel: DiscordChannel): Channel { + switch (channel.type) { + case ChannelTypes.GuildPublicThread: + case ChannelTypes.GuildPrivateThread: + return new ThreadChannel(session, channel, channel.guild_id!); + case ChannelTypes.GuildNews: + return new NewsChannel(session, channel, channel.guild_id!); + case ChannelTypes.DM: + return new DMChannel(session, channel); + case ChannelTypes.GuildVoice: + return new VoiceChannel(session, channel, channel.guild_id!); + default: + if (textBasedChannels.includes(channel.type)) { + return new TextChannel(session, channel, channel.guild_id!); + } + throw new Error("Channel was not implemented"); + } } toString(): string { diff --git a/structures/GuildChannel.ts b/structures/GuildChannel.ts index 73dfd3b..2854425 100644 --- a/structures/GuildChannel.ts +++ b/structures/GuildChannel.ts @@ -6,7 +6,7 @@ import BaseChannel from "./BaseChannel.ts"; import Invite from "./Invite.ts"; import * as Routes from "../util/Routes.ts"; -export abstract class GuildChannel extends BaseChannel implements Model { +export class GuildChannel extends BaseChannel implements Model { constructor(session: Session, data: DiscordChannel, guildId: Snowflake) { super(session, data); this.guildId = guildId; diff --git a/structures/TextChannel.ts b/structures/TextChannel.ts index 7ecd39b..2491391 100644 --- a/structures/TextChannel.ts +++ b/structures/TextChannel.ts @@ -3,6 +3,7 @@ import type { Snowflake } from "../util/Snowflake.ts"; import type { GetMessagesOptions, GetReactions } from "../util/Routes.ts"; import type { DiscordChannel, DiscordInvite, DiscordMessage, TargetTypes } from "../vendor/external.ts"; import type { CreateMessage, EditMessage, ReactionResolvable } from "./Message.ts"; +import { ChannelTypes } from "../vendor/external.ts"; import GuildChannel from "./GuildChannel.ts"; import ThreadChannel from "./ThreadChannel.ts"; import Message from "./Message.ts"; @@ -36,15 +37,34 @@ export interface ThreadCreateOptions { reason?: string; } +export const textBasedChannels = [ + ChannelTypes.DM, + ChannelTypes.GroupDm, + ChannelTypes.GuildPrivateThread, + ChannelTypes.GuildPublicThread, + ChannelTypes.GuildNews, + ChannelTypes.GuildText, +]; + +export type TextBasedChannels = + | ChannelTypes.DM + | ChannelTypes.GroupDm + | ChannelTypes.GuildPrivateThread + | ChannelTypes.GuildPublicThread + | ChannelTypes.GuildNews + | ChannelTypes.GuildText; + export class TextChannel extends GuildChannel { constructor(session: Session, data: DiscordChannel, guildId: Snowflake) { super(session, data, guildId); data.last_message_id ? this.lastMessageId = data.last_message_id : undefined; data.last_pin_timestamp ? this.lastPinTimestamp = data.last_pin_timestamp : undefined; + this.type = data.type as TextBasedChannels; this.rateLimitPerUser = data.rate_limit_per_user ?? 0; this.nsfw = !!data.nsfw ?? false; } + override type: TextBasedChannels; lastMessageId?: Snowflake; lastPinTimestamp?: string; rateLimitPerUser: number;