fix: prepare zip file on the backend when exporting a project

This commit is contained in:
omar rashed
2024-11-16 21:48:40 -05:00
committed by James Murdza
parent ee531d7139
commit 10104c31b9
5 changed files with 210 additions and 26 deletions

View File

@ -1,4 +1,5 @@
import { FilesystemEvent, Sandbox, WatchHandle } from "e2b"
import JSZip from "jszip"
import path from "path"
import RemoteFileStorage from "./RemoteFileStorage"
import { MAX_BODY_SIZE } from "./ratelimit"
@ -472,6 +473,67 @@ export class FileManager {
return true
}
public async getFilesForDownload(): Promise<string> {
// Get all file paths, excluding node_modules
const result = await this.sandbox.commands.run(
`find "${this.dirName}" -path "${this.dirName}/node_modules" -prune -o -type f -print`
)
const filePaths = result.stdout.split("\n").filter((path) => path)
if (!filePaths || filePaths.length === 0) {
console.error(
"No files found in the sandbox project directory for download."
)
return ""
}
console.log("Paths found for download (excluding node_modules):", filePaths)
// Create new JSZip instance
const zip = new JSZip()
// Add files to zip with synchronized content
for (const filePath of filePaths) {
const relativePath = filePath.replace(this.dirName, "") // Remove base directory from path
try {
// Get the latest content directly from the sandbox
let content = await this.sandbox.files.read(filePath)
// Update the fileData cache with the latest content
const fileDataEntry = this.fileData.find((f) => f.id === relativePath)
if (fileDataEntry) {
fileDataEntry.data = typeof content === "string" ? content : ""
}
// Set content to an empty string if file is empty or undefined
if (typeof content !== "string") {
content = ""
}
zip.file(relativePath, content)
console.log(`Added file to ZIP: ${relativePath}`)
} catch (error) {
console.error(`Failed to read content for ${relativePath}:`, error)
}
}
// Generate zip file
const zipBlob = await zip.generateAsync({
type: "blob",
compression: "DEFLATE",
compressionOptions: {
level: 6,
},
})
// Convert Blob to Base64
const zipBlobArrayBuffer = await zipBlob.arrayBuffer()
const zipBlobBase64 = btoa(
String.fromCharCode(...new Uint8Array(zipBlobArrayBuffer))
)
return zipBlobBase64
}
// Create a new folder
async createFolder(name: string): Promise<void> {

View File

@ -13,7 +13,7 @@ import {
} from "./ratelimit"
import { SecureGitClient } from "./SecureGitClient"
import { TerminalManager } from "./TerminalManager"
import { TFile, TFileData, TFolder } from "./types"
import { TFile, TFolder } from "./types"
import { LockManager } from "./utils"
const lockManager = new LockManager()
@ -251,13 +251,10 @@ export class Sandbox {
const handleDownloadFiles: SocketHandler = async () => {
if (!this.fileManager) throw Error("No file manager")
// Get all files with their data through fileManager
const files = this.fileManager.fileData.map((file: TFileData) => ({
path: file.id.startsWith("/") ? file.id.slice(1) : file.id,
content: file.data,
}))
// Get the Base64 encoded ZIP string
const zipBase64 = await this.fileManager.getFilesForDownload()
return { files }
return { zipBlob: zipBase64 }
}
return {