( serverId: string | null, command: string, onData?: (data: string) => void, )
| 140 | }; |
| 141 | |
| 142 | export const execAsyncRemote = async ( |
| 143 | serverId: string | null, |
| 144 | command: string, |
| 145 | onData?: (data: string) => void, |
| 146 | ): Promise<{ stdout: string; stderr: string }> => { |
| 147 | if (!serverId) return { stdout: "", stderr: "" }; |
| 148 | const server = await findServerById(serverId); |
| 149 | if (!server.sshKeyId) throw new Error("No SSH key available for this server"); |
| 150 | |
| 151 | let stdout = ""; |
| 152 | let stderr = ""; |
| 153 | return new Promise((resolve, reject) => { |
| 154 | const conn = new Client(); |
| 155 | |
| 156 | sleep(1000); |
| 157 | conn |
| 158 | .once("ready", () => { |
| 159 | conn.exec(command, (err, stream) => { |
| 160 | if (err) { |
| 161 | onData?.(err.message); |
| 162 | reject( |
| 163 | new ExecError(`Remote command execution failed: ${err.message}`, { |
| 164 | command, |
| 165 | serverId, |
| 166 | originalError: err, |
| 167 | }), |
| 168 | ); |
| 169 | return; |
| 170 | } |
| 171 | stream |
| 172 | .on("close", (code: number, _signal: string) => { |
| 173 | conn.end(); |
| 174 | if (code === 0) { |
| 175 | resolve({ stdout, stderr }); |
| 176 | } else { |
| 177 | reject( |
| 178 | new ExecError( |
| 179 | `Remote command failed with exit code ${code}`, |
| 180 | { |
| 181 | command, |
| 182 | stdout, |
| 183 | stderr, |
| 184 | exitCode: code, |
| 185 | serverId, |
| 186 | }, |
| 187 | ), |
| 188 | ); |
| 189 | } |
| 190 | }) |
| 191 | .on("data", (data: string) => { |
| 192 | stdout += data.toString(); |
| 193 | onData?.(data.toString()); |
| 194 | }) |
| 195 | .stderr.on("data", (data) => { |
| 196 | stderr += data.toString(); |
| 197 | onData?.(data.toString()); |
| 198 | }); |
| 199 | }); |
no test coverage detected