mirror of
https://github.com/kmc7468/arkvault.git
synced 2026-11-04 08:10:28 +09:00
형식이 잘못된 세션 쿠키로 인해 서버 오류가 발생하던 문제와 업로드 중 오류가 무시되거나 무한히 대기하던 문제 등 버그 수정
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bb0328b39e
commit
9119c21881
11 files changed
+161
-77
No files matched your search
@@ -9,7 +9,11 @@ export const signMessageHmac = async (message: Blob, hmacSecret: CryptoKey) => {
|
||||
|
||||
return new Promise<Uint8Array>((resolve, reject) => {
|
||||
worker.onmessage = ({ data }: MessageEvent<ResultMessage>) => {
|
||||
resolve(data.result);
|
||||
if ("result" in data) {
|
||||
resolve(data.result);
|
||||
} else {
|
||||
reject(data.error);
|
||||
}
|
||||
worker.terminate();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import ExifReader from "exifreader";
|
||||
|
||||
const isInteger = (value: number | undefined): value is number => Number.isInteger(value);
|
||||
|
||||
export const extractExifDateTime = (fileBuffer: ArrayBuffer) => {
|
||||
const exif = ExifReader.load(fileBuffer);
|
||||
const dateTimeOriginal = exif["DateTimeOriginal"]?.description;
|
||||
@@ -11,7 +13,10 @@ export const extractExifDateTime = (fileBuffer: ArrayBuffer) => {
|
||||
|
||||
const [year, month, day] = date.split(":").map(Number);
|
||||
const [hour, minute, second] = time.split(":").map(Number);
|
||||
if (!year || !month || !day || !hour || !minute || !second) return undefined;
|
||||
// Hours, minutes, and seconds may be 0, so they are checked differently
|
||||
if (!year || !month || !day || !isInteger(hour) || !isInteger(minute) || !isInteger(second)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!offsetTimeOriginal) {
|
||||
// No timezone information.. Assume local timezone
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { sha256 } from "@noble/hashes/sha2.js";
|
||||
import axios from "axios";
|
||||
import pLimit from "p-limit";
|
||||
import { encodeToBase64, encryptChunk } from "#lib/shared/crypto/index.ts";
|
||||
import { CHUNK_SIZE, getChunkCount, getEncryptedSize } from "#lib/shared/format/index.ts";
|
||||
import { BoundedQueue } from "#lib/utils/concurrency/index.ts";
|
||||
@@ -70,7 +69,6 @@ export const uploadBlob = async (
|
||||
};
|
||||
|
||||
const queue = new BoundedQueue<EncryptedChunk>(maxQueueSize);
|
||||
let encryptionError: Error | null = null;
|
||||
|
||||
// Producer: encrypt chunks and push to queue
|
||||
const encryptionProducer = async () => {
|
||||
@@ -82,8 +80,6 @@ export const uploadBlob = async (
|
||||
hash.update(new Uint8Array(data));
|
||||
await queue.push({ index: i, data });
|
||||
}
|
||||
} catch (e) {
|
||||
encryptionError = e instanceof Error ? e : new Error(String(e));
|
||||
} finally {
|
||||
queue.close();
|
||||
}
|
||||
@@ -91,36 +87,43 @@ export const uploadBlob = async (
|
||||
|
||||
// Consumer: upload chunks from queue with concurrency limit
|
||||
const uploadConsumer = async () => {
|
||||
const limit = pLimit(networkConcurrency);
|
||||
const activeTasks = new Set<Promise<void>>();
|
||||
let failure: { reason: unknown } | undefined;
|
||||
|
||||
while (true) {
|
||||
const item = await queue.pop();
|
||||
if (item === null) break;
|
||||
if (encryptionError) throw encryptionError;
|
||||
try {
|
||||
while (!failure) {
|
||||
const item = await queue.pop();
|
||||
if (item === null) break;
|
||||
|
||||
const task = limit(async () => {
|
||||
try {
|
||||
await uploadEncryptedChunk(uploadId, item.index, item.data, onChunkProgress);
|
||||
} finally {
|
||||
// @ts-expect-error
|
||||
item.data = null;
|
||||
const task: Promise<void> = uploadEncryptedChunk(
|
||||
uploadId,
|
||||
item.index,
|
||||
item.data,
|
||||
onChunkProgress,
|
||||
)
|
||||
.catch((reason) => {
|
||||
failure ??= { reason };
|
||||
})
|
||||
.finally(() => activeTasks.delete(task));
|
||||
activeTasks.add(task);
|
||||
|
||||
if (activeTasks.size >= networkConcurrency) {
|
||||
await Promise.race(activeTasks);
|
||||
}
|
||||
});
|
||||
|
||||
activeTasks.add(task);
|
||||
task.finally(() => activeTasks.delete(task));
|
||||
|
||||
if (activeTasks.size >= networkConcurrency) {
|
||||
await Promise.race(activeTasks);
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(activeTasks);
|
||||
await Promise.all(activeTasks);
|
||||
if (failure) throw failure.reason;
|
||||
} finally {
|
||||
queue.close(); // Stops the producer if the upload failed
|
||||
}
|
||||
};
|
||||
|
||||
// Run producer and consumer concurrently
|
||||
await Promise.all([encryptionProducer(), uploadConsumer()]);
|
||||
const [encryption, upload] = await Promise.allSettled([encryptionProducer(), uploadConsumer()]);
|
||||
// The upload error takes precedence, as the producer fails due to the closed queue then
|
||||
if (upload.status === "rejected") throw upload.reason;
|
||||
if (encryption.status === "rejected") throw encryption.reason;
|
||||
|
||||
onProgress?.({ progress: 1, rate: speedMeter() });
|
||||
return { encContentHash: encodeToBase64(hash.digest()) };
|
||||
|
||||
Reference in new issue
Block a user