From 910079b3dc76751556308b389c86ac6a761934f3 Mon Sep 17 00:00:00 2001 From: PoulavBhowmick03 Date: Wed, 29 Jan 2025 03:15:36 +0530 Subject: [PATCH] feat: modified discord i/o in the core package --- packages/core/src/core/io/discord.ts | 211 ++++++++++++++++++++++++++- 1 file changed, 206 insertions(+), 5 deletions(-) diff --git a/packages/core/src/core/io/discord.ts b/packages/core/src/core/io/discord.ts index cd76e71..347925e 100644 --- a/packages/core/src/core/io/discord.ts +++ b/packages/core/src/core/io/discord.ts @@ -1,4 +1,13 @@ -import { Client, Events, GatewayIntentBits, Partials, User } from "discord.js"; +import { + Client, + GatewayIntentBits, + Events, + Message, + ChannelType, + Partials, + TextChannel, + GuildMember, +} from "discord.js"; import type { JSONSchemaType } from "ajv"; import { Logger } from "../../core/logger"; import { LogLevel } from "../types"; @@ -19,6 +28,40 @@ export interface EventCallbacks { messageCreate?: (bot: any, message: any) => void; } +export interface ReactionData { + emoji: string; + messageId: string; + userId: string; +} + +export interface GuildMemberData { + userId: string; + username: string; + action: "join" | "leave"; +} + +export interface VoiceStateData { + guildId?: string; + userId: string; + channelId: string; + action: "join" | "leave" | "move"; +} + +export interface RoleData { + guildId: string; + userId: string; + roleId: string; + action: "add" | "remove"; +} + +export interface ChannelData { + guildId: string; + action: "create" | "delete"; + name?: string; + type?: ChannelType; + channelId?: string; +} + // Schema for message output validation export const messageSchema: JSONSchemaType = { type: "object", @@ -34,6 +77,7 @@ export const messageSchema: JSONSchemaType = { export class DiscordClient { private client: Client; + private isInitialized: boolean = false; private logger: Logger; constructor( @@ -63,7 +107,9 @@ export class DiscordClient { if (eventCallbacks.messageCreate) { this.client.on(Events.MessageCreate, (message) => { if (eventCallbacks.messageCreate) { - eventCallbacks.messageCreate(this.client.user, message); + if (this.client?.user) { + eventCallbacks.messageCreate(this.client.user, message); + } } }); } @@ -79,11 +125,47 @@ export class DiscordClient { } public destroy() { - this.client.destroy(); + this.client?.destroy(); + } + + /** + * Create an input that monitors messages + */ + public createMessageInput(interval: number = 60000, channelId?: string) { + return { + name: `discord_messages_${channelId || "all"}`, + handler: async () => { + return this.monitorMessages(channelId); + }, + response: { + type: "string", + content: "string", + metadata: "object", + }, + interval, + }; } /** - * Create an output for sending messages + * Create an output for monitoring joining or leaving of guild members + */ + public createGuildMemberInput() { + return { + name: "discord_guild_members", + handler: async () => { + return this.monitorGuildMembers(); + }, + response: { + type: "string", + userId: "string", + username: "string", + action: "string", + }, + }; + } + + /** + * Create an output for sending messages to a channel */ public createMessageOutput() { return { @@ -99,6 +181,77 @@ export class DiscordClient { }; } + private async monitorMessages(channelId?: string): Promise { + try { + this.logger.debug( + "DiscordClient.monitorMessages", + "Monitoring messages", + { channelId } + ); + + const messages: Message[] = []; + + if (channelId) { + // Fetch the channel and validate it + const channel = await this.client?.channels.fetch(channelId); + if (!channel || !channel.isTextBased()) { + throw new Error( + "Invalid channel or channel is not text-based" + ); + } + + const textChannel = channel as TextChannel; + + // Create a promise that resolves when the message collector ends + const collectedMessages = await new Promise( + (resolve) => { + const messageCollector = + textChannel.createMessageCollector({ + time: 60000, // Collect messages for 60 seconds + }); + + messageCollector.on("collect", (message) => { + messages.push(message); + }); + + messageCollector.on("end", () => { + this.logger.debug( + "DiscordClient.monitorMessages", + "Collected messages", + { count: messages.length } + ); + resolve(messages); // Resolve the promise with the collected messages + }); + } + ); + + return collectedMessages.map(this.formatMessageData); + } else { + // Handle global message collection (no specific channel) + return new Promise((resolve) => { + const messageHandler = (message: Message) => { + messages.push(message); + }; + + this.client?.on("messageCreate", messageHandler); + + // Optionally, you can add a timeout or condition to stop listening + setTimeout(() => { + this.client?.off("messageCreate", messageHandler); // Stop listening + resolve(messages.map(this.formatMessageData)); // Resolve with collected messages + }, 60000); // Stop after 60 seconds + }); + } + } catch (error) { + this.logger.error( + "DiscordClient.monitorMessages", + "Error monitoring messages", + { error } + ); + throw error; + } + } + private async sendMessage(data: MessageData) { try { this.logger.info( @@ -147,14 +300,62 @@ export class DiscordClient { throw error; } } + + private async monitorGuildMembers(): Promise { + return new Promise((resolve, reject) => { + try { + this.logger.debug( + "DiscordClient.monitorGuildMembers", + "Monitoring guild members" + ); + + const handleMemberEvent = ( + member: GuildMember, + action: "join" | "leave" + ) => { + const memberData: GuildMemberData = { + userId: member.id, + username: member.user.username, + action, + }; + resolve(memberData); + }; + + this.client?.on("guildMemberAdd", (member) => + handleMemberEvent(member as GuildMember, "join") + ); + this.client?.on("guildMemberRemove", (member) => + handleMemberEvent(member as GuildMember, "leave") + ); + } catch (error) { + this.logger.error( + "DiscordClient.monitorGuildMembers", + "Error monitoring guild members", + { error } + ); + reject(error); + } + }); + } + private formatMessageData(message: Message): MessageData { + return { + content: message.content, + channelId: message.channel.id, + sendBy: message.author.id, + }; + } } // Example usage: /* const discord = new DiscordClient({ - discord_token: "M..." + discord_token: process.env.DISCORD_TOKEN || "", }); +// Register inputs +core.createMessageInput("CHANNEL_ID"); +core.createGuildMemberInput(); + // Register output core.registerOutput(discord.createMessageOutput()); */