diff --git a/src/modules/fm-manager/proxy/ai-proxy.ts b/src/modules/fm-manager/proxy/ai-proxy.ts index 4cec84d..fc2e7a8 100644 --- a/src/modules/fm-manager/proxy/ai-proxy.ts +++ b/src/modules/fm-manager/proxy/ai-proxy.ts @@ -54,6 +54,14 @@ export const getFileList = async (list: any, opts?: { objectName: string; app: s }); }; // import { logger } from '@/module/logger.ts'; +/** + * GET 处理 AI 代理请求 + * 1. 如果是目录请求,返回目录列表 + * 2. 如果是文件请求,返回文件流 + * + * 如果是 stat + * 只返回对应的 stat 信息 +*/ const getAiProxy = async (req: IncomingMessage, res: ServerResponse, opts: ProxyOptions) => { const { createNotFoundPage } = opts; const _u = new URL(req.url, 'http://localhost'); @@ -63,6 +71,7 @@ const getAiProxy = async (req: IncomingMessage, res: ServerResponse, opts: Proxy const hash = params.get('hash'); let dir = !!params.get('dir'); const recursive = !!params.get('recursive'); + const showStat = !!params.get('stat'); const { objectName, app, owner, loginUser, isOwner } = await getObjectName(req); if (!dir && _u.pathname.endsWith('/')) { dir = true; // 如果是目录请求,强制设置为true @@ -103,6 +112,19 @@ const getAiProxy = async (req: IncomingMessage, res: ServerResponse, opts: Proxy logger.info('no permission', checkPermission, loginUser, owner); return createNotFoundPage('no permission'); } + if (showStat) { + res.writeHead(200, { 'content-type': 'application/json' }); + res.end( + JSON.stringify({ + code: 200, + data: { + ...stat, + metaData: filterKeys(stat.metaData, ['etag', 'size']), + }, + }), + ); + return true; + } if (hash && stat.etag === hash) { res.writeHead(304); // not modified res.end('not modified'); @@ -295,6 +317,48 @@ export const renameProxy = async (req: IncomingMessage, res: ServerResponse, opt } }; +export const updateMetadataProxy = async (req: IncomingMessage, res: ServerResponse, opts: ProxyOptions) => { + const { objectName, isOwner } = await getObjectName(req); + let oss = opts.oss; + if (!isOwner) { + return opts?.createNotFoundPage?.('no permission'); + } + const end = (data: any, message?: string, code = 200) => { + res.writeHead(code, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ code: code, data: data, message: message || 'success' })); + }; + const _u = new URL(req.url, 'http://localhost'); + const params = _u.searchParams; + const metaParam = params.get('meta'); + if (!metaParam) { + return end({ success: false }, 'meta parameter required', 400); + } + const meta = parseSearchValue(metaParam, { decode: true }); + try { + const stat = await oss.statObject(objectName); + if (!stat) { + return end({ success: false }, 'object not found', 404); + } + const newMeta = { + "app-source": "user-app", + ...meta, + }; + console.log('update metadata', objectName, newMeta); + // 过滤掉包含无效字符的 key(S3 元数据头不支持某些字符) + const filteredMeta: Record = {}; + for (const [key, value] of Object.entries(newMeta)) { + if (/^[\w\-]+$/.test(key)) { + filteredMeta[key] = String(value); + } + } + await oss.replaceObject(objectName, filteredMeta); + end({ success: true, objectName, meta }, 'update metadata success', 200); + } catch (error) { + logger.error('updateMetadataProxy error', error); + end({ success: false, error }, 'update metadata failed', 500); + } +}; + export type ProxyOptions = { createNotFoundPage: (msg?: string) => any; oss?: OssBase; @@ -303,8 +367,8 @@ export const aiProxy = async (req: IncomingMessage, res: ServerResponse, opts: P if (!opts.oss) { opts.oss = oss; } + const searchParams = new URL(req.url || '', 'http://localhost').searchParams; if (req.method === 'POST') { - const searchParams = new URL(req.url || '', 'http://localhost').searchParams; const chunk = searchParams.get('chunk'); const chunked = searchParams.get('chunked'); if (chunk !== null || chunked !== null) { @@ -316,6 +380,10 @@ export const aiProxy = async (req: IncomingMessage, res: ServerResponse, opts: P return deleteProxy(req, res, opts); } if (req.method === 'PUT') { + const meta = searchParams.get('meta'); + if (meta) { + return updateMetadataProxy(req, res, opts); + } return renameProxy(req, res, opts); } diff --git a/src/routes-simple/page-proxy.ts b/src/routes-simple/page-proxy.ts index 0922cf3..8627d20 100644 --- a/src/routes-simple/page-proxy.ts +++ b/src/routes-simple/page-proxy.ts @@ -298,6 +298,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR username: loginUser?.tokenUser?.username || '', password: password, }); + console.log('checkPermission', checkPermission, 'loginUser:', loginUser, password) if (!checkPermission.success) { return createNotFoundPage('no permission'); }