mirror of
https://github.com/kmc7468/arkvault.git
synced 2026-02-03 23:56:53 +00:00
Scheduler 클래스의 스케쥴링 로직 개선
This commit is contained in:
@@ -196,77 +196,74 @@ export const uploadFile = async (
|
||||
});
|
||||
const state = uploadingFiles.at(-1)!;
|
||||
|
||||
return await scheduler.schedule(
|
||||
async () => file.size,
|
||||
async () => {
|
||||
state.status = "encryption-pending";
|
||||
return await scheduler.schedule(file.size, async () => {
|
||||
state.status = "encryption-pending";
|
||||
|
||||
try {
|
||||
const { fileBuffer, fileSigned } = await requestDuplicateFileScan(
|
||||
file,
|
||||
hmacSecret,
|
||||
onDuplicate,
|
||||
);
|
||||
if (!fileBuffer || !fileSigned) {
|
||||
state.status = "canceled";
|
||||
uploadingFiles = uploadingFiles.filter((file) => file !== state);
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
const { fileBuffer, fileSigned } = await requestDuplicateFileScan(
|
||||
file,
|
||||
hmacSecret,
|
||||
onDuplicate,
|
||||
);
|
||||
if (!fileBuffer || !fileSigned) {
|
||||
state.status = "canceled";
|
||||
uploadingFiles = uploadingFiles.filter((file) => file !== state);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const {
|
||||
dataKeyWrapped,
|
||||
dataKeyVersion,
|
||||
fileType,
|
||||
fileEncrypted,
|
||||
fileEncryptedHash,
|
||||
nameEncrypted,
|
||||
createdAtEncrypted,
|
||||
lastModifiedAtEncrypted,
|
||||
thumbnail,
|
||||
} = await encryptFile(state, file, fileBuffer, masterKey);
|
||||
const {
|
||||
dataKeyWrapped,
|
||||
dataKeyVersion,
|
||||
fileType,
|
||||
fileEncrypted,
|
||||
fileEncryptedHash,
|
||||
nameEncrypted,
|
||||
createdAtEncrypted,
|
||||
lastModifiedAtEncrypted,
|
||||
thumbnail,
|
||||
} = await encryptFile(state, file, fileBuffer, masterKey);
|
||||
|
||||
const form = new FormData();
|
||||
form.set(
|
||||
const form = new FormData();
|
||||
form.set(
|
||||
"metadata",
|
||||
JSON.stringify({
|
||||
parent: parentId,
|
||||
mekVersion: masterKey.version,
|
||||
dek: dataKeyWrapped,
|
||||
dekVersion: dataKeyVersion.toISOString(),
|
||||
hskVersion: hmacSecret.version,
|
||||
contentHmac: fileSigned,
|
||||
contentType: fileType,
|
||||
contentIv: fileEncrypted.iv,
|
||||
name: nameEncrypted.ciphertext,
|
||||
nameIv: nameEncrypted.iv,
|
||||
createdAt: createdAtEncrypted?.ciphertext,
|
||||
createdAtIv: createdAtEncrypted?.iv,
|
||||
lastModifiedAt: lastModifiedAtEncrypted.ciphertext,
|
||||
lastModifiedAtIv: lastModifiedAtEncrypted.iv,
|
||||
} satisfies FileUploadRequest),
|
||||
);
|
||||
form.set("content", new Blob([fileEncrypted.ciphertext]));
|
||||
form.set("checksum", fileEncryptedHash);
|
||||
|
||||
let thumbnailForm = null;
|
||||
if (thumbnail) {
|
||||
thumbnailForm = new FormData();
|
||||
thumbnailForm.set(
|
||||
"metadata",
|
||||
JSON.stringify({
|
||||
parent: parentId,
|
||||
mekVersion: masterKey.version,
|
||||
dek: dataKeyWrapped,
|
||||
dekVersion: dataKeyVersion.toISOString(),
|
||||
hskVersion: hmacSecret.version,
|
||||
contentHmac: fileSigned,
|
||||
contentType: fileType,
|
||||
contentIv: fileEncrypted.iv,
|
||||
name: nameEncrypted.ciphertext,
|
||||
nameIv: nameEncrypted.iv,
|
||||
createdAt: createdAtEncrypted?.ciphertext,
|
||||
createdAtIv: createdAtEncrypted?.iv,
|
||||
lastModifiedAt: lastModifiedAtEncrypted.ciphertext,
|
||||
lastModifiedAtIv: lastModifiedAtEncrypted.iv,
|
||||
} satisfies FileUploadRequest),
|
||||
contentIv: thumbnail.iv,
|
||||
} satisfies FileThumbnailUploadRequest),
|
||||
);
|
||||
form.set("content", new Blob([fileEncrypted.ciphertext]));
|
||||
form.set("checksum", fileEncryptedHash);
|
||||
|
||||
let thumbnailForm = null;
|
||||
if (thumbnail) {
|
||||
thumbnailForm = new FormData();
|
||||
thumbnailForm.set(
|
||||
"metadata",
|
||||
JSON.stringify({
|
||||
dekVersion: dataKeyVersion.toISOString(),
|
||||
contentIv: thumbnail.iv,
|
||||
} satisfies FileThumbnailUploadRequest),
|
||||
);
|
||||
thumbnailForm.set("content", new Blob([thumbnail.ciphertext]));
|
||||
}
|
||||
|
||||
const { fileId } = await requestFileUpload(state, form, thumbnailForm);
|
||||
return { fileId, fileBuffer, thumbnailBuffer: thumbnail?.plaintext };
|
||||
} catch (e) {
|
||||
state.status = "error";
|
||||
throw e;
|
||||
thumbnailForm.set("content", new Blob([thumbnail.ciphertext]));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const { fileId } = await requestFileUpload(state, form, thumbnailForm);
|
||||
return { fileId, fileBuffer, thumbnailBuffer: thumbnail?.plaintext };
|
||||
} catch (e) {
|
||||
state.status = "error";
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,39 +1,46 @@
|
||||
export class Scheduler<T = void> {
|
||||
private tasks = 0;
|
||||
private isEstimating = false;
|
||||
private memoryUsage = 0;
|
||||
private queue: (() => void)[] = [];
|
||||
|
||||
constructor(public memoryLimit = 100 * 1024 * 1024 /* 100 MiB */) {}
|
||||
constructor(public readonly memoryLimit = 100 * 1024 * 1024 /* 100 MiB */) {}
|
||||
|
||||
private next() {
|
||||
if (this.memoryUsage < this.memoryLimit) {
|
||||
this.queue.shift()?.();
|
||||
if (!this.isEstimating && this.memoryUsage < this.memoryLimit) {
|
||||
const resolve = this.queue.shift();
|
||||
if (resolve) {
|
||||
this.isEstimating = true;
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async schedule(estimateMemoryUsage: () => Promise<number>, task: () => Promise<T>) {
|
||||
if (this.tasks++ > 0) {
|
||||
async schedule(
|
||||
estimateMemoryUsage: number | (() => number | Promise<number>),
|
||||
task: () => Promise<T>,
|
||||
) {
|
||||
if (this.isEstimating || this.memoryUsage >= this.memoryLimit) {
|
||||
await new Promise<void>((resolve) => {
|
||||
this.queue.push(resolve);
|
||||
});
|
||||
}
|
||||
|
||||
while (this.memoryUsage >= this.memoryLimit) {
|
||||
await new Promise<void>((resolve) => {
|
||||
this.queue.unshift(resolve);
|
||||
});
|
||||
} else {
|
||||
this.isEstimating = true;
|
||||
}
|
||||
|
||||
let taskMemoryUsage = 0;
|
||||
|
||||
try {
|
||||
taskMemoryUsage = await estimateMemoryUsage();
|
||||
taskMemoryUsage =
|
||||
typeof estimateMemoryUsage === "number" ? estimateMemoryUsage : await estimateMemoryUsage();
|
||||
this.memoryUsage += taskMemoryUsage;
|
||||
} finally {
|
||||
this.isEstimating = false;
|
||||
this.next();
|
||||
}
|
||||
|
||||
try {
|
||||
return await task();
|
||||
} finally {
|
||||
this.tasks--;
|
||||
this.memoryUsage -= taskMemoryUsage;
|
||||
this.next();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user