51 lines
1.8 KiB
TypeScript
51 lines
1.8 KiB
TypeScript
import type { ArtifactContentChunk, ArtifactDownloadReferenceResponse } from "../api/types";
|
|
|
|
export async function downloadArtifactReference(
|
|
reference: ArtifactDownloadReferenceResponse,
|
|
readContent: (artifactId: string, offset: number, limit?: number) => Promise<ArtifactContentChunk>,
|
|
onProgress?: (progress: number) => void
|
|
) {
|
|
const chunks: ArrayBuffer[] = [];
|
|
let offset = 0;
|
|
onProgress?.(0);
|
|
|
|
while (offset < reference.sizeBytes) {
|
|
const chunk = await readContent(reference.artifactId, offset, reference.chunkSizeBytes);
|
|
chunks.push(chunk.payload);
|
|
offset += chunk.payload.byteLength;
|
|
onProgress?.(Math.min(100, Math.round((offset / reference.sizeBytes) * 100)));
|
|
if (chunk.payload.byteLength === 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
openArtifactBlob(reference, chunks);
|
|
onProgress?.(100);
|
|
}
|
|
|
|
export function openArtifactBlob(reference: ArtifactDownloadReferenceResponse, chunks: ArrayBuffer[]) {
|
|
if (typeof document === "undefined" || typeof URL === "undefined") {
|
|
return;
|
|
}
|
|
const blob = new Blob(chunks, { type: reference.contentType });
|
|
const url = URL.createObjectURL(blob);
|
|
const anchor = document.createElement("a");
|
|
anchor.href = url;
|
|
anchor.download = safeArtifactFilename(reference.filename);
|
|
anchor.rel = "noopener";
|
|
document.body.append(anchor);
|
|
anchor.click();
|
|
anchor.remove();
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
export function safeArtifactFilename(filename: string): string {
|
|
const cleaned = filename.replace(/[\\/]/g, "").trim();
|
|
return cleaned || "artifact.bin";
|
|
}
|
|
|
|
export function safeArtifactError(error: unknown): string {
|
|
const message = error instanceof Error ? error.message : "制品传输失败";
|
|
return message.replace(/\/Users\/[^\s]+/g, "[path]").replace(/Bearer\s+[^\s]+/gi, "[token]").replace(/sk-[A-Za-z0-9_-]+/g, "[secret]");
|
|
}
|