diff --git a/js/examples/dom-webworker/Makefile b/js/examples/dom-webworker/Makefile new file mode 100644 index 0000000..34717b3 --- /dev/null +++ b/js/examples/dom-webworker/Makefile @@ -0,0 +1,7 @@ +all: index.expanded.js worker.expanded.js + +%.expanded.js: %.js + ../../bin/syndicatec $< > $@ || (rm -f $@; false) + +clean: + rm -f *.expanded.js diff --git a/js/examples/dom-webworker/index.html b/js/examples/dom-webworker/index.html new file mode 100644 index 0000000..6b5f389 --- /dev/null +++ b/js/examples/dom-webworker/index.html @@ -0,0 +1,15 @@ + + + + Syndicate: DOM WebWorker Example + + + + + +

DOM WebWorker example

+
+
+

+  
+
diff --git a/js/examples/dom-webworker/index.js b/js/examples/dom-webworker/index.js
new file mode 100644
index 0000000..f5f396b
--- /dev/null
+++ b/js/examples/dom-webworker/index.js
@@ -0,0 +1,22 @@
+document.addEventListener('DOMContentLoaded', function () {
+  ground dataspace G {
+    Syndicate.UI.spawnUIDriver();
+
+    spawn {
+      var ui = new Syndicate.UI.Anchor();
+      during Syndicate.observe('bump_count') { // wait for the worker to boot and start listening
+        assert ui.html('#clicker-holder',
+                       '');
+      }
+      on message Syndicate.UI.globalEvent('#clicker-holder > button', 'click', _) {
+        :: 'bump_count';
+      }
+    }
+
+    Syndicate.Dataspace.spawn(new Syndicate.Worker('worker.expanded.js'));
+  }
+
+  G.dataspace.setOnStateChange(function (mux, patch) {
+    document.getElementById('spy-holder').innerText = Syndicate.prettyTrie(mux.routingTable);
+  });
+});
diff --git a/js/examples/dom-webworker/worker.js b/js/examples/dom-webworker/worker.js
new file mode 100644
index 0000000..ffb8722
--- /dev/null
+++ b/js/examples/dom-webworker/worker.js
@@ -0,0 +1,19 @@
+importScripts("../../dist/syndicate.js");
+
+var G = new Syndicate.WorkerGround(function () {
+  spawn {
+    var ui = new Syndicate.UI.Anchor();
+    field this.counter = 0;
+
+    assert ui.html('#counter-holder', '

The current count is: '+this.counter+'

') + metalevel 1; + + on message 'bump_count' + metalevel 1 + { + this.counter++; + } + } +}); + +G.startStepping(); diff --git a/js/src/main.js b/js/src/main.js index df6e1e8..1d363f7 100644 --- a/js/src/main.js +++ b/js/src/main.js @@ -48,6 +48,6 @@ module.exports.Actor = require("./actor.js"); // module.exports.Spy = require("./spy.js").Spy; // module.exports.WakeDetector = require("./wake-detector.js").WakeDetector; -// var Worker = require("./worker.js"); -// module.exports.Worker = Worker.Worker; -// module.exports.WorkerGround = Worker.WorkerGround; +var Worker = require("./worker.js"); +module.exports.Worker = Worker.Worker; +module.exports.WorkerGround = Worker.WorkerGround; diff --git a/js/src/randomid.js b/js/src/randomid.js index 52473e3..9458679 100644 --- a/js/src/randomid.js +++ b/js/src/randomid.js @@ -1,11 +1,10 @@ var randomId; -if ((typeof window !== 'undefined') && - (typeof window.crypto !== 'undefined') && - (typeof window.crypto.getRandomValues !== 'undefined')) { +function browserCryptoObject(crypto) { + if (typeof crypto.getRandomValues === 'undefined') return false; randomId = function (byteCount, hexOutput) { var buf = new Uint8Array(byteCount); - window.crypto.getRandomValues(buf); + crypto.getRandomValues(buf); if (hexOutput) { var encoded = []; for (var i = 0; i < buf.length; i++) { @@ -17,7 +16,24 @@ if ((typeof window !== 'undefined') && return btoa(String.fromCharCode.apply(null, buf)).replace(/=/g,''); } }; + return true; +} + +if ((typeof window !== 'undefined') && + (typeof window.crypto !== 'undefined') && + browserCryptoObject(window.crypto)) { + // We are in the main page, and window.crypto is available, and + // browserCryptoObject has installed a suitable randomId. Do + // nothing. +} else if ((typeof self !== 'undefined') && + (typeof self.crypto !== 'undefined') && + browserCryptoObject(self.crypto)) { + // We are in a web worker, and self.crypto is available, and + // browserCryptoObject has installed a suitable randomId. Do + // nothing. } else { + // See if we're in node.js. + var crypto; try { crypto = require('crypto'); diff --git a/js/src/worker.js b/js/src/worker.js new file mode 100644 index 0000000..858b8f7 --- /dev/null +++ b/js/src/worker.js @@ -0,0 +1,52 @@ +/* Web Worker interface */ +var Ground = require("./ground.js").Ground; +var Util = require("./util.js"); +var Codec = require("./codec.js"); + +var Dataspace = require("./dataspace.js").Dataspace; + +var BuiltinWorker = typeof window !== 'undefined' && window.Worker; + +/////////////////////////////////////////////////////////////////////////// + +function Worker(scriptUrl) { + this.scriptUrl = scriptUrl; + this.w = new BuiltinWorker(scriptUrl); +} + +Worker.prototype.boot = function () { + this.w.onmessage = Dataspace.wrap(function (e) { + console.log("Received from worker", JSON.stringify(e.data)); + Dataspace.enqueueAction(Codec.decodeAction(e.data)); + }); +}; + +Worker.prototype.handleEvent = function (e) { + console.log("Sending to worker", JSON.stringify(Codec.encodeEvent(e))); + this.w.postMessage(Codec.encodeEvent(e)); +}; + +/////////////////////////////////////////////////////////////////////////// + +function WorkerGround(bootFn) { + var self = this; + Ground.call(this, bootFn); + onmessage = function (e) { + console.log("Received from main page", JSON.stringify(e.data)); + self.dataspace.handleEvent(Codec.decodeEvent(e.data)); + self.startStepping(); + }; +} + +WorkerGround.prototype = Util.extend({}, Ground.prototype); + +WorkerGround.prototype.enqueueAction = function (pid, action) { + console.log("Sending to main page", JSON.stringify(Codec.encodeAction(action))); + postMessage(Codec.encodeAction(action)); + console.log("Sent to main page"); +}; + +/////////////////////////////////////////////////////////////////////////// + +module.exports.Worker = Worker; +module.exports.WorkerGround = WorkerGround;