파일을 다운로드할 때 전체 파일을 메모리에 올리는 대신 서비스 워커에서 스트리밍으로 복호화하도록 변경

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
staticandClaude Opus 5.5 committed 2026-10-12 00:48:21 +09:00
1 parent 877cf9c42e
commit 3e52fa7a7c
29 files changed
+629 -467

No files matched your search

+1 -53
View File
@@ -4,6 +4,7 @@ import pLimit from "p-limit";
import { encodeToBase64, encryptChunk } from "#lib/shared/crypto/index.js";
import { CHUNK_SIZE, getChunkCount, getEncryptedSize } from "#lib/shared/format/index.js";
import { BoundedQueue } from "#lib/utils/concurrency/index.js";
import { createSpeedMeter } from "#lib/utils/speedMeter.js";
interface UploadStats {
progress: number;
@@ -15,59 +16,6 @@ interface EncryptedChunk {
data: ArrayBuffer;
}
const createSpeedMeter = (timeWindow = 3000, minInterval = 200, warmupPeriod = 500) => {
const samples: { t: number; b: number }[] = [];
let lastSpeed = 0;
let startTime: number | null = null;
return (bytesNow?: number) => {
if (bytesNow === undefined) return lastSpeed;
const now = performance.now();
// Initialize start time on first call
if (startTime === null) {
startTime = now;
}
// Check if enough time has passed since the last sample
const lastSample = samples[samples.length - 1];
if (lastSample && now - lastSample.t < minInterval) {
return lastSpeed;
}
samples.push({ t: now, b: bytesNow });
// Remove old samples outside the time window
const cutoff = now - timeWindow;
while (samples.length > 2 && samples[0]!.t < cutoff) samples.shift();
// Need at least 2 samples to calculate speed
if (samples.length < 2) {
return lastSpeed;
}
const first = samples[0]!;
const dt = now - first.t;
const db = bytesNow - first.b;
if (dt >= minInterval) {
const instantSpeed = (db / dt) * 1000;
// Apply EMA for smoother speed transitions
const alpha = 0.3;
const rawSpeed =
lastSpeed === 0 ? instantSpeed : alpha * instantSpeed + (1 - alpha) * lastSpeed;
// Apply warmup ramp to prevent initial overestimation
const elapsed = now - startTime;
const warmupWeight = Math.min(1, elapsed / warmupPeriod);
lastSpeed = rawSpeed * warmupWeight;
}
return lastSpeed;
};
};
const encryptChunkData = async (chunk: Blob, dataKey: CryptoKey): Promise<ArrayBuffer> => {
return await encryptChunk(await chunk.arrayBuffer(), dataKey);
};