mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-09 16:05:23 +02:00
feat: add web UI file upload to Docker containers
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
import {
|
||||
execAsync,
|
||||
execAsyncRemote,
|
||||
@@ -472,3 +475,85 @@ export const getApplicationInfo = async (
|
||||
return appArray;
|
||||
} catch {}
|
||||
};
|
||||
|
||||
export const uploadFileToContainer = async (
|
||||
containerId: string,
|
||||
fileBuffer: Buffer,
|
||||
fileName: string,
|
||||
destinationPath: string,
|
||||
serverId?: string | null,
|
||||
): Promise<void> => {
|
||||
const containerIdRegex = /^[a-zA-Z0-9.\-_]+$/;
|
||||
if (!containerIdRegex.test(containerId)) {
|
||||
throw new Error("Invalid container ID");
|
||||
}
|
||||
|
||||
// Ensure destination path starts with /
|
||||
const normalizedPath = destinationPath.startsWith("/")
|
||||
? destinationPath
|
||||
: `/${destinationPath}`;
|
||||
|
||||
if (serverId) {
|
||||
// Remote server: transfer file via base64 encoding using heredoc
|
||||
const base64Content = fileBuffer.toString("base64");
|
||||
const tempFileName = `dokploy-upload-${Date.now()}-${fileName.replace(/[^a-zA-Z0-9.-]/g, "_")}`;
|
||||
const tempPath = `/tmp/${tempFileName}`;
|
||||
|
||||
try {
|
||||
// Create temp directory and write file on remote server using heredoc
|
||||
// This handles large files and special characters better than echo
|
||||
const writeCommand = `cat << 'EOF' | base64 -d > "${tempPath}"
|
||||
${base64Content}
|
||||
EOF
|
||||
`;
|
||||
|
||||
await execAsyncRemote(serverId, writeCommand);
|
||||
|
||||
// Copy file into container
|
||||
const copyCommand = `docker cp "${tempPath}" "${containerId}:${normalizedPath}"`;
|
||||
await execAsyncRemote(serverId, copyCommand);
|
||||
|
||||
// Clean up temp file
|
||||
const cleanupCommand = `rm -f "${tempPath}"`;
|
||||
await execAsyncRemote(serverId, cleanupCommand);
|
||||
} catch (error) {
|
||||
// Try to clean up on error
|
||||
try {
|
||||
await execAsyncRemote(serverId, `rm -f "${tempPath}"`);
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
throw new Error(
|
||||
`Failed to upload file to container: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Local server: use temp directory
|
||||
const tempDir = await mkdtemp(join(tmpdir(), "dokploy-upload-"));
|
||||
const tempFilePath = join(tempDir, fileName);
|
||||
|
||||
try {
|
||||
// Write file to temp directory
|
||||
await writeFile(tempFilePath, fileBuffer);
|
||||
|
||||
// Copy file into container
|
||||
const copyCommand = `docker cp "${tempFilePath}" "${containerId}:${normalizedPath}"`;
|
||||
await execAsync(copyCommand);
|
||||
|
||||
// Clean up temp directory
|
||||
await rm(tempFilePath, { force: true });
|
||||
await rm(tempDir, { recursive: true, force: true });
|
||||
} catch (error) {
|
||||
// Try to clean up on error
|
||||
try {
|
||||
await rm(tempFilePath, { force: true });
|
||||
await rm(tempDir, { recursive: true, force: true });
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
throw new Error(
|
||||
`Failed to upload file to container: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user