UNPKG

n1cat-discord-script-manager

Version:

A Discord.js plugin for dynamic script management and execution

253 lines (216 loc) 7.17 kB
const { EmbedBuilder } = require("discord.js"); const fs = require("fs"); const path = require("path"); const Logger = require("../utils/logger"); // 用於追蹤函式調用的輔助函數 function getCallerInfo() { const stack = new Error().stack; const callerLine = stack.split("\n")[3]; // 跳過 Error 和 getCallerInfo 的堆疊 const match = callerLine.match(/at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/); if (match) { const [, functionName, file, line, column] = match; return { function: functionName, file: file.split("/").pop(), // 只取檔案名稱 line, column, }; } return { function: "unknown", file: "unknown", line: "unknown", column: "unknown", }; } // 日誌輸出函數 function log(message, isError = false) { const caller = getCallerInfo(); const debugMode = this.options?.debug ?? false; // 如果是錯誤或 debug 模式開啟,則輸出詳細日誌 if (isError || debugMode) { console.log(`[${caller.file}:${caller.line}] ${message}`); } } // 主要消息處理函數 async function handleMessage(message, client) { const logger = Logger.createContextLogger({ module: "EventHandler", debug: client.config?.debug || false, }); if (!message || typeof message !== "object") { logger.error("Invalid message object"); return; } try { // 檢查是否是機器人消息 if (message.author.bot) return; // 檢查消息內容 if (!message.content) return; // 檢查是否是命令 if (!message.content.startsWith(client.config.prefix)) return; // 解析命令 const args = message.content .slice(client.config.prefix.length) .trim() .split(/ +/); const commandName = args.shift().toLowerCase(); // 獲取命令 const command = client.commands.get(commandName); if (!command) return; try { // 執行命令 await command.execute(message, args, client); } catch (error) { logger.error(`Error executing command: ${error.message}`, { showStack: true, }); try { await message.reply("執行命令時出錯,請稍後再試。"); } catch (replyError) { logger.error(`Critical error sending message: ${replyError.message}`, { showStack: true, }); } } } catch (error) { logger.error(`Error processing message: ${error.message}`, { showStack: true, }); } } // 創建消息處理器 - 完全重新設計的 API 以避免 Discord.js 的不穩定性 function createMessageHandler(message) { const logger = Logger.createContextLogger({ module: "MessageHandlerCreation", debug: false, }); return { // 基本屬性 content: message.content, author: message.author, channel: message.channel, guild: message.guild, member: message.member, // 內容處理方法 split: (separator = " ") => message.content.split(separator), includes: (text) => message.content.includes(text), startsWith: (text) => message.content.startsWith(text), // 回覆方法 - 使用 channel.send 並模擬回覆效果,避免 reply 的問題 reply: async (options) => { try { // 處理不同的輸入格式 let sendOptions = {}; if (typeof options === "string") { sendOptions.content = options; } else if (options && typeof options === "object") { sendOptions = { ...options }; } // 添加引用原始消息的引用資料 sendOptions.reference = { messageId: message.id }; // 使用 channel.send 替代 reply return await message.channel.send(sendOptions); } catch (error) { logger.error("Error sending message", { showStack: true }); // 嘗試最基本的訊息發送方式 try { return await message.channel.send( typeof options === "string" ? options : options?.content || "Error occurred" ); } catch (e) { logger.error("Critical error sending message", { showStack: true }); return null; } } }, // 直接發送訊息,不引用原訊息 send: async (options) => { try { return await message.channel.send( typeof options === "string" ? options : options ); } catch (error) { logger.error("Error sending message", { showStack: true }); return null; } }, // 創建並發送嵌入消息 sendEmbed: async (options) => { try { const embed = new EmbedBuilder(); if (options.title) embed.setTitle(options.title); if (options.description) embed.setDescription(options.description); if (options.color) embed.setColor(options.color); if (options.thumbnail) embed.setThumbnail(options.thumbnail); if (options.image) embed.setImage(options.image); if (options.footer) embed.setFooter(options.footer); if (options.fields) embed.addFields(options.fields); return await message.channel.send({ embeds: [embed] }); } catch (error) { logger.error("Error sending embed", { showStack: true }); return null; } }, // 獲取原始消息物件 (僅供高級使用) getRawMessage: () => message, // 將消息處理器轉換為字符串 toString: () => message.content, }; } async function handleCommandError(error, fileName, message) { const logger = Logger.createContextLogger({ module: "CommandErrorHandler", debug: false, }); logger.error(`Error in ${fileName}: ${error.message}`, { showStack: true }); } async function handleInteraction(interaction, client) { const logger = Logger.createContextLogger({ module: "InteractionHandler", debug: client.config?.debug || false, }); if (interaction.isCommand()) { await handleSlashCommand(interaction, client); } else if (interaction.isButton()) { await handleButtonInteraction(interaction); } } async function handleSlashCommand(interaction, client) { const logger = Logger.createContextLogger({ module: "SlashCommandHandler", debug: client.config?.debug || false, }); const command = client.slashCommands.get(interaction.commandName); if (!command) return; try { await command.execute(interaction); } catch (error) { logger.error("Error executing slash command", { showStack: true }); await interaction.reply({ content: "There was an error while executing this command!", ephemeral: true, }); } } async function handleButtonInteraction(interaction) { const logger = Logger.createContextLogger({ module: "ButtonInteractionHandler", debug: false, }); const interactionHandler = require("../commands/interaction"); try { await interactionHandler.execute(interaction); } catch (error) { logger.error("Button interaction error", { showStack: true }); await interaction.reply({ content: "處理按鈕互動時發生錯誤。", ephemeral: true, }); } } module.exports = { handleMessage, handleInteraction, };