mirror of
https://github.com/DeviceFarmer/stf.git
synced 2026-04-21 05:15:17 +02:00
Don't rely on lucky timings when sending messages from the provider.
This commit is contained in:
@@ -9,12 +9,14 @@ var _ = require('lodash')
|
||||
var logger = require('../util/logger')
|
||||
var wire = require('../wire')
|
||||
var wireutil = require('../wire/util')
|
||||
var wirerouter = require('../wire/router')
|
||||
var procutil = require('../util/procutil')
|
||||
|
||||
module.exports = function(options) {
|
||||
var log = logger.createLogger('provider')
|
||||
var client = Promise.promisifyAll(adb.createClient())
|
||||
var workers = {}
|
||||
var solo = wireutil.makePrivateChannel()
|
||||
var lists = {
|
||||
all: []
|
||||
, ready: []
|
||||
@@ -58,6 +60,19 @@ module.exports = function(options) {
|
||||
push.connect(endpoint)
|
||||
})
|
||||
|
||||
// Input
|
||||
var sub = zmq.socket('sub')
|
||||
options.endpoints.sub.forEach(function(endpoint) {
|
||||
log.info('Receiving input from %s', endpoint)
|
||||
sub.connect(endpoint)
|
||||
})
|
||||
|
||||
// Establish always-on channels
|
||||
;[solo].forEach(function(channel) {
|
||||
log.info('Subscribing to permanent channel "%s"', channel)
|
||||
sub.subscribe(channel)
|
||||
})
|
||||
|
||||
// Track and manage devices
|
||||
client.trackDevicesAsync().then(function(tracker) {
|
||||
log.info('Tracking devices')
|
||||
@@ -82,85 +97,119 @@ module.exports = function(options) {
|
||||
tracker.on('add', filterDevice(function(device) {
|
||||
log.info('Found device "%s" (%s)', device.id, device.type)
|
||||
|
||||
// Tell others we found a device
|
||||
push.send([
|
||||
wireutil.global
|
||||
, wireutil.envelope(new wire.DevicePresentMessage(
|
||||
device.id
|
||||
, options.name
|
||||
, wireutil.toDeviceStatus(device.type)
|
||||
))
|
||||
])
|
||||
var privateTracker = new events.EventEmitter()
|
||||
, timer
|
||||
, worker
|
||||
|
||||
// Wait for others to acknowledge the device
|
||||
var register = new Promise(function(resolve, reject) {
|
||||
// Tell others we found a device
|
||||
push.send([
|
||||
wireutil.global
|
||||
, wireutil.envelope(new wire.DevicePresentMessage(
|
||||
device.id
|
||||
, wireutil.toDeviceStatus(device.type)
|
||||
, new wire.ProviderMessage(
|
||||
solo
|
||||
, options.name
|
||||
)
|
||||
))
|
||||
])
|
||||
|
||||
privateTracker.once('register', resolve)
|
||||
})
|
||||
|
||||
register.then(function() {
|
||||
log.info('Registered device "%s"', device.id)
|
||||
check()
|
||||
})
|
||||
|
||||
// Statistics
|
||||
lists.all.push(device.id)
|
||||
delayedTotals()
|
||||
|
||||
var privateTracker = new events.EventEmitter()
|
||||
, resolver = Promise.defer()
|
||||
, timer
|
||||
, worker
|
||||
// The device object will be kept up to date by the tracker, except
|
||||
// our custom "present" property
|
||||
_.assign(device, {
|
||||
present: true
|
||||
})
|
||||
|
||||
// When any event occurs on the added device
|
||||
function deviceListener(type, device) {
|
||||
function deviceListener(type) {
|
||||
// Okay, this is a bit unnecessary but it allows us to get rid of an
|
||||
// ugly switch statement and return to the original style.
|
||||
privateTracker.emit(type, device)
|
||||
privateTracker.emit(type)
|
||||
}
|
||||
|
||||
// When the added device changes
|
||||
function changeListener(device) {
|
||||
log.info('Device "%s" is now "%s"', device.id, device.type)
|
||||
function changeListener() {
|
||||
register.then(function() {
|
||||
log.info('Device "%s" is now "%s"', device.id, device.type)
|
||||
|
||||
// Tell others the device changed
|
||||
push.send([
|
||||
wireutil.global
|
||||
, wireutil.envelope(new wire.DeviceStatusMessage(
|
||||
device.id
|
||||
, wireutil.toDeviceStatus(device.type)
|
||||
))
|
||||
])
|
||||
// Tell others the device changed
|
||||
push.send([
|
||||
wireutil.global
|
||||
, wireutil.envelope(new wire.DeviceStatusMessage(
|
||||
device.id
|
||||
, wireutil.toDeviceStatus(device.type)
|
||||
))
|
||||
])
|
||||
|
||||
check(device)
|
||||
check()
|
||||
})
|
||||
}
|
||||
|
||||
// When the added device gets removed
|
||||
function removeListener(device) {
|
||||
log.info('Lost device "%s" (%s)', device.id, device.type)
|
||||
function removeListener() {
|
||||
register.then(function() {
|
||||
log.info('Lost device "%s" (%s)', device.id, device.type)
|
||||
|
||||
clearTimeout(timer)
|
||||
flippedTracker.removeListener(device.id, deviceListener)
|
||||
_.pull(lists.all, device.id)
|
||||
delayedTotals()
|
||||
clearTimeout(timer)
|
||||
flippedTracker.removeListener(device.id, deviceListener)
|
||||
_.pull(lists.all, device.id)
|
||||
delayedTotals()
|
||||
|
||||
// Tell others the device is gone
|
||||
push.send([
|
||||
wireutil.global
|
||||
, wireutil.envelope(new wire.DeviceAbsentMessage(
|
||||
device.id
|
||||
))
|
||||
])
|
||||
// Tell others the device is gone
|
||||
push.send([
|
||||
wireutil.global
|
||||
, wireutil.envelope(new wire.DeviceAbsentMessage(
|
||||
device.id
|
||||
))
|
||||
])
|
||||
|
||||
stop()
|
||||
_.assign(device, {
|
||||
present: false
|
||||
})
|
||||
|
||||
check()
|
||||
})
|
||||
}
|
||||
|
||||
// Check if we can do anything with the device
|
||||
function check(device) {
|
||||
function check() {
|
||||
clearTimeout(timer)
|
||||
switch (device.type) {
|
||||
case 'device':
|
||||
case 'emulator':
|
||||
timer = setTimeout(work, 100)
|
||||
break
|
||||
default:
|
||||
stop()
|
||||
break
|
||||
|
||||
if (device.present) {
|
||||
// We might get multiple status updates in rapid succession,
|
||||
// so let's wait for a while
|
||||
switch (device.type) {
|
||||
case 'device':
|
||||
case 'emulator':
|
||||
timer = setTimeout(work, 100)
|
||||
break
|
||||
default:
|
||||
timer = setTimeout(stop, 100)
|
||||
break
|
||||
}
|
||||
}
|
||||
else {
|
||||
stop()
|
||||
}
|
||||
}
|
||||
|
||||
// Starts a device worker and keeps it alive
|
||||
function work() {
|
||||
return worker = workers[device.id] = spawn(device)
|
||||
return worker = workers[device.id] = spawn()
|
||||
.then(function() {
|
||||
log.info('Device worker "%s" has retired', device.id)
|
||||
worker = workers[device.id] = null
|
||||
@@ -188,7 +237,7 @@ module.exports = function(options) {
|
||||
}
|
||||
|
||||
// Spawn a device worker
|
||||
function spawn(device) {
|
||||
function spawn() {
|
||||
var ports = options.ports.splice(0, 2)
|
||||
, proc = options.fork(device, ports)
|
||||
, resolver = Promise.defer()
|
||||
@@ -272,7 +321,6 @@ module.exports = function(options) {
|
||||
flippedTracker.on(device.id, deviceListener)
|
||||
privateTracker.on('change', changeListener)
|
||||
privateTracker.on('remove', removeListener)
|
||||
check(device)
|
||||
}))
|
||||
|
||||
tracker.on('change', filterDevice(function(device) {
|
||||
@@ -282,6 +330,12 @@ module.exports = function(options) {
|
||||
tracker.on('remove', filterDevice(function(device) {
|
||||
flippedTracker.emit(device.id, 'remove', device)
|
||||
}))
|
||||
|
||||
sub.on('message', wirerouter()
|
||||
.on(wire.DeviceRegisteredMessage, function(channel, message) {
|
||||
flippedTracker.emit(message.serial, 'register')
|
||||
})
|
||||
.handler())
|
||||
})
|
||||
|
||||
function gracefullyExit() {
|
||||
|
||||
Reference in New Issue
Block a user