1
0
Fork 0
mirror of https://github.com/openstf/stf synced 2025-10-04 18:29:17 +02:00

First attempt at running shell commands with potentially streaming output. Still missing: multiple device support, command cancellation.

This commit is contained in:
Simo Kinnunen 2014-01-22 20:56:06 +09:00
parent 51ebf42dd3
commit 242f6f17de
5 changed files with 153 additions and 30 deletions

View file

@ -5,6 +5,8 @@ var Promise = require('bluebird')
var logger = require('../util/logger')
var tx = require('../util/tx')
var wire = require('../wire')
var wireutil = require('../util/wireutil')(wire)
module.exports = function(options) {
var log = logger.createLogger('console')
@ -43,33 +45,49 @@ module.exports = function(options) {
console.log()
rl.prompt()
break
case 'ls':
tx.q(push, sub, 'ALL', ['ls'])
.timeout(1000)
.then(function(results) {
results.forEach(function(result) {
console.log('%s', result.serial)
})
})
.catch(Promise.TimeoutError, function(err) {
console.log(err.message)
})
.finally(function() {
rl.prompt()
})
break
case 'shell':
tx.q(push, sub, 'ALL', ['shell', args.join(' ')])
.timeout(1000)
.then(function(results) {
results.forEach(function(result) {
console.log('%s: %s', result.serial, result.value.toString().trim())
})
})
.catch(Promise.TimeoutError, function(err) {
console.log(err.message)
})
.finally(function() {
var resolver = Promise.defer()
, ours = wireutil.makePrivateChannel()
log.debug('Using channel "%s"', ours)
function messageListener(theirs, data) {
if (theirs.toString() === ours) {
var wrapper = wire.Envelope.decode(data)
switch (wrapper.type) {
case wire.MessageType.DEVICE_DATA:
var message = wire.DeviceDataMessage.decode(wrapper.message)
log.info('[%s] DATA: %s'
, message.serial, message.data.toUTF8().trim())
break
case wire.MessageType.DEVICE_DONE:
var message = wire.DeviceDoneMessage.decode(wrapper.message)
log.info('[%s] DONE', message.serial)
resolver.resolve() // @todo Wait till all devices have finished
break
case wire.MessageType.DEVICE_FAIL:
var message = wire.DeviceFailMessage.decode(wrapper.message)
log.error('[%s] FAIL: ', message.serial, message.reason)
resolver.reject(new Error(message.reason))
break
default:
resolver.reject(new Error('Unexpected response'))
break
}
}
}
sub.subscribe(ours)
sub.on('message', messageListener)
push.send([wireutil.global, wireutil.makeShellCommandMessage(
ours
, args
)])
resolver.promise.finally(function() {
sub.unsubscribe(ours)
sub.removeListener('message', messageListener)
rl.prompt()
})
break

View file

@ -18,8 +18,8 @@ module.exports = function(options) {
appDealer.connect(endpoint)
})
appDealer.on('message', function(channel, id, cmd) {
devDealer.send([].slice.call(arguments))
appDealer.on('message', function(channel, data) {
devDealer.send([channel, data])
})
// Device side
@ -42,6 +42,18 @@ module.exports = function(options) {
case wire.MessageType.DEVICE_PROPERTIES:
var message = wire.DevicePropertiesMessage.decode(wrapper.message)
break
case wire.MessageType.DEVICE_DATA:
var message = wire.DeviceDataMessage.decode(wrapper.message)
appDealer.send([channel, data])
break
case wire.MessageType.DEVICE_DONE:
var message = wire.DeviceDoneMessage.decode(wrapper.message)
appDealer.send([channel, data])
break
case wire.MessageType.DEVICE_FAIL:
var message = wire.DeviceFailMessage.decode(wrapper.message)
appDealer.send([channel, data])
break
}
})
}

View file

@ -9,6 +9,7 @@ var wire = require('../wire')
var wireutil = require('../util/wireutil')(wire)
var devutil = require('../util/devutil')
var ChannelManager = require('../wire/channelmanager')
var streamutil = require('../util/streamutil')
module.exports = function(options) {
var log = logger.createLogger('device')
@ -67,6 +68,56 @@ module.exports = function(options) {
wireutil.makeDevicePropertiesMessage(options.serial, properties)])
})
break
case wire.MessageType.SHELL_COMMAND:
var message = wire.ShellCommandMessage.decode(wrapper.message)
adb.shellAsync(options.serial, message.command)
.then(function(stream) {
var resolver = Promise.defer()
, seq = 0
function dataListener(chunk) {
push.send([message.channel,
wireutil.makeDeviceDataMessage(
options.serial
, seq++
, chunk
)])
}
function endListener() {
push.send([message.channel,
wireutil.makeDeviceDoneMessage(options.serial)])
resolver.resolve()
}
function errorListener(err) {
log.error('Shell command "%s" failed due to "%s"'
, message.command.join(' '), err.message)
resolver.reject(err)
push.send([message.channel,
wireutil.makeDeviceFailMessage(
options.serial
, err.message
)])
}
stream.on('data', dataListener)
stream.on('end', endListener)
stream.on('error', errorListener)
return resolver.promise.finally(function() {
stream.removeListener('data', dataListener)
stream.removeListener('end', endListener)
stream.removeListener('error', errorListener)
})
})
.error(function(err) {
log.error('Shell command "%s" failed due to "%s"'
, message.command.join(' '), err.message)
push.send([message.channel,
wire.makeShellCommandFailMessage(options.serial, err.message)])
})
break
}
})

View file

@ -89,6 +89,22 @@ module.exports = function(wire) {
var message = new wire.ProbeMessage()
return wireutil.envelope(wire.MessageType.PROBE, message)
}
, makeShellCommandMessage: function(channel, command) {
var message = new wire.ShellCommandMessage(channel, command)
return wireutil.envelope(wire.MessageType.SHELL_COMMAND, message)
}
, makeDeviceDataMessage: function(serial, seq, chunk) {
var message = new wire.DeviceDataMessage(serial, seq, chunk)
return wireutil.envelope(wire.MessageType.DEVICE_DATA, message)
}
, makeDeviceDoneMessage: function(serial) {
var message = new wire.DeviceDoneMessage(serial)
return wireutil.envelope(wire.MessageType.DEVICE_DONE, message)
}
, makeDeviceFailMessage: function(serial, reason) {
var message = new wire.DeviceFailMessage(serial, reason)
return wireutil.envelope(wire.MessageType.DEVICE_FAIL, message)
}
}
return wireutil

View file

@ -9,6 +9,10 @@ enum MessageType {
JOIN_GROUP = 6;
LEAVE_GROUP = 7;
PROBE = 8;
SHELL_COMMAND = 9;
DEVICE_DATA = 10;
DEVICE_DONE = 11;
DEVICE_FAIL = 12;
}
message Envelope {
@ -85,3 +89,25 @@ message JoinGroupMessage {
message LeaveGroupMessage {
required string serial = 1;
}
// Commands
message ShellCommandMessage {
required string channel = 1;
repeated string command = 2;
}
message DeviceDataMessage {
required string serial = 1;
required uint32 seq = 2;
required bytes data = 3;
}
message DeviceDoneMessage {
required string serial = 1;
}
message DeviceFailMessage {
required string serial = 1;
required string reason = 2;
}