const Host = require('./Host') const ssh = require('ssh2') const ExecutionResult = require('../logical/ExecutionResult') const fs = require('fs').promises class RemoteHost extends Host { _ssh = false async execute(command) { const conn = await this._get_ssh_connection() const result = new ExecutionResult() await new Promise((resolve, reject) => { conn.exec(command, (error, stream) => { if ( error ) reject(error) else { stream.on('close', (code, signal) => { result.exit(code) resolve() }).on('data', (data) => { result.out(data) }).stderr.on('data', (data) => { result.error(data) }) } }) }) return result } async open_file_read_stream(file_path) { file_path = typeof file_path === 'string' ? file_path : file_path.path const sftp = await this._get_sftp_connection() return sftp.createReadStream(file_path) } async open_file_write_stream(file_path) { file_path = typeof file_path === 'string' ? file_path : file_path.path const sftp = await this._get_sftp_connection() return sftp.createWriteStream(file_path) } async _get_ssh_connection() { if ( this._ssh ) return this._ssh if ( this.config.ssh_params && this.config.ssh_params.key_file && !this.config.ssh_params.privateKey ) { this.config.ssh_params.privateKey = await fs.readFile(this.config.ssh_params.key_file) } return new Promise((resolve, reject) => { const client = new ssh.Client() client.on('ready', () => { this._ssh = client resolve(client) }).connect(this.config.ssh_params) client.on('error', reject) }) } async _get_sftp_connection() { const ssh = await this._get_ssh_connection() return new Promise((resolve, reject) => { ssh.sftp((err, sftp) => { if ( err ) reject(err) else resolve(sftp) }) }) } async _cleanup() { if ( this._ssh ) { this._ssh.end() } } } module.exports = exports = RemoteHost