var Promise = require('bluebird') var syrup = require('stf-syrup') var logger = require('../../../util/logger') var wire = require('../../../wire') var wireutil = require('../../../wire/util') module.exports = syrup.serial() .dependency(require('../support/adb')) .dependency(require('../support/router')) .dependency(require('../support/push')) .dependency(require('../support/sub')) .define(function(options, adb, router, push, sub) { var log = logger.createLogger('device:plugins:shell') router.on(wire.ShellCommandMessage, function(channel, message) { var reply = wireutil.reply(options.serial) log.info('Running shell command "%s"', message.command) adb.shell(options.serial, message.command) .timeout(10000) .then(function(stream) { var resolver = Promise.defer() var timer function forceStop() { stream.end() } function keepAliveListener(channel, message) { clearTimeout(timer) timer = setTimeout(forceStop, message.timeout) } function readableListener() { var chunk while ((chunk = stream.read())) { push.send([ channel , reply.progress(chunk) ]) } } function endListener() { push.send([ channel , reply.okay(null) ]) resolver.resolve() } function errorListener(err) { resolver.reject(err) } stream.setEncoding('utf8') stream.on('readable', readableListener) stream.on('end', endListener) stream.on('error', errorListener) sub.subscribe(channel) router.on(wire.ShellKeepAliveMessage, keepAliveListener) timer = setTimeout(forceStop, message.timeout) return resolver.promise.finally(function() { stream.removeListener('readable', readableListener) stream.removeListener('end', endListener) stream.removeListener('error', errorListener) sub.unsubscribe(channel) router.removeListener(wire.ShellKeepAliveMessage, keepAliveListener) clearTimeout(timer) }) }) .error(function(err) { log.error('Shell command "%s" failed', message.command, err.stack) push.send([ channel , reply.fail(err.message) ]) }) }) })