Split out Ground, Codec

This commit is contained in:
Tony Garnock-Jones 2014-08-02 00:30:52 -07:00
parent f46fd52239
commit e78696c621
6 changed files with 114 additions and 88 deletions

33
src/codec.js Normal file
View File

@ -0,0 +1,33 @@
// Wire protocol representation of events and actions
var Route = require("./route.js");
function _encode(e) {
switch (e.type) {
case "routes":
return ["routes", e.gestalt.serialize(function (v) { return true; })];
case "message":
return ["message", e.message, e.metaLevel, e.isFeedback];
}
}
function _decode(what) {
return function (j) {
switch (j[0]) {
case "routes":
return Minimart.updateRoutes([
Route.deserializeGestalt(j[1], function (v) { return true; })]);
case "message":
return Minimart.sendMessage(j[1], j[2], j[3]);
default:
throw { message: "Invalid JSON-encoded " + what + ": " + JSON.stringify(j) };
}
};
}
///////////////////////////////////////////////////////////////////////////
module.exports.encodeEvent = _encode;
module.exports.decodeEvent = _decode("event");
module.exports.encodeAction = _encode;
module.exports.decodeAction = _decode("action");

61
src/ground.js Normal file
View File

@ -0,0 +1,61 @@
/* Ground interface */
var Minimart = require("./minimart.js");
var World = Minimart.World;
function Ground(bootFn) {
var self = this;
this.stepperId = null;
World.withWorldStack([[this, -1]], function () {
self.world = new World(bootFn);
});
}
Ground.prototype.step = function () {
var self = this;
return World.withWorldStack([[this, -1]], function () {
return self.world.step();
});
};
Ground.prototype.checkPid = function (pid) {
if (pid !== -1) console.error("Weird pid in Ground markPidRunnable", pid);
};
Ground.prototype.markPidRunnable = function (pid) {
this.checkPid(pid);
this.startStepping();
};
Ground.prototype.startStepping = function () {
var self = this;
if (this.stepperId) return;
if (this.step()) {
this.stepperId = setTimeout(function () {
self.stepperId = null;
self.startStepping();
}, 0);
}
};
Ground.prototype.stopStepping = function () {
if (this.stepperId) {
clearTimeout(this.stepperId);
this.stepperId = null;
}
};
Ground.prototype.enqueueAction = function (pid, action) {
this.checkPid(pid);
if (action.type === 'routes') {
if (!action.gestalt.isEmpty()) {
console.error("You have subscribed to a nonexistent event source.",
action.gestalt.pretty());
}
} else {
console.error("You have sent a message into the outer void.", action);
}
};
///////////////////////////////////////////////////////////////////////////
module.exports.Ground = Ground;

View File

@ -6,6 +6,7 @@ module.exports.RoutingTableWidget = require("./routing-table-widget.js");
module.exports.WebSocket = require("./websocket-driver.js");
module.exports.Reflect = require("./reflect.js");
module.exports.Ground = require("./ground.js").Ground;
module.exports.Actor = require("./actor.js").Actor;
module.exports.Spy = require("./spy.js").Spy;
module.exports.WakeDetector = require("./wake-detector.js").WakeDetector;
module.exports.Actor = require("./actor.js").Actor;

View File

@ -1,4 +1,5 @@
var Route = require("./route.js");
var Util = require("./util.js");
///////////////////////////////////////////////////////////////////////////
@ -390,7 +391,7 @@ World.prototype.clearTombstones = function () {
/* Utilities: matching demand for some service */
function DemandMatcher(projection, metaLevel, options) {
options = $.extend({
options = Util.extend({
demandLevel: 0,
supplyLevel: 0,
demandSideIsSubscription: false
@ -481,63 +482,6 @@ Deduplicator.prototype.expireMessages = function () {
}
};
/*---------------------------------------------------------------------------*/
/* Ground interface */
function Ground(bootFn) {
var self = this;
this.stepperId = null;
World.withWorldStack([[this, -1]], function () {
self.world = new World(bootFn);
});
}
Ground.prototype.step = function () {
var self = this;
return World.withWorldStack([[this, -1]], function () {
return self.world.step();
});
};
Ground.prototype.checkPid = function (pid) {
if (pid !== -1) console.error("Weird pid in Ground markPidRunnable", pid);
};
Ground.prototype.markPidRunnable = function (pid) {
this.checkPid(pid);
this.startStepping();
};
Ground.prototype.startStepping = function () {
var self = this;
if (this.stepperId) return;
if (this.step()) {
this.stepperId = setTimeout(function () {
self.stepperId = null;
self.startStepping();
}, 0);
}
};
Ground.prototype.stopStepping = function () {
if (this.stepperId) {
clearTimeout(this.stepperId);
this.stepperId = null;
}
};
Ground.prototype.enqueueAction = function (pid, action) {
this.checkPid(pid);
if (action.type === 'routes') {
if (!action.gestalt.isEmpty()) {
console.error("You have subscribed to a nonexistent event source.",
action.gestalt.pretty());
}
} else {
console.error("You have sent a message into the outer void.", action);
}
};
///////////////////////////////////////////////////////////////////////////
module.exports.__ = __;
@ -553,5 +497,4 @@ module.exports.shutdownWorld = shutdownWorld;
module.exports.World = World;
module.exports.DemandMatcher = DemandMatcher;
module.exports.Deduplicator = Deduplicator;
module.exports.Ground = Ground;
module.exports.Route = Route;

13
src/util.js Normal file
View File

@ -0,0 +1,13 @@
// Minimal jQueryish utilities. Reimplemented because jQuery needs
// window to exist, and we want to run in Web Worker context as well.
function extend(what, _with) {
for (var prop in _with) {
if (_with.hasOwnProperty(prop)) {
what[prop] = _with[prop];
}
}
return what;
}
module.exports.extend = extend;

View File

@ -1,4 +1,5 @@
var Minimart = require("./minimart.js");
var Codec = require("./codec.js");
var Route = Minimart.Route;
var World = Minimart.World;
var sub = Minimart.sub;
@ -97,7 +98,7 @@ WebSocketConnection.prototype.safeSend = function (m) {
WebSocketConnection.prototype.sendLocalRoutes = function () {
var newLocalRoutesMessage =
JSON.stringify(encodeEvent(Minimart.updateRoutes([this.localGestalt])));
JSON.stringify(Codec.encodeEvent(Minimart.updateRoutes([this.localGestalt])));
if (this.prevLocalRoutesMessage !== newLocalRoutesMessage) {
this.prevLocalRoutesMessage = newLocalRoutesMessage;
this.safeSend(newLocalRoutesMessage);
@ -138,7 +139,7 @@ WebSocketConnection.prototype.handleEvent = function (e) {
var m = e.message;
if (m.length && m.length === 3 && m[0] === this.label)
{
var encoded = JSON.stringify(encodeEvent(
var encoded = JSON.stringify(Codec.encodeEvent(
Minimart.sendMessage(m[2], m[1], e.isFeedback)));
if (this.deduplicator.accept(encoded)) {
this.safeSend(encoded);
@ -227,32 +228,6 @@ WebSocketConnection.prototype.onclose = function (e) {
}
};
///////////////////////////////////////////////////////////////////////////
// Wire protocol representation of events and actions
function encodeEvent(e) {
switch (e.type) {
case "routes":
return ["routes", e.gestalt.serialize(function (v) { return true; })];
case "message":
return ["message", e.message, e.metaLevel, e.isFeedback];
}
}
function decodeAction(j) {
switch (j[0]) {
case "routes":
return Minimart.updateRoutes([
Route.deserializeGestalt(j[1], function (v) { return true; })]);
case "message":
return Minimart.sendMessage(j[1], j[2], j[3]);
default:
throw { message: "Invalid JSON-encoded action: " + JSON.stringify(j) };
}
}
///////////////////////////////////////////////////////////////////////////
module.exports.WebSocketConnection = WebSocketConnection;
module.exports.encodeEvent = encodeEvent;
module.exports.decodeAction = decodeAction;