/** * WOPI 协议 API 路由 * * 功能: * - CheckFileInfo: GET /api/collabora/wopi/files/{fileId} * - GetFile: GET /api/collabora/wopi/files/{fileId}/contents * - PutFile: POST /api/collabora/wopi/files/{fileId}/contents * * @encoding UTF-8 */ import { type LoaderFunctionArgs, type ActionFunctionArgs } from '@remix-run/node'; import { WopiService } from '../services/collabora.wopi.server'; const wopiService = new WopiService(); /** * GET 请求处理 * - 无 /contents 后缀 → CheckFileInfo * - 有 /contents 后缀 → GetFile */ export async function loader({ request, params }: LoaderFunctionArgs) { try { const url = new URL(request.url); const accessToken = url.searchParams.get('access_token'); if (!accessToken) { return new Response('访问令牌缺失', { status: 401 }); } // 获取文件 ID const fileId = params.fileId || ''; // 判断是否是 GetFile 请求(路径以 /contents 结尾) const isContentsRequest = url.pathname.endsWith('/contents'); if (isContentsRequest) { // GetFile: 返回文件内容 const { buffer, metadata } = await wopiService.getFile(fileId, accessToken); return new Response(buffer, { headers: { 'Content-Type': metadata.contentType, 'Content-Length': metadata.size.toString(), 'Content-Disposition': 'inline', }, }); } // CheckFileInfo: 返回文件元数据 const checkFileInfo = await wopiService.checkFileInfo(fileId, accessToken); // 注意:CheckFileInfo 必须返回纯 JSON,不能使用 Result.success() 包装 return Response.json(checkFileInfo); } catch (error) { console.error('WOPI GET 失败:', error); return new Response( error instanceof Error ? error.message : 'Internal server error', { status: 500 } ); } } /** * POST 请求处理 * - PutFile: 保存文件内容 */ export async function action({ request, params }: ActionFunctionArgs) { try { const url = new URL(request.url); const accessToken = url.searchParams.get('access_token'); if (!accessToken) { return new Response('访问令牌缺失', { status: 401 }); } const fileId = params.fileId || ''; // 判断是否是 PutFile 请求(路径以 /contents 结尾) const isContentsRequest = url.pathname.endsWith('/contents'); if (!isContentsRequest) { return new Response('PutFile 必须使用 /contents 路径', { status: 400 }); } // PutFile: 保存文件 const fileBuffer = await request.arrayBuffer(); await wopiService.putFile(fileId, accessToken, fileBuffer); return new Response(null, { status: 200 }); } catch (error) { console.error('WOPI POST 失败:', error); return new Response( error instanceof Error ? error.message : 'Internal server error', { status: 500 } ); } }