mirror of
https://github.com/bewcloud/bewcloud.git
synced 2026-03-11 08:54:49 +00:00
Replace zip with JSZip
This commit is contained in:
parent
ed88b927d3
commit
efb9f62a37
2 changed files with 47 additions and 42 deletions
|
|
@ -50,6 +50,7 @@
|
||||||
"@std/path": "jsr:@std/path@1.1.2",
|
"@std/path": "jsr:@std/path@1.1.2",
|
||||||
|
|
||||||
"chart.js": "npm:chart.js@4.5.0",
|
"chart.js": "npm:chart.js@4.5.0",
|
||||||
|
"jszip": "npm:jszip@3.10.1",
|
||||||
"mrmime": "npm:mrmime@2.0.1",
|
"mrmime": "npm:mrmime@2.0.1",
|
||||||
"nodemailer": "npm:nodemailer@7.0.6",
|
"nodemailer": "npm:nodemailer@7.0.6",
|
||||||
"openid-client": "npm:openid-client@6.8.0",
|
"openid-client": "npm:openid-client@6.8.0",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { Handlers } from 'fresh/server.ts';
|
import { Handlers } from 'fresh/server.ts';
|
||||||
import { join } from '@std/path';
|
import { join } from '@std/path';
|
||||||
|
import JSZip from 'jszip';
|
||||||
|
|
||||||
import { FreshContextState } from '/lib/types.ts';
|
import { FreshContextState } from '/lib/types.ts';
|
||||||
import { AppConfig } from '/lib/config.ts';
|
import { AppConfig } from '/lib/config.ts';
|
||||||
|
|
@ -39,55 +40,58 @@ export const handler: Handlers<Data, FreshContextState> = {
|
||||||
const userRootPath = join(filesRootPath, context.state.user.id);
|
const userRootPath = join(filesRootPath, context.state.user.id);
|
||||||
const fullDirectoryPath = join(userRootPath, directoryPath);
|
const fullDirectoryPath = join(userRootPath, directoryPath);
|
||||||
|
|
||||||
// Use the zip command to create the archive with streaming
|
// Create a JSZip instance
|
||||||
const zipProcess = new Deno.Command('zip', {
|
const zip = new JSZip();
|
||||||
args: ['-r', '-', '.'],
|
|
||||||
cwd: fullDirectoryPath,
|
|
||||||
stdout: 'piped',
|
|
||||||
stderr: 'piped',
|
|
||||||
}).spawn();
|
|
||||||
|
|
||||||
// Get the zip stream from the process stdout
|
// Recursively add files to the zip
|
||||||
const zipStream = zipProcess.stdout;
|
async function addFilesToZip(currentPath: string, zipFolder: JSZip) {
|
||||||
|
for await (const entry of Deno.readDir(currentPath)) {
|
||||||
|
const entryPath = join(currentPath, entry.name);
|
||||||
|
|
||||||
// Monitor process errors and log them (stream will end on error)
|
if (entry.isFile) {
|
||||||
zipProcess.status.then(async (status) => {
|
// Read file and add to zip
|
||||||
if (status.code !== 0) {
|
const fileContent = await Deno.readFile(entryPath);
|
||||||
console.error('Zip command failed with code:', status.code);
|
zipFolder.file(entry.name, fileContent);
|
||||||
// Read and log stderr for error details
|
} else if (entry.isDirectory) {
|
||||||
try {
|
// Create a folder in the zip and recursively add its contents
|
||||||
const stderrReader = zipProcess.stderr.getReader();
|
const subFolder = zipFolder.folder(entry.name);
|
||||||
try {
|
if (subFolder) {
|
||||||
const chunks: Uint8Array[] = [];
|
await addFilesToZip(entryPath, subFolder);
|
||||||
while (true) {
|
|
||||||
const { done, value } = await stderrReader.read();
|
|
||||||
if (done) break;
|
|
||||||
if (value) chunks.push(value);
|
|
||||||
}
|
|
||||||
if (chunks.length > 0) {
|
|
||||||
// Concatenate chunks
|
|
||||||
const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
|
|
||||||
const combined = new Uint8Array(totalLength);
|
|
||||||
let offset = 0;
|
|
||||||
for (const chunk of chunks) {
|
|
||||||
combined.set(chunk, offset);
|
|
||||||
offset += chunk.length;
|
|
||||||
}
|
|
||||||
const errorText = new TextDecoder().decode(combined);
|
|
||||||
console.error('Zip stderr:', errorText);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
stderrReader.releaseLock();
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
console.error('Error reading stderr:', error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).catch((error) => {
|
}
|
||||||
console.error('Zip process error:', error);
|
|
||||||
|
// Add all files from the directory
|
||||||
|
await addFilesToZip(fullDirectoryPath, zip);
|
||||||
|
|
||||||
|
// Generate the zip file as a stream
|
||||||
|
const zipStream = zip.generateNodeStream({
|
||||||
|
type: 'nodebuffer',
|
||||||
|
streamFiles: true,
|
||||||
|
compression: 'DEFLATE',
|
||||||
|
compressionOptions: { level: 6 },
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Response(zipStream, {
|
// Convert Node.js stream to Web ReadableStream
|
||||||
|
const readableStream = new ReadableStream({
|
||||||
|
async start(controller) {
|
||||||
|
zipStream.on('data', (chunk: Buffer) => {
|
||||||
|
controller.enqueue(new Uint8Array(chunk));
|
||||||
|
});
|
||||||
|
|
||||||
|
zipStream.on('end', () => {
|
||||||
|
controller.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
zipStream.on('error', (error: Error) => {
|
||||||
|
console.error('Zip stream error:', error);
|
||||||
|
controller.error(error);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Response(readableStream, {
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': 'application/zip',
|
'content-type': 'application/zip',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue