mira-app-server
Version:
Mira Server - standalone server application using mira-app-core
248 lines • 10.9 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HttpRouter = void 0;
const express_1 = __importDefault(require("express"));
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
class HttpRouter {
constructor(bakend) {
this.registerdRounters = new Map();
this.libraryServices = [];
this.backend = bakend;
this.router = express_1.default.Router();
this.setupRoutes();
}
registerRounter(libraryId, path, method, router) {
// 获取或创建该路径的 handler Map
if (!this.registerdRounters.has(path)) {
this.registerdRounters.set(path, new Map());
// 为该路径注册一个统一的处理函数
const combinedHandler = async (req, res, next) => {
// 从请求中获取 libraryId
const requestLibraryId = req.body?.libraryId || req.query?.libraryId || req.params?.libraryId;
if (!requestLibraryId) {
return res.status(400).send('Missing libraryId parameter');
}
const handlersMap = this.registerdRounters.get(path);
if (!handlersMap) {
return res.status(404).send('No handlers found for this path');
}
const handler = handlersMap.get(requestLibraryId);
if (!handler) {
return res.status(404).send(`No handler found for libraryId: ${requestLibraryId}`);
}
console.log(`Processing request for path: ${path}, libraryId: ${requestLibraryId}`);
// 调用对应的 handler
handler(req, res, next);
};
// 根据 method 注册到 express router
switch (method.toLowerCase()) {
case 'post':
this.router.post(path, combinedHandler);
break;
case 'get':
this.router.get(path, combinedHandler);
break;
case 'put':
this.router.put(path, combinedHandler);
break;
case 'delete':
this.router.delete(path, combinedHandler);
break;
case 'patch':
this.router.patch(path, combinedHandler);
break;
case 'head':
this.router.head(path, combinedHandler);
break;
case 'options':
this.router.options(path, combinedHandler);
break;
case 'trace':
this.router.trace(path, combinedHandler);
break;
case 'connect':
this.router.connect(path, combinedHandler);
break;
default:
throw new Error('不支持的方法');
}
}
// 将新的 handler 添加到 Map 中,以 libraryId 为 key
this.registerdRounters.get(path).set(libraryId, router);
}
unregisterRounter(path, libraryId, handler) {
if (!this.registerdRounters.has(path)) {
return;
}
const handlersMap = this.registerdRounters.get(path);
if (libraryId) {
// 移除特定 libraryId 的 handler
if (handler) {
// 检查是否是指定的 handler
const existingHandler = handlersMap.get(libraryId);
if (existingHandler === handler) {
handlersMap.delete(libraryId);
}
}
else {
// 移除该 libraryId 的 handler
handlersMap.delete(libraryId);
}
// 如果没有更多 handler,移除整个路径
if (handlersMap.size === 0) {
this.registerdRounters.delete(path);
// 注意:这里无法从 express router 中移除路由
// express 不支持动态移除路由,只能重新创建 router
}
}
else {
// 移除整个路径的所有 handlers
this.registerdRounters.delete(path);
}
}
// 获取指定路径和 libraryId 的 handler
getHandler(path, libraryId) {
const handlersMap = this.registerdRounters.get(path);
return handlersMap?.get(libraryId);
}
// 获取指定路径的所有 handlers(返回 Map)
getHandlers(path) {
return this.registerdRounters.get(path);
}
// 获取所有注册的路径
getRegisteredPaths() {
return Array.from(this.registerdRounters.keys());
}
// 检查路径是否已注册
hasPath(path) {
return this.registerdRounters.has(path);
}
// 检查特定路径和 libraryId 是否已注册
hasPathForLibrary(path, libraryId) {
const handlersMap = this.registerdRounters.get(path);
return handlersMap ? handlersMap.has(libraryId) : false;
}
setupRoutes() {
// 插件文件获取接口
this.router.get('/plugins/:libraryId/:pluginName/*', (req, res) => {
try {
const { libraryId, pluginName } = req.params;
const filePath = req.params[0]; // 获取 * 匹配的部分
// 从库存储中获取库数据
const libraries = this.backend.libraries?.getLibraries();
if (!libraries || !libraries[libraryId]) {
return res.status(404).json({ error: 'Library not found' });
}
const libraryData = libraries[libraryId];
// 获取库的插件管理器
const pluginManager = libraryData.pluginManager;
if (!pluginManager) {
return res.status(500).json({ error: 'Plugin manager not available for this library' });
}
const pluginDir = pluginManager.getPluginDistDir(pluginName);
let fullFilePath = path.join(pluginDir, filePath);
// dist/ 下找不到则回退到插件根目录
if (!fs.existsSync(fullFilePath)) {
fullFilePath = path.join(pluginManager.getPluginDir(pluginName), filePath);
}
// 安全检查:确保文件路径在插件目录内
const resolvedPath = path.resolve(fullFilePath);
const resolvedPluginDir = path.resolve(pluginManager.getPluginDir(pluginName));
if (!resolvedPath.startsWith(resolvedPluginDir)) {
return res.status(403).json({ error: 'Access denied: path outside plugin directory' });
}
console.log({ resolvedPath, filePath });
// 检查文件是否存在
if (!fs.existsSync(resolvedPath)) {
return res.status(404).json({ error: 'File not found' });
}
// 检查是否是文件(不是目录)
const stats = fs.statSync(resolvedPath);
if (!stats.isFile()) {
return res.status(400).json({ error: 'Path is not a file' });
}
// 根据文件扩展名设置 Content-Type
const ext = path.extname(resolvedPath).toLowerCase();
let contentType = 'text/plain';
switch (ext) {
case '.js':
contentType = 'application/javascript; charset=utf-8';
break;
case '.vue':
contentType = 'text/javascript; charset=utf-8';
break;
case '.css':
contentType = 'text/css; charset=utf-8';
break;
case '.html':
contentType = 'text/html; charset=utf-8';
break;
case '.json':
contentType = 'application/json; charset=utf-8';
break;
case '.ts':
contentType = 'text/typescript; charset=utf-8';
break;
} // 设置 CORS 头部支持跨域访问
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET');
res.header('Access-Control-Allow-Headers', 'Content-Type');
// 读取并返回文件内容
const fileContent = fs.readFileSync(resolvedPath, 'utf-8');
res.setHeader('Content-Type', contentType);
res.send(fileContent);
console.log(`Plugin file served: ${libraryId}/${pluginName}/${filePath}`);
}
catch (error) {
console.error('Error serving plugin file:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
}
getRouter() {
return this.router;
}
async close() {
await Promise.all(this.libraryServices.map(service => service.close()));
this.libraryServices = [];
}
}
exports.HttpRouter = HttpRouter;
//# sourceMappingURL=HttpRouter.js.map