import type { PlatformApiClient } from "../api/client"; import type { ServerFileDownloadResponse } from "../api/types"; export async function downloadServerFileResult(client: PlatformApiClient, result: ServerFileDownloadResponse): Promise { if (result.status !== "ready") { return result.reason ?? "文件读取任务已派发,完成后可再次下载。"; } if (result.content !== undefined) { saveBlob(new Blob([result.content], { type: result.contentType ?? "text/plain;charset=utf-8" }), result.filename || "server-file.txt"); return `下载已开始:${result.filename || result.key}`; } if (!result.artifact) { return "文件内容尚未可用。"; } const writer = await createFileWriter(result.filename || result.artifact.filename); let offset = 0; const chunkSize = Math.max(1, result.artifact.chunkSizeBytes || 1024 * 1024); try { while (offset < result.artifact.sizeBytes) { const chunk = await client.readArtifactContent(result.artifact.artifactId, offset, Math.min(chunkSize, result.artifact.sizeBytes - offset)); if (chunk.contentLength <= 0) throw new Error("文件下载返回空数据"); await writer.write(chunk.payload); offset += chunk.contentLength; } await writer.close(); } catch (error) { await writer.abort(); throw error; } return `下载已开始:${result.filename || result.artifact.filename}`; } interface FileWriter { write(data: ArrayBuffer): Promise; close(): Promise; abort(): Promise; } async function createFileWriter(filename: string): Promise { const picker = (window as Window & { showSaveFilePicker?: (options?: { suggestedName?: string }) => Promise<{ createWritable(): Promise }> }).showSaveFilePicker; if (picker) { const handle = await picker({ suggestedName: safeFilename(filename) }); const writable = await handle.createWritable(); return { write: async (data) => { await writable.write(data); }, close: async () => { await writable.close(); }, abort: async () => { await writable.abort(); } }; } const chunks: ArrayBuffer[] = []; return { write: async (data) => { chunks.push(data); }, close: async () => { saveBlob(new Blob(chunks, { type: "application/octet-stream" }), safeFilename(filename)); }, abort: async () => { chunks.length = 0; } }; } function saveBlob(blob: Blob, filename: string) { const url = URL.createObjectURL(blob); const anchor = document.createElement("a"); anchor.href = url; anchor.download = safeFilename(filename); document.body.appendChild(anchor); anchor.click(); anchor.remove(); window.setTimeout(() => URL.revokeObjectURL(url), 1000); } function safeFilename(filename: string): string { const cleaned = filename.replace(/[\\/:*?"<>|]+/g, "-").trim(); return cleaned || "server-file.txt"; }