uci-utils-ssh/src/remote-code.js

124 lines
3.5 KiB
JavaScript

import { EventEmitter as Emitter } from 'events'
import stream from 'stream'
import Watcher from './watcher'
import Ssh from './ssh'
import Sync from './lib/sync'
const devNull = new stream.Writable()
devNull._write = () => null
class RemoteCode {
constructor(opts = {}) {
// Set defaults
// a id emitted with every event emit that can identify which remote code emitted
this.id = opts.id
this.watch = opts.watch || false
this.options.ssh.keepaliveInterval = opts.ssh.keepaliveInterval || 500
this.options.ssh.readyTimeout = opts.ssh.readyTimeout || 2000
this.options.ssh.port = opts.ssh.port || 22
this.options.source = opts.source || '.'
this.options.install = opts.install || 'yarn'
this.options.install = opts.registry ? `${this.options.install} --registry ${opts.registry}` : this.options.install
this.options.start = opts.start || 'nodemon .'
if (!(opts.ssh.keyfilePath || opts.ssh.password)) {
this.options.ssh.agent = process.env[opts.ssh.agent] || process.env.SSH_AUTH_SOCK || process.env.SSH_AGENT_SOCK
if (!this.options.ssh.agent) {
return new Error('no ssh authentification method provided')
}
}
this.ssh = new Ssh()
this.verbose = opts.verbose || false
this.stdout = opts.stdout instanceof stream.Writable ? opts.stdout : new stream.Writable()
this.stderr = opts.stderr instanceof stream.Writable ? opts.stderr : new stream.Writable()
this.watcher = new Watcher(this.options)
this.sync = new Sync(this.options)
.addStdOutStream(this.stdout)
.addStdErrStream(this.stderr)
}
_getStdOut() {
if (this.verbose) {
return this.stdout
}
return devNull
}
_getStdErr() {
if (this.verbose) {
return this.stderr
}
return devNull
}
sync() {
this.emit('sync',{})
return this.sync.execute()
}
watch() {
this.watcher.start()
const watchEmitter = this.watcher.getEventEmitter()
watchEmitter.on('sync', () => {
this.syncCode()
})
watchEmitter.on('install', () => {
return this.install()
.then(() => {
this.ssh.liveReload.send('rs')
})
})
return this.emitter
}
async init() {
this.emitter.emit('start')
const sshSettings = this.options.ssh
return Promise.all([this.syncCode(), this.watch()])
.then(() => this.install())
.then(() => this.ssh.liveReload.connect(sshSettings))
.then(() => {
this.emitter.emit('nodemon', 'start')
this.ssh.liveReload.send(`cd ${this.options.target} && ${this.options.start}`)
})
.catch(this._abort.bind(this))
}
// execute a single command and then resolve
execute(cmd, stdout, stderr) {
console.log('remote codes exec', cmd)
this.emitter.emit('exec', cmd)
const ssh = new Ssh()
const result = ssh.exec(this.options.ssh, cmd, stdout, stderr)
return result
}
async install() {
this.emit('install', 'triggered')
if (!this.installInProgress) {
this.emitter.emit('install', 'started')
console.log('calling execute from install')
return this.execute(`cd ${this.options.target} && ${this.options.install}`, this._getStdOut(), this._getStdErr())
.then(res => {
this.emit('install', 'done', res)
this.installInProgress = false
return res
})
}
return Promise.resolve()
}
close() {
this.emitter.emit('close')
return Promise.all([this.watcher.close(),
this.ssh.liveReload.close()])
}
_abort(err) {
this.emitter.emit('error', err)
}
}
export default RemoteCode