ionian/packages/server/src/util/zipwrap.ts
2024-03-29 02:14:53 +09:00

59 lines
1.6 KiB
TypeScript

import { type FileHandle, open } from "node:fs/promises";
import { orderBy } from "natural-orderby";
import { ZipReader, Reader, type Entry } from "@zip.js/zip.js";
class FileReader extends Reader<FileHandle> {
private fd: FileHandle;
private offset: number;
constructor(fd: FileHandle) {
super(fd);
this.fd = fd;
this.offset = 0;
}
async init(): Promise<void> {
this.offset = 0;
this.size = (await this.fd.stat()).size;
}
close(): void {
this.fd.close();
}
async readUint8Array(index: number, length: number): Promise<Uint8Array> {
const buffer = new Uint8Array(length);
const buf = await this.fd.read(buffer, 0, length, index);
if (buf.bytesRead !== length) {
console.error(`read error: ${buf.bytesRead} !== ${length}`);
throw new Error("read error");
}
return buffer;
}
}
export async function readZip(path: string): Promise<{
reader: ZipReader<FileHandle>
handle: FileHandle
}> {
const fd = await open(path);
const reader = new ZipReader(new FileReader(fd), {
useCompressionStream: true,
preventClose: false,
});
return { reader, handle: fd };
}
export async function entriesByNaturalOrder(zip: ZipReader<FileHandle>) {
// console.log(zip);
const entries = await zip.getEntries();
// console.log(entries.map((v) => v.filename));
const ret = orderBy(entries, (v) => v.filename);
return ret;
}
export async function createReadableStreamFromZip(_zip: ZipReader<FileHandle>, entry: Entry): Promise<ReadableStream> {
if (entry.getData === undefined) {
throw new Error("entry.getData is undefined");
}
const stream = new TransformStream<Uint8Array, Uint8Array>();
entry.getData(stream.writable);
return stream.readable;
}