Tenant-Importe ohne ZIP-Buffering verarbeiten
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 44s
Build and Push Docker Images / build-frontend (push) Successful in 22s
Build and Push Docker Images / build-central-services-api (push) Successful in 22s
Build and Push Docker Images / build-website (push) Successful in 21s
Build and Push Docker Images / build-central-services-admin (push) Successful in 22s
Build and Push Docker Images / build-docs (push) Successful in 22s

This commit is contained in:
root
2026-08-31 20:20:02 +00:00
parent b1785a35a9
commit f26743154a
2 changed files with 13 additions and 5 deletions

View File

@@ -3,7 +3,7 @@ import { and, eq, inArray, isNull, sql } from "drizzle-orm";
import multipart from "@fastify/multipart";
import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3";
import { randomUUID } from "node:crypto";
import { createReadStream, createWriteStream } from "node:fs";
import { createReadStream, createWriteStream, openAsBlob } from "node:fs";
import { stat, unlink } from "node:fs/promises";
import { pipeline } from "node:stream/promises";
@@ -469,6 +469,7 @@ export default async function adminRoutes(server: FastifyInstance) {
currentUser: { id: string; email: string },
source: { archiveStoragePath: string } | { exportData: TenantFullExport }
) => {
let temporaryArchivePath: string | null = null;
try {
await server.db
.update(tenantExportJobs)
@@ -499,8 +500,10 @@ export default async function adminRoutes(server: FastifyInstance) {
}));
if (!object.Body) throw new Error("Importarchiv konnte nicht aus dem Speicher gelesen werden");
const archiveBuffer = Buffer.from(await object.Body.transformToByteArray());
result = await importTenantFullExportArchive(server, archiveBuffer, { onProgress });
temporaryArchivePath = `${process.env.TMPDIR || "/tmp"}/fedeo-tenant-import-${randomUUID()}.zip`;
await pipeline(object.Body as NodeJS.ReadableStream, createWriteStream(temporaryArchivePath, { flags: "wx" }));
const archive = await openAsBlob(temporaryArchivePath);
result = await importTenantFullExportArchive(server, archive, { onProgress });
} else {
result = await importTenantFullExport(server, source.exportData, { onProgress });
}
@@ -532,6 +535,11 @@ export default async function adminRoutes(server: FastifyInstance) {
})
.where(eq(tenantExportJobs.id, jobId));
} finally {
if (temporaryArchivePath) {
await unlink(temporaryArchivePath).catch((cleanupError) => {
console.error("ERROR cleanup temporary tenant import archive:", cleanupError);
});
}
if ("archiveStoragePath" in source) {
await s3.send(new DeleteObjectCommand({
Bucket: secrets.S3_BUCKET,

View File

@@ -982,10 +982,10 @@ export const importTenantFullExport = async (
export const importTenantFullExportArchive = async (
server: FastifyInstance,
archiveBuffer: Buffer,
archive: Buffer | Blob,
options: ImportOptions = {}
): Promise<ImportResult> => {
const reader = new ZipReader(new BlobReader(new Blob([archiveBuffer])))
const reader = new ZipReader(new BlobReader(archive instanceof Blob ? archive : new Blob([archive])))
try {
const entries = await reader.getEntries()