From 43e94b83b49f88de921ded962df82f959a8ad51e Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Tue, 10 May 2016 17:04:16 -0400 Subject: [PATCH] Timer driver --- js/src/main.js | 1 + js/src/timer-driver.js | 114 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 js/src/timer-driver.js diff --git a/js/src/main.js b/js/src/main.js index 0925f29..96a580a 100644 --- a/js/src/main.js +++ b/js/src/main.js @@ -29,6 +29,7 @@ module.exports.Ack = require('./ack.js').Ack; module.exports.RandomID = require('./randomid.js'); module.exports.DOM = require("./dom-driver.js"); module.exports.JQuery = require("./jquery-driver.js"); +module.exports.Timer = require("./timer-driver.js"); module.exports.Reflect = require("./reflect.js"); module.exports.WakeDetector = require("./wake-detector-driver.js"); module.exports.Codec = require("./codec.js"); diff --git a/js/src/timer-driver.js b/js/src/timer-driver.js new file mode 100644 index 0000000..0ee8162 --- /dev/null +++ b/js/src/timer-driver.js @@ -0,0 +1,114 @@ +// Timer event driver +var Patch = require("./patch.js"); +var DemandMatcher = require('./demand-matcher.js').DemandMatcher; +var Struct = require('./struct.js'); + +var Dataspace_ = require("./dataspace.js"); +var Dataspace = Dataspace_.Dataspace; +var __ = Dataspace_.__; +var _$ = Dataspace_._$; + +var periodicTick = Struct.makeConstructor('periodicTick', ['intervalMS']); // message +var timeLaterThan = Struct.makeConstructor('timeLaterThan', ['deadlineMS']); // assertion + +function spawnTimerDriver() { + Dataspace.spawn( + new DemandMatcher([Patch.observe(periodicTick(_$('intervalMS')))], + [Patch.advertise(periodicTick(_$('intervalMS')))], + { + onDemandIncrease: function (c) { + Dataspace.spawn(new Tick(c.intervalMS)); + } + })); + Dataspace.spawn( + new DemandMatcher([Patch.observe(timeLaterThan(_$('deadlineMS')))], + [Patch.advertise(timeLaterThan(_$('deadlineMS')))], + { + onDemandIncrease: function (c) { + Dataspace.spawn(new Alarm(c.deadlineMS)); + } + })); +} + +function Tick(intervalMS) { + this.intervalMS = intervalMS; + this.handle = null; +} + +Tick.prototype.boot = function () { + var self = this; + this.handle = setInterval(Dataspace.wrap(function () { + Dataspace.send(periodicTick(self.intervalMS)); + }), this.intervalMS); + + return Patch.sub(Patch.observe(periodicTick(this.intervalMS))) // monitor interest + .andThen(Patch.pub(periodicTick(this.intervalMS))) // signal we exist to DemandMatcher + ; +}; + +Tick.prototype.trapexit = function () { + this.cancelTimer(); +}; + +Tick.prototype.cancelTimer = function () { + if (this.handle !== null) { + clearInterval(this.handle); + this.handle = null; + } +}; + +Tick.prototype.handleEvent = function (e) { + if (e.type === 'stateChange' && e.patch.hasRemoved()) { + Dataspace.exit(); + } +}; + +function Alarm(deadlineMS) { + this.deadlineMS = deadlineMS; + this.handle = null; +} + +Alarm.prototype.boot = function () { + this.checkTimeout(); + + return Patch.sub(Patch.observe(timeLaterThan(this.deadlineMS))) // monitor interest + .andThen(Patch.pub(timeLaterThan(this.deadlineMS))) // signal we exist to DemandMatcher + ; +}; + +Alarm.prototype.checkTimeout = function () { + var now = +(new Date()); + var delta = this.deadlineMS - now; + if (delta <= 0) { + Dataspace.stateChange(Patch.assert(timeLaterThan(this.deadlineMS))); + this.cancelTimer(); + } else if (this.handle === null) { + var self = this; + this.handle = setTimeout(Dataspace.wrap(function () { self.checkTimeout(); }), delta); + } +}; + +Alarm.prototype.cancelTimer = function () { + if (this.handle !== null) { + clearTimeout(this.handle); + this.handle = null; + } +}; + +Alarm.prototype.trapexit = function () { + this.cancelTimer(); +}; + +Alarm.prototype.handleEvent = function (e) { + if (e.type === 'stateChange' && e.patch.hasRemoved()) { + Dataspace.exit(); + } +}; + +/////////////////////////////////////////////////////////////////////////// + +module.exports.spawnTimerDriver = spawnTimerDriver; +module.exports.periodicTick = periodicTick; +module.exports.timeLaterThan = timeLaterThan; +module.exports.Tick = Tick; +module.exports.Alarm = Alarm;