80 lines · 2.1 KB · TypeScript
RawDownload
import { exec } from "node:child_process";import util from "node:util";import { findServerById } from "@dokploy/server/services/server";import { Client } from "ssh2";export const execAsync = util.promisify(exec); export const execAsyncRemote = async (	serverId: string | null,	command: string,	onData?: (data: string) => void,): Promise<{ stdout: string; stderr: string }> => {	if (!serverId) return { stdout: "", stderr: "" };	const server = await findServerById(serverId);	if (!server.sshKeyId) throw new Error("No SSH key available for this server"); 	let stdout = "";	let stderr = "";	return new Promise((resolve, reject) => {		const conn = new Client(); 		sleep(1000);		conn			.once("ready", () => {				conn.exec(command, (err, stream) => {					if (err) {						onData?.(err.message);						throw err;					}					stream						.on("close", (code: number, _signal: string) => {							conn.end();							if (code === 0) {								resolve({ stdout, stderr });							} else {								reject(									new Error(										`Command exited with code ${code}. Stderr: ${stderr}, command: ${command}`,									),								);							}						})						.on("data", (data: string) => {							stdout += data.toString();							onData?.(data.toString());						})						.stderr.on("data", (data) => {							stderr += data.toString();							onData?.(data.toString());						});				});			})			.on("error", (err) => {				conn.end();				if (err.level === "client-authentication") {					onData?.(						`Authentication failed: Invalid SSH private key. ❌ Error: ${err.message} ${err.level}`,					);					reject(						new Error(							`Authentication failed: Invalid SSH private key. ❌ Error: ${err.message} ${err.level}`,						),					);				} else {					onData?.(`SSH connection error: ${err.message}`);					reject(new Error(`SSH connection error: ${err.message}`));				}			})			.connect({				host: server.ipAddress,				port: server.port,				username: server.username,				privateKey: server.sshKey?.privateKey,				timeout: 99999,			});	});}; export const sleep = (ms: number) => {	return new Promise((resolve) => setTimeout(resolve, ms));};