diff --git a/lib/units/device/plugins/screen/stream.js b/lib/units/device/plugins/screen/stream.js index f5993b2b..62a71cc5 100644 --- a/lib/units/device/plugins/screen/stream.js +++ b/lib/units/device/plugins/screen/stream.js @@ -16,6 +16,7 @@ var FrameConfig = require('./util/frameconfig') var BroadcastSet = require('./util/broadcastset') var StateQueue = require('./util/statequeue') var RiskyStream = require('./util/riskystream') +var FailCounter = require('./util/failcounter') module.exports = syrup.serial() .dependency(require('../../support/adb')) @@ -38,6 +39,9 @@ module.exports = syrup.serial() this.readable = false this.needsReadable = false this.starter = Promise.resolve(true) + this.failCounter = new FailCounter(3, 10000) + this.failCounter.on('exceedLimit', this._failLimitExceeded.bind(this)) + this.failed = false } util.inherits(FrameProducer, EventEmitter) @@ -52,6 +56,11 @@ module.exports = syrup.serial() return } + if (this.failed) { + log.warn('Will not apply desired state due to too many failures') + return + } + switch (this.runningState) { case FrameProducer.STATE_STARTING: case FrameProducer.STATE_STOPPING: @@ -88,6 +97,7 @@ module.exports = syrup.serial() }) .catch(function(err) { return this._stop().finally(function() { + this.failCounter.inc() this.emit('error', err) }) }) @@ -191,14 +201,26 @@ module.exports = syrup.serial() FrameProducer.prototype._socketEnded = function() { log.warn('Connection to minicap ended unexpectedly') + this.failCounter.inc() this.restart() } FrameProducer.prototype._outputEnded = function() { log.warn('Shell keeping minicap running ended unexpectedly') + this.failCounter.inc() this.restart() } + FrameProducer.prototype._failLimitExceeded = function(limit, time) { + this._stop() + this.failed = true + this.emit('error', new Error(util.format( + 'Failed more than %d times in %dms' + , limit + , time + ))) + } + FrameProducer.prototype._startService = function() { log.info('Launching screen service') return minicap.run(util.format('-S -P %s', this.frameConfig.toString())) diff --git a/lib/units/device/plugins/screen/util/failcounter.js b/lib/units/device/plugins/screen/util/failcounter.js new file mode 100644 index 00000000..4df55912 --- /dev/null +++ b/lib/units/device/plugins/screen/util/failcounter.js @@ -0,0 +1,32 @@ +var util = require('util') + +var EventEmitter = require('eventemitter3').EventEmitter + +function FailCounter(threshold, time) { + this.threshold = threshold + this.time = time + this.values = [] +} + +util.inherits(FailCounter, EventEmitter) + +FailCounter.prototype.inc = function() { + var now = Date.now() + + while (this.values.length) { + if (now - this.values[0] >= this.time) { + this.values.shift() + } + else { + break + } + } + + this.values.push(now) + + if (this.values.length > this.threshold) { + this.emit('exceedLimit', this.threshold, this.time) + } +} + +module.exports = FailCounter