uci-remote-code/src/ssh.js

80 lines
2.5 KiB
JavaScript

import { promisify } from 'util'
import to from 'await-to-js'
import { readFile } from 'fs'
import { Client } from 'ssh2'
import logger from '@uci/logger'
let log = {} // declare module wide log to be set during construction
const read = promisify(readFile)
// ssh client is already an event emitter
class Ssh extends Client {
constructor(opts={}) {
super()
this.opts = opts
log = logger({ name: 'remote-code', file:'src/ssh.js', class:'Ssh', id: opts.id })
this.ready = false
// additional options available
this.rpath = opts.rpath || '/opt' // will cd to this path upon connect
}
async connect(copts = {}) {
const opts = Object.assign({},this.opts,copts) // merge any changes pasted via connect
// log.info('connection options ', opts)
opts.readyTimeout = opts.readyTimeout | 5000 // default was 20 seconds...too long
opts.privateKey = opts.privateKey || opts.privateKeyPath ? await read(opts.privateKeyPath) : null
// log.info(opts.privateKeyPath, opts.privateKey)
super.connect(opts)
return new Promise( (resolve,reject) => {
this.on('ready', async () => {
this.ready=true
log.info(`connected to ${this.opts.host}`)
resolve(`connected to ${this.opts.host}`)
})
this.on('error', (err) => {
log.info('connection error', err)
reject(err)
})
})
}
close() {
this.ready=false
this.end()
}
async exec(command = 'ls -la', opts={}) {
if (!this.ready) {
log.info('not connected, attempting connect first')
let [err] = await to(this.connect())
if (err) return err
}
// log.info('executing command ', command)
const remote = this
let superexec = super.exec.bind(this)
return new Promise(function(resolve, reject) {
let reply=[]
let error=[]
superexec(command, function(err, stream) {
if (err) reject(err)
stream.on('finish', () => {
if (remote.opts.close || opts.close) {
log.info('closing connection')
remote.close
}
if (error.length!==0) remote.emit('client:error',error)
resolve({command:command,reply:reply,error:error})
})
.on('data', function(data) {
reply.push(data)
log.info(`${remote.opts.host}$ ${data}`)
}).stderr.on('data', function(data) {
error.push(data)
log.info(`${remote.opts.host}:ERR$ ${data}`)
})
}) // end super
}) // end Promise
}
}
export default Ssh