import fs from "fs" import path from "path" import { logger } from "@/logger.js" import compose from "koa-compose" import { Next, ParameterizedContext } from "koa" async function scanControllers(rootDir: string) { const routers = [] const stack: string[] = [rootDir] while (stack.length) { const dir = stack.pop() if (!dir) continue let files try { files = fs.readdirSync(dir) } catch (error: any) { logger.error(`[控制器注册] ❌ 读取目录失败 ${dir}: ${error.message}`) continue } for (const file of files) { if (file.startsWith("_")) continue const fullPath = path.join(dir, file) let stat try { stat = fs.statSync(fullPath) } catch (error: any) { logger.error(`[控制器注册] ❌ 读取文件信息失败 ${fullPath}: ${error.message}`) continue } if (stat.isDirectory()) { stack.push(fullPath) continue } if (!fullPath.replace(/\\/g, "/").includes("/controller/")) continue let fileName = fullPath.replace(rootDir + path.sep, "") try { const controllerModule = await import(fullPath) const controller = controllerModule.default || controllerModule if (!controller) { logger.warn(`[控制器注册] ${fileName} - 缺少默认导出,跳过注册`) continue } let routesFactory = controller.createRoutes || controller.default?.createRoutes || controller.default || controller if (typeof routesFactory === "function") { routesFactory = routesFactory.bind(controller) } if (typeof routesFactory !== "function") { logger.warn(`[控制器注册] ⚠️ ${fileName} - 未找到 createRoutes 方法或导出对象`) continue } let routerResult try { routerResult = routesFactory() } catch (error: any) { logger.error(`[控制器注册] ❌ ${fileName} - createRoutes() 执行失败: ${error.message}`) continue } const list = Array.isArray(routerResult) ? routerResult : [routerResult] let added = 0 for (const r of list) { if (r && typeof r.middleware === "function") { routers.push(r) added++ } else { logger.warn(`[控制器注册] ⚠️ ${fileName} - createRoutes() 返回的部分路由器对象无效`) } } if (added > 0) logger.debug(`[控制器注册] ✅ ${fileName} - 创建成功 (${added})`) } catch (importError: any) { logger.error(`[控制器注册] ❌ ${fileName} - 模块导入失败: ${importError.message}`) logger.error(importError) } } } return routers } export default async function (options: { root: string, handleBeforeEachRequest: Function }) { const { root, handleBeforeEachRequest } = options if (!root) { throw new Error("controller root is required") } const routers = await scanControllers(root) const allRouters: any[] = [] for (let i = 0; i < routers.length; i++) { const router = routers[i] allRouters.push(router.middleware((options = {}) => handleBeforeEachRequest(options))) } return async function (ctx: ParameterizedContext, next: Next) { return await compose(allRouters)(ctx, next) } }