Ground network; minor refactorings and bugfixes; smoketest example

This commit is contained in:
Tony Garnock-Jones 2016-02-02 21:02:55 -05:00
parent e0f76b991a
commit 9f69cffbe7
9 changed files with 160 additions and 28 deletions

View File

@ -0,0 +1,13 @@
<!doctype html>
<html>
<head>
<title>Syndicate: Smoketest</title>
<meta charset="utf-8">
<script src="../../third-party/jquery-2.2.0.min.js"></script>
<script src="../../dist/syndicate.js"></script>
<script src="index.js"></script>
</head>
<body>
<h1>Smoketest</h1>
</body>
</html>

View File

@ -0,0 +1,31 @@
var G;
$(document).ready(function () {
var Network = Syndicate.Network;
var sub = Syndicate.sub;
var __ = Syndicate.__;
var _$ = Syndicate._$;
G = new Syndicate.Ground(function () {
console.log('starting ground boot');
Network.spawn({
counter: 0,
boot: function () {},
handleEvent: function (e) {},
step: function () {
Network.send(["beep", this.counter++]);
return this.counter <= 10;
}
});
Network.spawn({
boot: function () { return sub(["beep", __]); },
handleEvent: function (e) {
if (e.type === 'message') {
console.log("beep!", e.message[1]);
}
}
});
});
G.startStepping();
});

77
js/src/ground.js Normal file
View File

@ -0,0 +1,77 @@
var Immutable = require('immutable');
var Syndicate = require('./syndicate.js');
var Network = Syndicate.Network;
function Ground(bootFn) {
var self = this;
this.stepperId = null;
this.baseStack = Immutable.List.of({ network: this, activePid: -1 });
Network.withNetworkStack(this.baseStack, function () {
self.network = new Network(bootFn);
});
}
Ground.prototype.step = function () {
var self = this;
return Network.withNetworkStack(this.baseStack, function () {
return self.network.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.kill = function (pid, exn) {
this.checkPid(pid);
console.log("Ground network terminated");
this.stopStepping();
};
Ground.prototype.enqueueAction = function (pid, action) {
this.checkPid(pid);
switch (action.type) {
case 'stateChange':
if (action.patch.isNonEmpty()) {
console.error('You have subscribed to a nonexistent event source.',
action.patch.pretty());
}
break;
case 'message':
console.error('You have sent a message into the outer void.', action);
break;
default:
console.error('Internal error: unexpected action at ground level', action);
break;
}
};
///////////////////////////////////////////////////////////////////////////
module.exports.Ground = Ground;

View File

@ -26,12 +26,11 @@ copyKeys(['emptyPatch',
'observe', 'atMeta', 'advertise',
'isObserve', 'isAtMeta', 'isAdvertise',
'assert', 'retract', 'sub', 'unsub', 'pub', 'unpub',
'patchSeq',
'prettyPatch'],
'patchSeq'],
module.exports,
module.exports.Patch);
// module.exports.Ground = require("./ground.js").Ground;
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;

View File

@ -87,7 +87,7 @@ function computeAffectedPids(routingTable, delta) {
Mux.prototype.routeMessage = function (body) {
if (Route.matchValue(this.routingTable, body) === null) {
return Route.matchValue(m.routingTable, Patch.observe(body)) || Immutable.Set();
return Route.matchValue(this.routingTable, Patch.observe(body)) || Immutable.Set();
} else {
// Some other stream has declared body
return Immutable.Set();

View File

@ -206,9 +206,9 @@ Patch.prototype.projectObjects = function (compiledProjection) {
Route.projectObjects(this.removed, compiledProjection)];
};
function prettyPatch(p) {
return ("<<<<<<<< Removed:\n" + Route.prettyTrie(p.removed) +
"======== Added:\n" + Route.prettyTrie(p.added) +
Patch.prototype.pretty = function () {
return ("<<<<<<<< Removed:\n" + Route.prettyTrie(this.removed) +
"======== Added:\n" + Route.prettyTrie(this.added) +
">>>>>>>>\n");
}
@ -240,4 +240,3 @@ module.exports.unpub = unpub;
module.exports.patchSeq = patchSeq;
module.exports.computePatch = computePatch;
module.exports.biasedIntersection = biasedIntersection;
module.exports.prettyPatch = prettyPatch;

View File

@ -101,37 +101,43 @@ Network.exit = function (exn) {
Network.current().kill(Network.activePid(), exn);
};
Network.terminateNetwork = function () {
Network.exitNetwork = function () {
Network.enqueueAction(terminateNetwork());
};
Network.inertBehavior = {
handleEvent: function (e) {}
};
// Instance methods
Network.prototype.asChild = function (pid, f, omitLivenessCheck) {
var self = this;
var p = this.processTable.get(pid, null);
if (!omitLivenessCheck && (p === null)) {
console.warn("Network.asChild eliding invocation of dead process", pid);
return;
}
return Network.withWorldStack(Network.stack.push({ network: this, activePid: pid }),
function () {
try {
return f(p);
} catch (e) {
this.kill(pid, e);
}
});
return Network.withNetworkStack(
Network.stack.push({ network: this, activePid: pid }),
function () {
try {
return f(p);
} catch (e) {
self.kill(pid, e);
}
});
};
Network.prototype.kill = function (pid, exn) {
if (exn && exn.stack) {
console.log("Process exited", pid, exn, exn.stack);
console.log("Process exiting", pid, exn, exn.stack);
} else {
console.log("Process exited", pid, exn);
console.log("Process exiting", pid, exn);
}
var p = this.processTable.get(pid);
this.processTable = this.processTable.remove(pid);
this.processTable = this.processTable.set(pid, { behavior: Network.inertBehavior });
if (p) {
if (p.behavior.trapexit) {
this.asChild(pid, function () { return p.behavior.trapexit(exn); }, true);
@ -172,13 +178,14 @@ Network.prototype.enqueueAction = function (pid, action) {
};
Network.prototype.dispatchActions = function () {
var self = this;
var actionQueue = this.pendingActions;
this.pendingActions = Immutable.List();
var alive = true;
actionQueue.forEach(function (entry) {
var pid = entry[0];
var action = entry[1];
if (!this.interpretAction(pid, action)) {
if (!self.interpretAction(pid, action)) {
alive = false;
return false;
}
@ -191,19 +198,22 @@ Network.prototype.markRunnable = function (pid) {
};
Network.prototype.runRunnablePids = function () {
var self = this;
var pidSet = this.runnablePids;
this.runnablePids = Immutable.Set();
pidSet.forEach(function (pid) {
var childBusy = this.asChild(pid, function (p) {
var childBusy = self.asChild(pid, function (p) {
return p.behavior.step // exists, haven't called it yet
&& p.behavior.step();
});
if (childBusy) this.markRunnable(pid);
if (childBusy) self.markRunnable(pid);
});
return true;
};
Network.prototype.interpretAction = function (pid, action) {
var self = this;
switch (action.type) {
case 'stateChange':
var oldMux = this.mux.shallowCopy();
@ -218,7 +228,7 @@ Network.prototype.interpretAction = function (pid, action) {
Network.send(action.message[1]);
} else {
this.mux.routeMessage(action.message).forEach(function (pid) {
this.deliverEvent(pid, action);
self.deliverEvent(pid, action);
});
}
return true;
@ -240,6 +250,8 @@ Network.prototype.interpretAction = function (pid, action) {
case 'terminate':
var oldMux = this.mux.shallowCopy();
this.deliverPatches(oldMux, this.mux.removeStream(pid));
console.log("Process exit complete", pid);
this.processTable = this.processTable.remove(pid);
return true;
case 'terminateNetwork':
@ -254,15 +266,16 @@ Network.prototype.interpretAction = function (pid, action) {
};
Network.prototype.deliverPatches = function (oldMux, updateStreamResult) {
var self = this;
var events = Mux.computeEvents(oldMux, this.mux, updateStreamResult);
events.eventMap.forEach(function (patch, pid) {
this.deliverEvent(pid, stateChange(patch));
self.deliverEvent(pid, stateChange(patch));
});
events.metaEvents.forEach(Network.stateChange);
};
Network.prototype.deliverEvent = function (pid, event) {
var childBusy = this.asChild(pid, function (p) { return p.handleEvent(event); });
var childBusy = this.asChild(pid, function (p) { return p.behavior.handleEvent(event); });
if (childBusy) this.markRunnable(pid);
};

View File

@ -13,7 +13,7 @@ function checkPrettyTrie(m, expected) {
}
function checkPrettyPatch(p, expectedAdded, expectedRemoved) {
expect(Patch.prettyPatch(p)).to.equal(
expect(p.pretty()).to.equal(
('<<<<<<<< Removed:\n' + expectedRemoved.join('\n') +
'======== Added:\n' + expectedAdded.join('\n') +
'>>>>>>>>\n'));

View File

@ -8,7 +8,7 @@ var __ = Route.__;
var _$ = Route._$;
function checkPrettyPatch(p, expectedAdded, expectedRemoved) {
expect(Patch.prettyPatch(p)).to.equal(
expect(p.pretty()).to.equal(
('<<<<<<<< Removed:\n' + expectedRemoved.join('\n') +
'======== Added:\n' + expectedAdded.join('\n') +
'>>>>>>>>\n'));