UNPKG

mira-app-core

Version:

Core library for Mira TypeScript project - provides base functionality without auto-execution

209 lines 9.49 kB
"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.FileRoutes = void 0; const express_1 = require("express"); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const multer_1 = __importDefault(require("multer")); class FileRoutes { constructor(backend) { this.backend = backend; this.router = (0, express_1.Router)(); this.setupUpload(); this.setupRoutes(); } setupUpload() { // 配置multer文件上传 this.upload = (0, multer_1.default)({ storage: multer_1.default.diskStorage({ destination: (req, file, cb) => { const tempDir = path.join(this.backend.dataPath, 'temp'); if (!fs.existsSync(tempDir)) { fs.mkdirSync(tempDir, { recursive: true }); } cb(null, tempDir); }, filename: (req, file, cb) => { // 处理中文名,确保文件名为utf8编码 const originalName = Buffer.from(file.originalname, 'latin1').toString('utf8'); const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9); cb(null, uniqueSuffix + path.extname(originalName)); } }) }); } setupRoutes() { // 上传文件到资源库 this.router.post('/upload', this.upload.array('files'), async (req, res) => { const { libraryId, sourcePath } = req.body; // sourcePath是用户的本地文件位置,用来验证是否上传成功 const clientId = req.body.clientId || null; const fields = req.body.fields ? JSON.parse(req.body.fields) : null; const payload = req.body.payload ? JSON.parse(req.body.payload) : null; const obj = this.backend.libraries.get(libraryId); if (!obj) return res.status(404).send('Library not found'); // 解析上传的文件 const files = req.files; if (!files || !files.length) return res.status(400).send('No files uploaded.'); try { const results = []; for (const file of files) { try { // 生成唯一文件名并保存文件 const originalName = Buffer.from(file.originalname, 'latin1').toString('utf8'); const { tags, folder_id } = payload.data || {}; const fileData = { name: req.body.name || originalName, tags: JSON.stringify(tags || []), folder_id: folder_id || null, }; const result = await obj.libraryService.createFileFromPath(file.path, fileData, { importType: 'move' }); // 使用move上传完成后自动删除临时文件 results.push({ success: true, file: file.path, result }); // 发布公告 // 发送WebSocket事件(如果可用) if (this.backend.webSocketServer) { this.backend.webSocketServer.broadcastPluginEvent('file::created', { message: { type: 'file', action: 'create', fields, payload }, result, libraryId }); if (clientId) { const ws = this.backend.webSocketServer?.getWsClientById(libraryId, clientId); ws && this.backend.webSocketServer?.sendToWebsocket(ws, { eventName: 'file::uploaded', data: { path: sourcePath } }); this.backend.webSocketServer?.broadcastLibraryEvent(libraryId, 'file::created', { ...result, libraryId }); } } } catch (error) { console.error(`Error processing file ${file.originalname}:`, error); results.push({ success: false, file: file.path, error: error instanceof Error ? error.message : String(error) }); } } res.send({ results }); } catch (error) { console.error('Error uploading files:', error); res.status(500).send('Internal server error while processing the upload.'); } }); // 获取文件缩略图 this.router.get('/thumb/:libraryId/:id', async (req, res) => { try { const ret = await this.parseLibraryItem(req, res); if (ret) { const thumbPath = await ret.library.getItemThumbPath(ret.item, { isNetworkImage: false }); if (!fs.existsSync(thumbPath)) return res.status(404).send('Thumbnail not found'); res.setHeader('Content-Type', 'image/png'); fs.createReadStream(thumbPath).pipe(res); } } catch (err) { console.error('Error serving thumbnail:', err); res.status(500).send('Internal server error'); } }); // 获取文件内容 this.router.get('/file/:libraryId/:id', async (req, res) => { const ret = await this.parseLibraryItem(req, res); if (ret) { const filePath = await ret.library.getItemFilePath(ret.item); if (!filePath || !fs.existsSync(filePath)) { return res.status(404).send('File not found'); } const fileExt = path.extname(filePath).toLowerCase(); const contentType = this.getContentType(fileExt); res.setHeader('Content-Type', contentType); fs.createReadStream(filePath).pipe(res); } }); } async parseLibraryItem(req, res) { const { libraryId, id } = req.params; const obj = this.backend.libraries.get(libraryId); if (!obj) { res.status(404).send('Library not found'); return; } const item = await obj.libraryService.getFile(parseInt(id)); if (!item) { res.status(404).send('Item not found'); return; } return { library: obj.libraryService, item }; } getContentType(ext) { const mimeTypes = { '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.pdf': 'application/pdf', '.txt': 'text/plain', '.html': 'text/html', '.json': 'application/json', '.mp4': 'video/mp4', '.mp3': 'audio/mpeg', '.zip': 'application/zip', '.doc': 'application/msword', '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', '.xls': 'application/vnd.ms-excel', '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', '.ppt': 'application/vnd.ms-powerpoint', '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation' }; return mimeTypes[ext] || 'application/octet-stream'; } getRouter() { return this.router; } } exports.FileRoutes = FileRoutes; //# sourceMappingURL=FileRoutes.js.map