Skip to main content
Glama

Office MCP Server

by walkingzzzy
fileController.ts10.6 kB
import { Request, Response } from 'express'; import { ApiResponse, FileUploadInfo, DocumentDiff, DocumentSession } from '../types'; import logger from '../utils/logger'; import path from 'path'; import fs from 'fs'; import documentService from '../services/DocumentService'; import chunkService from '../services/ChunkService'; /** * 处理文件上传 */ export const uploadFile = async (req: Request, res: Response) => { try { if (!req.file) { const response: ApiResponse = { success: false, error: '没有上传文件', message: '请求参数错误', }; return res.status(400).json(response); } const file = req.file; const fileInfo: FileUploadInfo = { filename: file.filename, originalName: file.originalname, mimetype: file.mimetype, size: file.size, path: file.path, }; logger.info('文件上传成功', fileInfo); const response: ApiResponse = { success: true, data: fileInfo, message: '文件上传成功', }; res.json(response); } catch (error: any) { logger.error('文件上传失败', error); const response: ApiResponse = { success: false, error: error.message, message: '文件上传失败', }; res.status(500).json(response); } }; /** * 下载文件 */ export const downloadFile = async (req: Request, res: Response) => { try { const { filename } = req.params; if (!filename) { const response: ApiResponse = { success: false, error: '缺少filename参数', message: '请求参数错误', }; return res.status(400).json(response); } const filePath = path.join(process.cwd(), 'temp', filename); // 检查文件是否存在 if (!fs.existsSync(filePath)) { const response: ApiResponse = { success: false, error: '文件不存在', message: '文件未找到', }; return res.status(404).json(response); } logger.info(`下载文件: ${filename}`); res.download(filePath, (err) => { if (err) { logger.error('文件下载失败', err); if (!res.headersSent) { const response: ApiResponse = { success: false, error: err.message, message: '文件下载失败', }; res.status(500).json(response); } } }); } catch (error: any) { logger.error('文件下载失败', error); const response: ApiResponse = { success: false, error: error.message, message: '文件下载失败', }; res.status(500).json(response); } }; /** * 删除文件 */ export const deleteFile = async (req: Request, res: Response) => { try { const { filename } = req.params; if (!filename) { const response: ApiResponse = { success: false, error: '缺少filename参数', message: '请求参数错误', }; return res.status(400).json(response); } const filePath = path.join(process.cwd(), 'temp', filename); // 检查文件是否存在 if (!fs.existsSync(filePath)) { const response: ApiResponse = { success: false, error: '文件不存在', message: '文件未找到', }; return res.status(404).json(response); } // 删除文件 fs.unlinkSync(filePath); logger.info(`删除文件: ${filename}`); const response: ApiResponse = { success: true, message: '文件删除成功', }; res.json(response); } catch (error: any) { logger.error('文件删除失败', error); const response: ApiResponse = { success: false, error: error.message, message: '文件删除失败', }; res.status(500).json(response); } }; /** * 创建文档会话 */ export const createSession = async (req: Request, res: Response) => { try { const { fileId } = req.body; if (!fileId) { const response: ApiResponse = { success: false, error: '缺少fileId参数', message: '请求参数错误', }; return res.status(400).json(response); } if (!documentService.fileExists(fileId)) { const response: ApiResponse = { success: false, error: '文件不存在', message: '文件未找到', }; return res.status(404).json(response); } const session = documentService.createSession(fileId); const response: ApiResponse<DocumentSession> = { success: true, data: session, message: '会话创建成功', }; res.json(response); } catch (error: any) { logger.error('创建会话失败', error); const response: ApiResponse = { success: false, error: error.message, message: '创建会话失败', }; res.status(500).json(response); } }; /** * 获取文档会话 */ export const getSession = async (req: Request, res: Response) => { try { const { sessionId } = req.params; const session = documentService.getSession(sessionId); if (!session) { const response: ApiResponse = { success: false, error: '会话不存在', message: '会话未找到', }; return res.status(404).json(response); } const response: ApiResponse<DocumentSession> = { success: true, data: session, message: '获取会话成功', }; res.json(response); } catch (error: any) { logger.error('获取会话失败', error); const response: ApiResponse = { success: false, error: error.message, message: '获取会话失败', }; res.status(500).json(response); } }; /** * 计算文档差异 */ export const calculateDiff = async (req: Request, res: Response) => { try { const { originalFileId, modifiedFileId } = req.body; if (!originalFileId || !modifiedFileId) { const response: ApiResponse = { success: false, error: '缺少文件ID参数', message: '请求参数错误', }; return res.status(400).json(response); } const originalPath = documentService.getFilePath(originalFileId); const modifiedPath = documentService.getFilePath(modifiedFileId); if (!fs.existsSync(originalPath) || !fs.existsSync(modifiedPath)) { const response: ApiResponse = { success: false, error: '文件不存在', message: '文件未找到', }; return res.status(404).json(response); } const diff = await documentService.calculateDiff(originalPath, modifiedPath); const response: ApiResponse<DocumentDiff> = { success: true, data: diff, message: '差异计算成功', }; res.json(response); } catch (error: any) { logger.error('计算差异失败', error); const response: ApiResponse = { success: false, error: error.message, message: '计算差异失败', }; res.status(500).json(response); } }; /** * 分片上传 */ export const uploadChunk = async (req: Request, res: Response) => { try { const { fileId, chunkIndex, totalChunks } = req.body; const chunkData = req.file?.buffer; if (!fileId || chunkIndex === undefined || !totalChunks || !chunkData) { const response: ApiResponse = { success: false, error: '缺少必要参数', message: '请求参数错误', }; return res.status(400).json(response); } const success = chunkService.receiveChunk( fileId, parseInt(chunkIndex), parseInt(totalChunks), chunkData ); if (!success) { const response: ApiResponse = { success: false, error: '分片上传失败', message: '分片处理失败', }; return res.status(500).json(response); } const progress = chunkService.getProgress(fileId); const response: ApiResponse = { success: true, data: progress, message: '分片上传成功', }; res.json(response); } catch (error: any) { logger.error('分片上传失败', error); const response: ApiResponse = { success: false, error: error.message, message: '分片上传失败', }; res.status(500).json(response); } }; /** * 合并分片 */ export const mergeChunks = async (req: Request, res: Response) => { try { const { fileId } = req.body; if (!fileId) { const response: ApiResponse = { success: false, error: '缺少fileId参数', message: '请求参数错误', }; return res.status(400).json(response); } if (!chunkService.isFileComplete(fileId)) { const response: ApiResponse = { success: false, error: '文件不完整', message: '部分分片缺失', }; return res.status(400).json(response); } const filePath = await chunkService.mergeChunks(fileId); chunkService.clearChunks(fileId); const response: ApiResponse = { success: true, data: { filePath, fileId }, message: '文件合并成功', }; res.json(response); } catch (error: any) { logger.error('合并分片失败', error); const response: ApiResponse = { success: false, error: error.message, message: '合并分片失败', }; res.status(500).json(response); } }; /** * 下载分片 */ export const downloadChunk = async (req: Request, res: Response) => { try { const { fileId, chunkIndex } = req.params; if (!fileId || chunkIndex === undefined) { const response: ApiResponse = { success: false, error: '缺少参数', message: '请求参数错误', }; return res.status(400).json(response); } const chunk = chunkService.getChunk(fileId, parseInt(chunkIndex)); if (!chunk) { const response: ApiResponse = { success: false, error: '分片不存在', message: '分片未找到', }; return res.status(404).json(response); } res.set({ 'Content-Type': 'application/octet-stream', 'Content-Length': chunk.size.toString(), 'X-Chunk-Index': chunk.chunkIndex.toString(), 'X-Total-Chunks': chunk.totalChunks.toString(), }); res.send(chunk.data); } catch (error: any) { logger.error('下载分片失败', error); const response: ApiResponse = { success: false, error: error.message, message: '下载分片失败', }; res.status(500).json(response); } };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/walkingzzzy/office-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server