Skip to content

Commit

Permalink
feat: add zip upload support
Browse files Browse the repository at this point in the history
  • Loading branch information
darlanalves authored Mar 11, 2024
1 parent 6c43d5d commit 729a083
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 3 deletions.
15 changes: 13 additions & 2 deletions filebin.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,28 @@ export async function listFiles(bin) {
* @returns {Promise<ArrayBuffer>} zip file
*/
export async function downloadZip(bin) {
const req = await fetch(getDownloadUrl(bin), g);
const req = await fetch(getZipUrl(bin), g);

return req.ok ? await req : Promise.reject(new Error('Failed to generate a zip for this bin'));
}

/**
* @param {string} bin
* @param {BodyInit} zipContent
* @returns {Promise<ArrayBuffer>} zip file
*/
export async function uploadZip(bin, zipContent) {
const req = await fetch(getZipUrl(bin), {...p, body: zipContent });

return req.ok ? await req.json() : Promise.reject(new Error('Failed to import a zip in this bin'));
}

/**
* Returns an URL pointing to a zip with the entire bin
* @param {string} bin
* @returns {string} url
*/
export function getDownloadUrl(bin) {
export function getZipUrl(bin) {
return u(`/zip/${bin}.zip`).toString();
}

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@
"@cloud-cli/typescript-config": "^1.0.0",
"@types/node": "^20.10.6",
"@types/yazl": "^2.4.5",
"@types/yauzl": "^2.10.3",
"typescript": "^5.3.3"
},
"dependencies": {
"micro-router": "^1.0.1",
"yazl": "^2.5.1"
"yazl": "^2.5.1",
"yauzl": "^3.1.2"
}
}
72 changes: 72 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { join } from 'node:path';
import { writeFile, readFile, mkdir, readdir, stat, rm, unlink } from 'node:fs/promises';
import router from 'micro-router';
import * as yazl from 'yazl';
import * as yauzl from 'yauzl';

const rootDir = process.env.ROOT_DIR;
export type Options = { port?: Number };
Expand Down Expand Up @@ -209,6 +210,76 @@ async function onGetUI(_req, res) {
createReadStream('./index.html').pipe(res);
}

async function onUploadZip(req, res, args) {
const { binId = '' } = args;
const binPath = join(rootDir, binId);

if (!(binId && existsSync(binPath))) {
return notFound(res);
}

const uid = randomUUID();
const tmpFile = join(binPath, uid);

try {
await new Promise((resolve, reject) => {
req.on('end', () => {
const zipOptions = {
strictFileNames:true,
lazyEntries: true,
decodeStrings: true
};

yauzl.open(tmpFile, zipOptions, (err, zip) => {
if (err) {
return reject(err);
}

zip.on('error', (err) => reject(err));

zip.once('end', () => {
zip.close();
resolve(true);
});

zip.on('entry', (entry) => {
if (entry.fileName.endsWith('/')) {
zip.readEntry();
return;
}

zip.openReadStream(entry, async (err, readStream) => {
if (err) {
return reject(err);
}

readStream.on("end", () => zip.readEntry());

const fileId = randomUUID();
const meta = { name: entry.fileName };
const stream = createWriteStream(join(binPath, fileId));

await writeFile(join(binPath, fileId + '.meta'), JSON.stringify(meta));
readStream.pipe(stream);
});
});

zip.readEntry();
});
});

req.pipe(createWriteStream(tmpFile));
});

res.writeHead(202).end(`{"binId": "${binId}"}`);
} catch (error) {
console.log(error);
res.writeHead(500).end();
} finally {
unlink(tmpFile);
}
}

async function onDownloadZip(_req, res, args) {
let { binId = '' } = args;
binId = binId.replace('.zip', '');
Expand Down Expand Up @@ -297,6 +368,7 @@ const match = router({
'GET /meta/:binId/:fileId': onReadMetadata,
'PUT /meta/:binId/:fileId': onWriteMetadata,
'GET /zip/:binId': onDownloadZip,
'POST /zip/:binId': onUploadZip,
});

export function start(options: Options = {}) {
Expand Down

0 comments on commit 729a083

Please sign in to comment.