n1cat-discord-script-manager
Version:
A Discord.js plugin for dynamic script management and execution
253 lines (216 loc) • 7.17 kB
JavaScript
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,
};