From ec6b7710d30dedb3b55a44bd24ecebf152ce4713 Mon Sep 17 00:00:00 2001 From: Gubolin Date: Fri, 6 Mar 2015 20:26:02 +0100 Subject: first working version of p2p cloud variables --- objects.js | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) (limited to 'objects.js') diff --git a/objects.js b/objects.js index 1fe1309..71519f6 100644 --- a/objects.js +++ b/objects.js @@ -1176,6 +1176,19 @@ SpriteMorph.prototype.initBlocks = function () { defaults: [localize('each item')] }, + // peer to peer communication + receivePeerMessage: { + type: 'hat', + category: 'other', + spec: 'when I receive %upvar from %upvar', + defaults: [localize('message'), localize('peer')] + }, + sendPeerMessage: { + type: 'command', + category: 'other', + spec: 'send %s to %s' + }, + // Code mapping - experimental doMapCodeOrHeader: { // experimental type: 'command', @@ -2103,6 +2116,11 @@ SpriteMorph.prototype.blockTemplates = function (category) { blocks.push('='); + blocks.push(block('receivePeerMessage')); + blocks.push(block('sendPeerMessage')); + + blocks.push('='); + if (StageMorph.prototype.enableCodeMapping) { blocks.push(block('doMapCodeOrHeader')); blocks.push(block('doMapStringCode')); @@ -3517,6 +3535,9 @@ SpriteMorph.prototype.allHatBlocksFor = function (message) { if (morph.selector === 'receiveOnClone') { return message === '__clone__init__'; } + if (morph.selector === 'receivePeerMessage') { + return message === '__peer__message__'; + } } return false; }); @@ -4386,8 +4407,62 @@ StageMorph.prototype.init = function (globals) { this.acceptsDrops = false; this.setColor(new Color(255, 255, 255)); this.fps = this.frameRate; + + this.peer = new Peer({ + host: 'snapmesh.herokuapp.com', + port: 80, + path: '/' + }); + var myself = this; + + this.peer.on('open', function (id) { + myself.peerId = id; + console.log('Id: ' + id); // DEBUG + }); + + this.peer.on('connection', function (connection) { + connection.on('open', function () { + connection.on('data', function (data) { + var hats = []; + // call hat blocks + myself.children.concat(myself).forEach(function (morph) { + if (morph instanceof SpriteMorph + || morph instanceof StageMorph) { + hats = hats.concat( + morph.allHatBlocksFor('__peer__message__')); + } + }); + hats.forEach(function (block) { + var process = myself.threads.startProcess(block, + myself.isThreadSafe); + process.context.outerContext.variables.addVar('message'); + process.context.outerContext.variables.setVar( + 'message', + data + ); + process.context.outerContext.variables.addVar('peer'); + process.context.outerContext.variables.setVar( + 'peer', + connection.peer + ); + }); + }); + }); + }); }; +// peer to peer communication + +SpriteMorph.prototype.sendPeerMessage = function (message, peer) { + var stage = this.parentThatIsA(StageMorph); + var connection = stage.peer.connect(peer, {reliable: true}); + connection.on('open', function () { + connection.send(message); + }); +}; + +StageMorph.prototype.sendPeerMessage = SpriteMorph.prototype.sendPeerMessage; + // StageMorph scaling StageMorph.prototype.setScale = function (number) { @@ -5305,6 +5380,10 @@ StageMorph.prototype.blockTemplates = function (category) { blocks.push('='); + blocks.push(block('receivePeerMessage')); + blocks.push(block('sendPeerMessage')); + blocks.push('='); + if (StageMorph.prototype.enableCodeMapping) { blocks.push(block('doMapCodeOrHeader')); blocks.push(block('doMapStringCode')); -- cgit v1.3.1 From cdf8ce4e14f7c8fc12b519df8b4f5e1b33b67e60 Mon Sep 17 00:00:00 2001 From: Gubolin Date: Sat, 7 Mar 2015 19:25:18 +0100 Subject: send lists and blocks via "send" --- objects.js | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'objects.js') diff --git a/objects.js b/objects.js index 71519f6..9fc4808 100644 --- a/objects.js +++ b/objects.js @@ -4423,7 +4423,17 @@ StageMorph.prototype.init = function (globals) { this.peer.on('connection', function (connection) { connection.on('open', function () { connection.on('data', function (data) { - var hats = []; + var ide = myself.parentThatIsA(IDE_Morph); + var hats = [], model, message; + try { + model = ide.serializer.parse(data); + message = ide.serializer.loadValue(model); + } catch (err) { + console.log(err); // DEBUG + // Ok, it does not seem to be XML. It must be a string then. + message = data; + } + // call hat blocks myself.children.concat(myself).forEach(function (morph) { if (morph instanceof SpriteMorph @@ -4438,7 +4448,7 @@ StageMorph.prototype.init = function (globals) { process.context.outerContext.variables.addVar('message'); process.context.outerContext.variables.setVar( 'message', - data + message ); process.context.outerContext.variables.addVar('peer'); process.context.outerContext.variables.setVar( @@ -4454,10 +4464,19 @@ StageMorph.prototype.init = function (globals) { // peer to peer communication SpriteMorph.prototype.sendPeerMessage = function (message, peer) { - var stage = this.parentThatIsA(StageMorph); + var stage = this.parentThatIsA(StageMorph), + ide = this.parentThatIsA(IDE_Morph); var connection = stage.peer.connect(peer, {reliable: true}); connection.on('open', function () { - connection.send(message); + var data; + if (typeof message == "string") { + data = message; + } else if (typeof message == "function") { + data = message.toString(); + } else { + data = ide.serializer.serialize(message); + } + connection.send(data); }); }; -- cgit v1.3.1 From b83d4d83bf521b34b878662c7f145cc9286f096a Mon Sep 17 00:00:00 2001 From: Gubolin Date: Sat, 7 Mar 2015 19:28:18 +0100 Subject: add Todo with workaround --- objects.js | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'objects.js') diff --git a/objects.js b/objects.js index 9fc4808..116c792 100644 --- a/objects.js +++ b/objects.js @@ -4428,6 +4428,12 @@ StageMorph.prototype.init = function (globals) { try { model = ide.serializer.parse(data); message = ide.serializer.loadValue(model); + + // TODO: If a Context is sent, a new Sprite appears. + // This below is just a workaround for one-level rings, + // objects should be cleaned recursively. + message.receiver = null; + message.outerContext = null; } catch (err) { console.log(err); // DEBUG // Ok, it does not seem to be XML. It must be a string then. -- cgit v1.3.1 From 53936404d5c8ed7a6433e8e9f71c235d34b477b9 Mon Sep 17 00:00:00 2001 From: Gubolin Date: Sun, 8 Mar 2015 09:28:56 +0100 Subject: rewrite peering flow; add peer id blocks --- gui.js | 2 + objects.js | 142 ++++++++++++++++++++++++++++++++++++------------------------- threads.js | 41 ++++++++++++++++++ 3 files changed, 126 insertions(+), 59 deletions(-) (limited to 'objects.js') diff --git a/gui.js b/gui.js index 75220b3..1f51405 100644 --- a/gui.js +++ b/gui.js @@ -245,6 +245,8 @@ IDE_Morph.prototype.init = function (isAutoFill) { // override inherited properites: this.color = this.backgroundColor; + + window.peers = []; }; IDE_Morph.prototype.openIn = function (world) { diff --git a/objects.js b/objects.js index 116c792..9399269 100644 --- a/objects.js +++ b/objects.js @@ -1188,6 +1188,16 @@ SpriteMorph.prototype.initBlocks = function () { category: 'other', spec: 'send %s to %s' }, + reportPeerId: { + type: 'reporter', + category: 'other', + spec: 'my peer id' + }, + reportPeerList: { + type: 'reporter', + category: 'other', + spec: 'peers online' + }, // Code mapping - experimental doMapCodeOrHeader: { // experimental @@ -2118,6 +2128,8 @@ SpriteMorph.prototype.blockTemplates = function (category) { blocks.push(block('receivePeerMessage')); blocks.push(block('sendPeerMessage')); + blocks.push(block('reportPeerId')); + blocks.push(block('reportPeerList')); blocks.push('='); @@ -4408,86 +4420,96 @@ StageMorph.prototype.init = function (globals) { this.setColor(new Color(255, 255, 255)); this.fps = this.frameRate; - this.peer = new Peer({ + this.initPeering(); +}; + +StageMorph.prototype.initPeering = function (id) { + var myself = this; + + if (window.peers) { + // I don't know why, but it works. + window.peers.forEach(function (oldpeer) { + if (id != oldpeer.id) { + oldpeer.destroy() + } + }); + } + + this.peer = new Peer(id, { host: 'snapmesh.herokuapp.com', - port: 80, + port: 443, + secure: true, path: '/' }); - var myself = this; this.peer.on('open', function (id) { myself.peerId = id; - console.log('Id: ' + id); // DEBUG + }); + this.peer.on('disconnected', function () { + // peer.reconnect does not work (?) because 'id' is undefined + if (!myself.peer.destroyed) { + myself.initPeering(myself.peerId); + } + }); + this.peer.on('error', function (err) { + console.log(err); // DEBUG }); this.peer.on('connection', function (connection) { connection.on('open', function () { connection.on('data', function (data) { - var ide = myself.parentThatIsA(IDE_Morph); - var hats = [], model, message; - try { - model = ide.serializer.parse(data); - message = ide.serializer.loadValue(model); - - // TODO: If a Context is sent, a new Sprite appears. - // This below is just a workaround for one-level rings, - // objects should be cleaned recursively. - message.receiver = null; - message.outerContext = null; - } catch (err) { - console.log(err); // DEBUG - // Ok, it does not seem to be XML. It must be a string then. - message = data; - } - - // call hat blocks - myself.children.concat(myself).forEach(function (morph) { - if (morph instanceof SpriteMorph - || morph instanceof StageMorph) { - hats = hats.concat( - morph.allHatBlocksFor('__peer__message__')); - } - }); - hats.forEach(function (block) { - var process = myself.threads.startProcess(block, - myself.isThreadSafe); - process.context.outerContext.variables.addVar('message'); - process.context.outerContext.variables.setVar( - 'message', - message - ); - process.context.outerContext.variables.addVar('peer'); - process.context.outerContext.variables.setVar( - 'peer', - connection.peer - ); - }); + myself.newPeerMessage(data, connection.peer); }); }); }); + + window.peers.push(this.peer); }; -// peer to peer communication +StageMorph.prototype.newPeerMessage = function (data, peer) { + var ide = this.parentThatIsA(IDE_Morph); + var myself = this; + var hats = [], model, message; -SpriteMorph.prototype.sendPeerMessage = function (message, peer) { - var stage = this.parentThatIsA(StageMorph), - ide = this.parentThatIsA(IDE_Morph); - var connection = stage.peer.connect(peer, {reliable: true}); - connection.on('open', function () { - var data; - if (typeof message == "string") { - data = message; - } else if (typeof message == "function") { - data = message.toString(); - } else { - data = ide.serializer.serialize(message); + try { + model = ide.serializer.parse(data); + message = ide.serializer.loadValue(model); + + // TODO: If a Context is sent, a new Sprite appears. + // This below is just a workaround for one-level rings, + // objects should be cleaned recursively. + message.receiver = null; + message.outerContext = null; + } catch (err) { + console.log(err); // DEBUG + // Ok, it does not seem to be XML. It must be a string then. + message = data; + } + + // call hat blocks + this.children.concat(myself).forEach(function (morph) { + if (morph instanceof SpriteMorph + || morph instanceof StageMorph) { + hats = hats.concat( + morph.allHatBlocksFor('__peer__message__')); } - connection.send(data); + }); + hats.forEach(function (block) { + var process = myself.threads.startProcess(block, + myself.isThreadSafe); + process.context.outerContext.variables.addVar('message'); + process.context.outerContext.variables.setVar( + 'message', + message + ); + process.context.outerContext.variables.addVar('peer'); + process.context.outerContext.variables.setVar( + 'peer', + peer + ); }); }; -StageMorph.prototype.sendPeerMessage = SpriteMorph.prototype.sendPeerMessage; - // StageMorph scaling StageMorph.prototype.setScale = function (number) { @@ -5407,6 +5429,8 @@ StageMorph.prototype.blockTemplates = function (category) { blocks.push(block('receivePeerMessage')); blocks.push(block('sendPeerMessage')); + blocks.push(block('reportPeerId')); + blocks.push(block('reportPeerList')); blocks.push('='); if (StageMorph.prototype.enableCodeMapping) { diff --git a/threads.js b/threads.js index 50af8dd..bc8e429 100644 --- a/threads.js +++ b/threads.js @@ -1295,6 +1295,47 @@ Process.prototype.doRemoveTemporaries = function () { } }; +// Peer to peer primitives + +Process.prototype.sendPeerMessage = function (message, peer) { + var stage = this.homeContext.receiver.parentThatIsA(StageMorph), + ide = this.homeContext.receiver.parentThatIsA(IDE_Morph); + var connection = stage.peer.connect(peer, {reliable: true}); + connection.on('open', function () { + var data; + if (typeof message == "string") { + data = message; + } else if (typeof message == "function") { + data = message.toString(); + } else { + data = ide.serializer.serialize(message); + } + connection.send(data); + }); +}; + +Process.prototype.reportPeerList = function () { + var myself = this; + + if (!this.context.wait) { + var stage = this.homeContext.receiver.parentThatIsA(StageMorph); + stage.peer.listAllPeers(function (peers) { + myself.context.result = new List(peers); + }); + this.context.wait = true; + } else if (this.context.result) { + return this.context.result; + } + + this.pushContext('doYield'); + this.pushContext(); +}; + +Process.prototype.reportPeerId = function () { + var stage = this.homeContext.receiver.parentThatIsA(StageMorph); + return stage.peerId; +}; + // Process lists primitives Process.prototype.reportNewList = function (elements) { -- cgit v1.3.1 From da6c1a37a3f760ec787299f5a7f2bbf1a149acf5 Mon Sep 17 00:00:00 2001 From: Gubolin Date: Sun, 8 Mar 2015 09:44:41 +0100 Subject: fix localization bug; accept lists as peer message receiver --- objects.js | 8 ++++---- threads.js | 9 +++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'objects.js') diff --git a/objects.js b/objects.js index 9399269..282d01f 100644 --- a/objects.js +++ b/objects.js @@ -4497,14 +4497,14 @@ StageMorph.prototype.newPeerMessage = function (data, peer) { hats.forEach(function (block) { var process = myself.threads.startProcess(block, myself.isThreadSafe); - process.context.outerContext.variables.addVar('message'); + process.context.outerContext.variables.addVar(localize('message')); process.context.outerContext.variables.setVar( - 'message', + localize('message'), message ); - process.context.outerContext.variables.addVar('peer'); + process.context.outerContext.variables.addVar(localize('peer')); process.context.outerContext.variables.setVar( - 'peer', + localize('peer'), peer ); }); diff --git a/threads.js b/threads.js index bc8e429..2d1ce77 100644 --- a/threads.js +++ b/threads.js @@ -1298,6 +1298,15 @@ Process.prototype.doRemoveTemporaries = function () { // Peer to peer primitives Process.prototype.sendPeerMessage = function (message, peer) { + var myself = this; + + if (peer instanceof List) { + peer.asArray().forEach(function (singlePeer) { + myself.sendPeerMessage(message, singlePeer); + }); + return; + } + var stage = this.homeContext.receiver.parentThatIsA(StageMorph), ide = this.homeContext.receiver.parentThatIsA(IDE_Morph); var connection = stage.peer.connect(peer, {reliable: true}); -- cgit v1.3.1