import {Host} from './Host' import {Application, Awaitable, Filesystem, SSHFilesystem} from '@extollo/lib' import {ExecutionResult} from './ExecutionResult' import {ShellCommand} from './types' import * as ssh2 from 'ssh2' export class SSHHost extends Host { private sshClient?: ssh2.Client private filesystem?: Filesystem constructor( protected readonly config: ssh2.ConnectConfig, ) { super() } async close() { this.sshClient?.end() this.sshClient?.destroy() this.sshClient = undefined this.filesystem?.close() this.filesystem = undefined } async execute(command: ShellCommand): Promise{ const client = await this.getSSH() const result = new ExecutionResult() return new Promise((res, rej) => { client.exec(command, (err, stream) => { if ( err ) { return rej(err) } stream .on('close', (code: number) => { result.exit(code) res(result) }) .on('data', (data: any) => { result.out(data) }) .stderr.on('data', (data: any) => { result.error(data) }) }) }) } getFilesystem(): Awaitable { if ( !this.filesystem ) { this.filesystem = Application.getContainer().makeNew(SSHFilesystem, { ssh: this.config, baseDir: '/', }) } return this.filesystem } protected async getSSH(): Promise { if ( this.sshClient ) { return this.sshClient } return new Promise((res, rej) => { const client = new ssh2.Client() client.on('ready', () => { this.sshClient = client res(client) }).connect(this.config) client.on('error', rej) }) } }