feat: complete TASK-WP2-05 generation submission

This commit is contained in:
suyx
2026-08-03 00:26:34 +08:00
parent 4551d73e76
commit c8643c080d
22 changed files with 2372 additions and 22 deletions
+99 -1
View File
@@ -113,6 +113,9 @@ function sniffMime(prefix: Buffer) {
return "image/png";
}
if (prefix.length >= 3 && prefix[0] === 0xff && prefix[1] === 0xd8 && prefix[2] === 0xff) return "image/jpeg";
if (prefix.length >= 12 && prefix.subarray(0, 4).toString("ascii") === "RIFF" && prefix.subarray(8, 12).toString("ascii") === "WEBP") {
return "image/webp";
}
return "application/octet-stream";
}
@@ -129,7 +132,7 @@ function listFiles(root: string): string[] {
export interface CommitStreamInput {
content: Readable;
expectedMimeType: "image/png" | "image/jpeg" | "application/octet-stream";
expectedMimeType: "image/png" | "image/jpeg" | "image/webp" | "application/octet-stream";
expectedSha256?: string;
failurePoint?: CommitFailurePoint;
fileKind: ManagedFileKind;
@@ -139,6 +142,20 @@ export interface CommitStreamInput {
projectedWriteBytes: number;
}
export interface StagedManagedFile {
bytes: number;
destinationPath: string;
fileId: string;
fileKind: ManagedFileKind;
mimeType: "image/png" | "image/jpeg" | "image/webp";
operationId: string;
ownerRef: string;
relativePath: string;
sha256: string;
stagingDirectory: string;
stagingPath: string;
}
export class ManagedStorage {
readonly dataRoot: string;
readonly databasePath: string;
@@ -479,6 +496,87 @@ export class ManagedStorage {
}
}
async stagePrivateImage(input: {
content: Readable;
expectedMimeType: "image/png" | "image/jpeg" | "image/webp";
fileName: string;
maximumBytes: number;
operationId: string;
ownerRef: string;
projectedWriteBytes: number;
}): Promise<StagedManagedFile> {
const fileId = randomUUID();
const destination = this.destination({
content: input.content,
expectedMimeType: input.expectedMimeType,
fileKind: "reference",
fileName: input.fileName,
operationId: input.operationId,
ownerRef: input.ownerRef,
projectedWriteBytes: input.projectedWriteBytes,
}, fileId);
if (!Number.isSafeInteger(input.maximumBytes) || input.maximumBytes <= 0) throw new Error("maximum_bytes_invalid");
this.reserve(input.operationId, input.projectedWriteBytes);
const stagingDirectory = resolvePathWithinRoot(this.dataRoot, `staging/${input.operationId}`);
const stagingPath = resolvePathWithinRoot(this.dataRoot, `staging/${input.operationId}/payload.tmp`);
try {
mkdirSync(stagingDirectory, { recursive: true });
const hash = createHash("sha256");
let byteSize = 0;
let prefix = Buffer.alloc(0);
const inspect = new Transform({
transform(chunk: Buffer | string, encoding, callback) {
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding);
byteSize += bytes.byteLength;
if (byteSize > input.maximumBytes) return callback(new Error("content_size_invalid"));
hash.update(bytes);
if (prefix.byteLength < 16) prefix = Buffer.concat([prefix, bytes.subarray(0, 16 - prefix.byteLength)]);
callback(null, bytes);
},
});
await pipeline(input.content, inspect, createWriteStream(stagingPath, { flags: "wx" }));
validatePositiveBytes(byteSize, "actual_write_bytes");
if (sniffMime(prefix) !== input.expectedMimeType) throw new Error("content_mime_invalid");
const state = this.getState();
const otherReservations = this.activeReservationBytes(input.operationId);
if (state.managed_content_bytes + otherReservations + byteSize > HARD_LIMIT_BYTES) {
throw new StorageCapacityError({ activeReservationBytes: otherReservations, managedContentBytes: state.managed_content_bytes, projectedWriteBytes: byteSize });
}
this.database.prepare("UPDATE storage_reservations SET projected_bytes = ? WHERE operation_id = ? AND status = 'active'")
.run(byteSize, input.operationId);
this.refreshState();
return {
bytes: byteSize,
destinationPath: destination.absolutePath,
fileId,
fileKind: "reference",
mimeType: input.expectedMimeType,
operationId: input.operationId,
ownerRef: input.ownerRef,
relativePath: destination.relativePath,
sha256: hash.digest("hex"),
stagingDirectory,
stagingPath,
};
} catch (error) {
rmSync(stagingDirectory, { force: true, recursive: true });
this.releaseReservation(input.operationId);
throw error;
}
}
moveStagedFile(file: StagedManagedFile) {
mkdirSync(dirname(file.destinationPath), { recursive: true });
renameSync(file.stagingPath, file.destinationPath);
rmSync(file.stagingDirectory, { force: true, recursive: true });
}
abandonStagedFile(file: StagedManagedFile) {
if (existsSync(file.destinationPath)) this.queueCompensation(file.relativePath, statSync(file.destinationPath).size);
else rmSync(file.stagingDirectory, { force: true, recursive: true });
this.releaseReservation(file.operationId);
}
async commitBufferFixture(fileKind: ManagedFileKind, fileName: string, bytes: Buffer) {
return this.commitStream({
content: Readable.from(bytes),