UNPKG

n1cat-discord-script-manager

Version:

A Discord.js plugin for dynamic script management and execution

215 lines (190 loc) 5.43 kB
const fs = require("fs"); const path = require("path"); const { promisify } = require("util"); const readdir = promisify(fs.readdir); const stat = promisify(fs.stat); const Logger = require("../utils/logger"); const { installDependency, extractMissingModule, } = require("../utils/moduleLoader"); // 用於追蹤函式調用的輔助函數 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 checkDependencies(scriptPath) { const logger = Logger.createContextLogger({ module: "ScriptLoader", debug: this.options?.debug || false, }); try { const content = await fs.promises.readFile(scriptPath, "utf8"); const requireMatches = content.match(/require\(['"](.+?)['"]\)/g) || []; const missingModules = []; for (const match of requireMatches) { const moduleName = match.match(/require\(['"](.+?)['"]\)/)[1]; try { require.resolve(moduleName); } catch (error) { if (error.code === "MODULE_NOT_FOUND") { missingModules.push(moduleName); } } } return missingModules; } catch (error) { logger.error(`檢查依賴時出錯: ${error.message}`); return []; } } async function installDependency(dependency) { const logger = Logger.createContextLogger({ module: "ScriptLoader", debug: this.options?.debug || false, }); try { logger.log(`正在安裝缺少的依賴: ${dependency}`); const { exec } = require("child_process"); await new Promise((resolve, reject) => { exec(`npm install ${dependency}`, (error) => { if (error) reject(error); else resolve(); }); }); return true; } catch (error) { logger.error(`安裝依賴失敗: ${error.message}`); return false; } } async function loadScript(scriptPath, options = {}) { const logger = Logger.createContextLogger({ module: "ScriptLoader", debug: options.debug || false, }); try { // 檢查依賴 const missingModules = await checkDependencies(scriptPath); for (const dependency of missingModules) { const success = await installDependency(dependency); if (!success) { throw new Error(`無法安裝依賴: ${dependency}`); } } // 清除快取 if (require.cache[scriptPath]) { delete require.cache[scriptPath]; } // 載入腳本 const script = require(scriptPath); logger.log(`✅ 成功安裝並載入依賴: ${dependency}`); return { success: true, script, error: null, }; } catch (error) { logger.error(`模組載入失敗: ${error.message}`); return { success: false, script: null, error: error.message, }; } } async function loadScripts(SCRIPT_FOLDER, options = {}) { const logger = Logger.createContextLogger({ module: "ScriptLoader", debug: options.debug || false, }); try { logger.log("\n=== Loading Scripts ==="); logger.log(`Loading scripts from folder: ${SCRIPT_FOLDER}`); const files = await readdir(SCRIPT_FOLDER); const scriptFiles = files.filter((file) => file.endsWith(".js")); if (scriptFiles.length === 0) { logger.log("No scripts found in folder"); return { total: 0, loaded: 0, errors: 0, scripts: [], }; } let loaded = 0; let errors = 0; const scripts = []; for (const file of scriptFiles) { logger.log(`\n載入腳本: ${file}`); const scriptPath = path.join(SCRIPT_FOLDER, file); try { const result = await loadScript(scriptPath, options); if (result.success) { scripts.push({ name: file, path: scriptPath, module: result.script, }); loaded++; logger.log(`✅ ${file}`); } else { errors++; logger.error(`載入腳本失敗 ${file}: ${result.error}`); } } catch (error) { errors++; logger.error(`載入腳本失敗 ${file}: ${error.message}`); } } logger.log("\n=== Script Loading Summary ==="); logger.log(`Total scripts found: ${scriptFiles.length}`); logger.log(`Successfully loaded: ${loaded}`); logger.log("========================\n"); return { total: scriptFiles.length, loaded, errors, scripts, }; } catch (error) { logger.error(`載入腳本時出錯: ${error.message}`); return { total: 0, loaded: 0, errors: 1, scripts: [], }; } } module.exports = { loadScripts, loadScript, checkDependencies, installDependency, };