From 1600bb2bc8ee406e9a9f11654b0192c544a0a523 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 12 Mar 2018 15:50:37 -0700 Subject: [PATCH 1/6] wire mesh --- examples/http.js | 1 + gun.js | 303 ++++++++++++++++++++++++++++++++------------- lib/debug.js | 3 +- lib/server.js | 3 +- lib/store.js | 14 ++- lib/wire.js | 91 ++++++++++++++ lib/ws.js | 2 + test/gun.html | 5 + test/panic/load.js | 2 +- test/ptsd/spam.js | 51 ++++---- 10 files changed, 361 insertions(+), 114 deletions(-) create mode 100644 lib/wire.js create mode 100644 test/gun.html diff --git a/examples/http.js b/examples/http.js index 637ed36d..d2dca8d5 100644 --- a/examples/http.js +++ b/examples/http.js @@ -16,6 +16,7 @@ var server = require('http').createServer(function(req, res){ var gun = Gun({ file: 'data.json', web: server, + localStorage: false, s3: { key: process.env.AWS_ACCESS_KEY_ID, // Use environment variables secret: process.env.AWS_SECRET_ACCESS_KEY, // so your keys are not diff --git a/gun.js b/gun.js index 8c49d684..bb223305 100644 --- a/gun.js +++ b/gun.js @@ -621,21 +621,25 @@ function Dup(opt){ var dup = {s:{}}; opt = opt || {max: 1000, age: 1000 * 9};//1000 * 60 * 2}; - dup.check = function(id){ - return dup.s[id]? dup.track(id) : false; + dup.check = function(id){ var tmp; + if(!(tmp = dup.s[id])){ return false } + if(tmp.pass){ return tmp.pass = false } + return dup.track(id); } - dup.track = function(id){ - dup.s[id] = time_is(); + dup.track = function(id, pass){ + var it = dup.s[id] || (dup.s[id] = {}); + it.was = time_is(); + if(pass){ it.pass = true } if(!dup.to){ dup.to = setTimeout(function(){ - Type.obj.map(dup.s, function(time, id){ - if(opt.age > (time_is() - time)){ return } + Type.obj.map(dup.s, function(it, id){ + if(opt.age > (time_is() - it.was)){ return } Type.obj.del(dup.s, id); }); dup.to = null; }, opt.age); } - return id; + return it; } return dup; } @@ -685,13 +689,13 @@ return gun; } function root(msg){ - //console.log("add to.next(at)"); // TODO: BUG!!! - var ev = this, at = ev.as, gun = at.gun, tmp; + //console.log("add to.next(at)"); // TODO: MISSING FEATURE!!! + var ev = this, at = ev.as, gun = at.gun, dup, tmp; //if(!msg.gun){ msg.gun = at.gun } if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) } - if(at.dup.check(tmp)){ return } - at.dup.track(tmp); - msg = obj_to(msg);//, {gun: at.gun}); + if((dup = at.dup).check(tmp)){ return } + dup.track(tmp); + //msg = obj_to(msg);//, {gun: at.gun}); // can we delete this now? if(!at.ask(msg['@'], msg)){ if(msg.get){ Gun.on.get(msg, gun); @@ -804,7 +808,7 @@ //tmp = at.ack; root.on('in', { '@': msg['#'], - //how: 'mem', + how: 'mem', by: root.PID, put: node, gun: gun }); @@ -831,6 +835,7 @@ } at.opt.peers = at.opt.peers || {}; obj_to(opt, at.opt); // copies options on to `at.opt` only if not already taken. + at.PID = at.PID || Gun.log(Gun.text.random(2)); Gun.on('opt', at); at.opt.uuid = at.opt.uuid || function(){ return state_lex() + text_rand(12) } return gun; @@ -940,7 +945,7 @@ }*/ if(get['#'] || at.soul){ get['#'] = get['#'] || at.soul; - msg['#'] || (msg['#'] = text_rand()); + msg['#'] || (msg['#'] = text_rand(9)); back = (root.gun.get(get['#'])._); if(!(get = get['.'])){ if(obj_has(back, 'put')){ @@ -1555,6 +1560,10 @@ } Gun.chain.val = function(cb, opt){ + Gun.log.once("onceval", "Future Breaking API Change: .val -> .once, apologies unexpected."); + return this.once(cb, opt); + } + Gun.chain.once = function(cb, opt){ var gun = this, at = gun._, data = at.put; if(0 < at.ack && u !== data){ (cb || noop).call(gun, data, at.get); @@ -1569,7 +1578,7 @@ } else { Gun.log.once("valonce", "Chainable val is experimental, its behavior and API may change moving forward. Please play with it and report bugs and ideas on how to improve it."); var chain = gun.chain(); - chain._.val = gun.val(function(){ + chain._.val = gun.once(function(){ chain._.on('in', gun._); }); return chain; @@ -1781,6 +1790,7 @@ try{store.setItem(opt.file, JSON.stringify(disk)); }catch(e){ Gun.log(err = e || "localStorage failure") } if(!err && !Gun.obj.empty(opt.peers)){ return } // only ack if there are no peers. + console.log("@@@", ack); Gun.obj.map(ack, function(yes, id){ root.on('in', { '@': id, @@ -1793,105 +1803,226 @@ })(USE, './adapters/localStorage'); ;USE(function(module){ - var Gun = USE('./index'); - var websocket; - if(typeof WebSocket !== 'undefined'){ - websocket = WebSocket; - } else { - if(typeof webkitWebSocket !== 'undefined'){ - websocket = webkitWebSocket; + var Type = USE('./type'); + + function Mesh(ctx){ + var mesh = function(){}; + + mesh.out = function(msg){ var tmp; + if(this.to){ this.to.next(msg) } + if((tmp = msg['@']) + && (tmp = ctx.dup.s[tmp]) + && (tmp = tmp.it)){ + mesh.say(msg, tmp.mesh.via); + tmp['##'] = msg['##']; + return; + } + // add hook for AXE? + mesh.say(msg); } - if(typeof mozWebSocket !== 'undefined'){ - websocket = mozWebSocket; + + mesh.hear = function(msg, peer){ + if(!msg){ return } + var dup = ctx.dup, id, hash, tmp = msg[0]; + try{msg = JSON.parse(msg); + }catch(e){} + if('{' === tmp){ + + if(dup.check(id = msg['#'])){ return } + dup.track(id, true).it = msg; // GUN core also dedups, so `true` is needed. + if((tmp = msg['@']) && msg.put){ + hash = msg['##'] || (msg['##'] = mesh.hash(msg)); + if((tmp = tmp + hash) != id){ + if(dup.check(tmp)){ return } + (tmp = dup.s)[hash] = tmp[id]; + } + } + (msg.mesh = function(){}).via = peer; + if((tmp = msg['><'])){ + msg.mesh.to = Type.obj.map(tmp.split(','), function(k,i,m){m(k,true)}); + } + ctx.on('in', msg); + + return; + } else + if('[' === tmp){ + + var i = 0, m; + while(m = msg[i++]){ + mesh.hear(m, peer); + } + + return; + } } + + mesh.say = function(msg, peer){ + /* + TODO: Plenty of performance optimizations + that can be made just based off of ordering, + and reducing function calls for cached writes. + */ + if(!peer){ + Type.obj.map(ctx.opt.peers, function(peer){ + mesh.say(msg, peer); + }); + return; + } + var tmp, wire = peer.wire || ((ctx.opt.wire) && ctx.opt.wire(peer)), msh, raw;// || open(peer, ctx); // TODO: Reopen! + if(!wire){ return } + msh = msg.mesh || empty; + if(peer === msh.via){ return } + if(!(raw = msh.raw)){ raw = mesh.raw(msg) } + if((tmp = msg['@']) + && (tmp = ctx.dup.s[tmp]) + && (tmp = tmp.it)){ + if(tmp.get && tmp['##'] && tmp['##'] === msg['##']){ // PERF: move this condition outside say? + return; // TODO: this still needs to be tested in the browser! + } + } + if((tmp = msh.to) && (tmp[peer.url] || tmp[peer.id])){ return } // TODO: still needs to be tested + try{ + if(wire.send){ + wire.send(raw); + } else + if(peer.say){ + peer.say(raw); + } + }catch(e){ + (peer.queue = peer.queue || []).push(raw); + } + } + + ;(function(){ + + mesh.raw = function(msg){ + if(!msg){ return '' } + var dup = ctx.dup, msh = msg.mesh || {}, put, hash, tmp; + if(tmp = msh.raw){ return tmp } + if(typeof msg === 'string'){ return msg } + if(msg['@'] && (tmp = msg.put)){ + if(!(hash = msg['##'])){ + put = $(tmp, sort) || ''; + hash = mesh.hash(msg, put); + msg['##'] = hash; + } + (tmp = dup.s)[hash = msg['@']+hash] = tmp[msg['#']]; + msg['#'] = hash; + if(put){ (msg = Type.obj.to(msg)).put = _ } + } + msg['><'] = (Type.obj.map(ctx.opt.peers, function(p,k,m){ + m(p.url || p.id); + }) || []).join(); + var raw = $(msg); + if(u !== put){ + raw = raw.replace('"'+ _ +'"', put); + } + if(msh){ + msh.raw = raw; + } + return raw; + } + + mesh.hash = function(msg, hash){ + return Mesh.hash(hash || $(msg.put, sort) || '') || msg['#'] || Type.text.random(9); + } + + function sort(k, v){ var tmp; + if(!(v instanceof Object)){ return v } + Type.obj.map(Object.keys(v).sort(), map, {to: tmp = {}, on: v}); + return tmp; + } + + function map(k){ + this.to[k] = this.on[k]; + } + var $ = JSON.stringify, _ = ':])([:' + + }()); + + mesh.hi = function(peer){ + ctx.on('hi', peer); + var queue = peer.queue; + peer.queue = []; + Type.obj.map(queue, function(msg){ + mesh.say(msg, peer); + }); + } + + return mesh; } + Mesh.hash = function(s){ // via SO + if(typeof s !== 'string'){ return {err: 1} } + var c = 0; + if(!s.length){ return c } + for(var i=0,l=s.length,n; i'+Radisk.encode(Gun.state.is(node, key)); - rad(soul+'.'+key, val, (u === acks? u : ack)); + rad(soul+'.'+key, val, (track? ack : u)); }); function ack(err, ok){ acks--; @@ -30,7 +36,7 @@ Gun.on('opt', function(ctx){ return; } if(acks){ return } - ctx.on('in', {'@': id, ok: 1}); + ctx.on('in', {'@': id, ok: 1, RSE: 1}); } }); diff --git a/lib/wire.js b/lib/wire.js new file mode 100644 index 00000000..3daeaa8a --- /dev/null +++ b/lib/wire.js @@ -0,0 +1,91 @@ +var Gun = require('../gun'); + +/* + An Ad-Hoc Mesh-Network Daisy-Chain + should work even if humans are + communicating with each other blind. + + To prevent infinite broadcast loops, + we use a deduplication process + based on the message's identifier. + This is currently implemented in core. + + However, because this still creates a + N*2 (where N is the number of connections) + flood, it is not scalable for traditional + services that have a hub network topology. + + Does this mean we have to abandon mesh + algorithms? No, we can simply layer more + efficient optimizations in based on constraints. + If these constraints exist, it automatically + upgrades, but if not, it falls back to the + brute-force mesh based robust algorithm. + A simple example is to limit peer connections + and rely upon daisy chaining to relay messages. + + Another example, is if peers are willing to + identify themselves, then we can improve the + efficiency of the network by having each peer + include the names of peers it is connected in + each message. Then each subsequent peer will + not relay it to them, since it is unnecessary. + This should create N (where N is the number of + peers) messages (or possibly N+ if there is a + common peer of uncommon peers that receives it + and relays at exact latency timings), which is + optimal. + + Since computer networks aren't actually blind, + we will implement the above method to improve + the performance of the ad-hoc mesh network. + + But why not have every message contain the + whole history of peers that it relayed through? + Because in sufficiently large enough networks, + with extensive daisy chaining, this will cause + the message to become prohibitively slow and + increase indefinitely in size. + +*/ + +var WebSocket = require('ws'); + +var url = require('url'); + +Gun.on('opt', function(ctx){ + var opt = ctx.opt; + if(false === opt.ws){ + this.to.next(); + return; + } + + opt.WebSocket = opt.WebSocket || WebSocket; + + if(!opt.ws || !opt.ws.web){ + + var ws = opt.ws = opt.ws || {}; + ws.server = ws.server || opt.web; + ws.path = ws.path || '/gun'; + ws.web = new opt.WebSocket.Server(ws); + ws.web.on('connection', function(wire){ + wire.upgradeReq = wire.upgradeReq || {}; + wire.url = url.parse(wire.upgradeReq.url||'', true); + wire.id = wire.id || Gun.text.random(6); + var peer = opt.peers[wire.id] = {id: wire.id, wire: wire}; + wire.peer = function(){ return peer }; + ctx.on('hi', peer); + wire.on('message', function(msg){ + //console.log("MESSAGE", msg); + opt.mesh.hear(msg.data || msg, peer); + }); + wire.on('close', function(){ + ctx.on('bye', peer); + Gun.obj.del(opt.peers, wire.id); + }); + wire.on('error', function(e){}); + }); + } + + this.to.next(ctx); +}); \ No newline at end of file diff --git a/lib/ws.js b/lib/ws.js index 8ddf6d00..8a8ed81b 100644 --- a/lib/ws.js +++ b/lib/ws.js @@ -12,6 +12,7 @@ Gun.on('opt', function mount(ctx){ opt.peers = [opt]; if(ctx.once){ return } + if(false === opt.ws){ return } var ws = opt.ws || (opt.ws = {}), batch; if(opt.web){ @@ -80,6 +81,7 @@ Gun.on('opt', function mount(ctx){ } return; } + if(global.DEBUG && msg.put){ global.DEBUG++; } msg.peer = wire.peer; ctx.on('in', msg); } diff --git a/test/gun.html b/test/gun.html new file mode 100644 index 00000000..35701232 --- /dev/null +++ b/test/gun.html @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/test/panic/load.js b/test/panic/load.js index 40966ec3..1a77db71 100644 --- a/test/panic/load.js +++ b/test/panic/load.js @@ -88,7 +88,7 @@ describe("Load test "+ config.browsers +" browser(s) across "+ config.servers +" // Launch the server and start gun! var Gun = require('gun'); // Attach the server to gun. - var gun = Gun({file: env.i+'data', web: server}); + var gun = Gun({file: env.i+'data', web: server, localStorage: false}); server.listen(env.config.port + env.i, function(){ // This server peer is now done with the test! // It has successfully launched. diff --git a/test/ptsd/spam.js b/test/ptsd/spam.js index bbbce0f8..89745a5b 100644 --- a/test/ptsd/spam.js +++ b/test/ptsd/spam.js @@ -1,34 +1,21 @@ ;(function(){ window.SPAM = function(cb, opt){ opt = Gun.num.is(opt)? {each: opt} : opt || {}; + opt.wait = opt.wait || 1; setInterval(burst, opt.wait); -var n = Gun.time.is(), i = 0, c = 0, b = opt.burst || 1, l = opt.each || 100; -var raw = "AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA " +var n = Gun.time.is(), i = 0, c = 0, b = opt.burst || 10, l = opt.each || 100; +var r = Gun.text.random, raw; function save(i){ if(!window.SPAM){ return } if(i > l){ return clearTimeout(t); } - cb(i, raw + i); - return; - var d; - var ref = window.gun.get('asdf'+i); - ref.put({hello: raw + i}, function(ack){ - if(d){ return } d = true; - c++; - !(i % b) && console.log(i+'/'+l);//, '@'+Math.floor(b/((-n + (n = Gun.time.is()))/1000))+'/sec'); - //localStorage.clear(); - ref.off(); - //console.log("gl:", Object.keys(window.gun._.graph).length); - if(c < l){ return } - setTimeout(function(){ - test.done(); - }, 1000); - }); + cb(i, i + raw + i); } function burst(){ + raw = r(1000000); for(var j = 0; j <= b; j++){ save(++i); } @@ -37,7 +24,29 @@ var t; } }()); +var gun = Gun({localStorage: false, peers: 'http://localhost:8080/gun'}); +var g = gun.get('test'); +var room = Gun.text.random(100); +var pub = Gun.text.random(1000); SPAM(function(i, v){ - $("#message-input").text(v); - $('.say').trigger('click'); -}, 10000); \ No newline at end of file + //console.log(Gun.state(), i);return; + console.log(i); + var ref = g.set({ + a: v, + b: i, + c: room, + d: pub + }, function(ack){ + ref.off(); + }); +}, 99999999999999); + +/* +;(function(){ + $("#say").on('submit', function(){ + setTimeout(function(){ + $("#say").find('input').first().val(Gun.text.random(1000)); + },1); + }); +}); +*/ \ No newline at end of file From a10263df1325bcb05ca85184dc337e957db406c4 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 12 Mar 2018 16:37:19 -0700 Subject: [PATCH 2/6] batch! --- gun.js | 85 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 33 deletions(-) diff --git a/gun.js b/gun.js index bb223305..7bf06529 100644 --- a/gun.js +++ b/gun.js @@ -1856,42 +1856,61 @@ } } - mesh.say = function(msg, peer){ - /* - TODO: Plenty of performance optimizations - that can be made just based off of ordering, - and reducing function calls for cached writes. - */ - if(!peer){ - Type.obj.map(ctx.opt.peers, function(peer){ - mesh.say(msg, peer); - }); - return; + ;(function(){ + mesh.say = function(msg, peer){ + /* + TODO: Plenty of performance optimizations + that can be made just based off of ordering, + and reducing function calls for cached writes. + */ + if(!peer){ + Type.obj.map(ctx.opt.peers, function(peer){ + mesh.say(msg, peer); + }); + return; + } + var tmp, wire = peer.wire || ((ctx.opt.wire) && ctx.opt.wire(peer)), msh, raw;// || open(peer, ctx); // TODO: Reopen! + if(!wire){ return } + msh = msg.mesh || empty; + if(peer === msh.via){ return } + if(!(raw = msh.raw)){ raw = mesh.raw(msg) } + if((tmp = msg['@']) + && (tmp = ctx.dup.s[tmp]) + && (tmp = tmp.it)){ + if(tmp.get && tmp['##'] && tmp['##'] === msg['##']){ // PERF: move this condition outside say? + return; // TODO: this still needs to be tested in the browser! + } + } + if((tmp = msh.to) && (tmp[peer.url] || tmp[peer.id])){ return } // TODO: still needs to be tested + if(peer.batch){ + peer.batch.push(raw); + return; + } + peer.batch = []; + setTimeout(function(){ + var tmp = peer.batch; + if(!tmp){ return } + peer.batch = null; + if(!tmp.length){ return } + send(JSON.stringify(tmp), peer); + }, ctx.opt.wait || 1); + send(raw, peer); } - var tmp, wire = peer.wire || ((ctx.opt.wire) && ctx.opt.wire(peer)), msh, raw;// || open(peer, ctx); // TODO: Reopen! - if(!wire){ return } - msh = msg.mesh || empty; - if(peer === msh.via){ return } - if(!(raw = msh.raw)){ raw = mesh.raw(msg) } - if((tmp = msg['@']) - && (tmp = ctx.dup.s[tmp]) - && (tmp = tmp.it)){ - if(tmp.get && tmp['##'] && tmp['##'] === msg['##']){ // PERF: move this condition outside say? - return; // TODO: this still needs to be tested in the browser! + function send(raw, peer){ + var wire = peer.wire; + try{ + if(wire.send){ + wire.send(raw); + } else + if(peer.say){ + peer.say(raw); + } + }catch(e){ + (peer.queue = peer.queue || []).push(raw); } } - if((tmp = msh.to) && (tmp[peer.url] || tmp[peer.id])){ return } // TODO: still needs to be tested - try{ - if(wire.send){ - wire.send(raw); - } else - if(peer.say){ - peer.say(raw); - } - }catch(e){ - (peer.queue = peer.queue || []).push(raw); - } - } + + }()); ;(function(){ From 58e3d92746a2e95f5032ffc2a3e455128685109c Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 12 Mar 2018 23:43:30 -0700 Subject: [PATCH 3/6] safer wire mesh --- gun.js | 6 +++++- test/panic/b2s2s2b.js | 8 ++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/gun.js b/gun.js index 7bf06529..9347bac1 100644 --- a/gun.js +++ b/gun.js @@ -1900,7 +1900,11 @@ var wire = peer.wire; try{ if(wire.send){ - wire.send(raw); + if(wire.readyState === wire.OPEN){ + wire.send(raw); + } else { + (peer.queue = peer.queue || []).push(raw); + } } else if(peer.say){ peer.say(raw); diff --git a/test/panic/b2s2s2b.js b/test/panic/b2s2s2b.js index 4f9b0778..b0fc8da0 100644 --- a/test/panic/b2s2s2b.js +++ b/test/panic/b2s2s2b.js @@ -1,10 +1,10 @@ var config = { IP: require('ip').address(), port: 8080, - servers: 2, - browsers: 2, - each: 12000, - burst: 1000, + servers: 4, + browsers: 4, + each: 10000, + burst: 100, wait: 1, route: { '/': __dirname + '/index.html', From 093f0ca98ed8e571482df101c25696717426de17 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 12 Mar 2018 23:50:49 -0700 Subject: [PATCH 4/6] undo --- examples/http.js | 1 - gun.js | 1 - lib/debug.js | 2 +- lib/store.js | 2 +- lib/ws.js | 1 - 5 files changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/http.js b/examples/http.js index d2dca8d5..637ed36d 100644 --- a/examples/http.js +++ b/examples/http.js @@ -16,7 +16,6 @@ var server = require('http').createServer(function(req, res){ var gun = Gun({ file: 'data.json', web: server, - localStorage: false, s3: { key: process.env.AWS_ACCESS_KEY_ID, // Use environment variables secret: process.env.AWS_SECRET_ACCESS_KEY, // so your keys are not diff --git a/gun.js b/gun.js index 9347bac1..ce6e0b37 100644 --- a/gun.js +++ b/gun.js @@ -835,7 +835,6 @@ } at.opt.peers = at.opt.peers || {}; obj_to(opt, at.opt); // copies options on to `at.opt` only if not already taken. - at.PID = at.PID || Gun.log(Gun.text.random(2)); Gun.on('opt', at); at.opt.uuid = at.opt.uuid || function(){ return state_lex() + text_rand(12) } return gun; diff --git a/lib/debug.js b/lib/debug.js index 3291f09a..c3562cd1 100644 --- a/lib/debug.js +++ b/lib/debug.js @@ -7,7 +7,7 @@ var mem = process.memoryUsage(); var used = mem.heapUsed / 1024 / 1024; used = used.toFixed(1); - console.log(used, 'MB', global.DEBUG); + console.log(used, 'MB'); }, 1000); }()); \ No newline at end of file diff --git a/lib/store.js b/lib/store.js index 2d0ffa3d..8d48c565 100644 --- a/lib/store.js +++ b/lib/store.js @@ -36,7 +36,7 @@ Gun.on('opt', function(ctx){ return; } if(acks){ return } - ctx.on('in', {'@': id, ok: 1, RSE: 1}); + ctx.on('in', {'@': id, ok: 1}); } }); diff --git a/lib/ws.js b/lib/ws.js index 8a8ed81b..2cb2e88e 100644 --- a/lib/ws.js +++ b/lib/ws.js @@ -81,7 +81,6 @@ Gun.on('opt', function mount(ctx){ } return; } - if(global.DEBUG && msg.put){ global.DEBUG++; } msg.peer = wire.peer; ctx.on('in', msg); } From 2b14f74ee04263836d2d522883c9701f103d2751 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 12 Mar 2018 23:58:28 -0700 Subject: [PATCH 5/6] wire mesh! --- gun.js | 3 +- gun.min.js | 2 +- lib/store.js | 6 -- src/adapters/mesh.js | 191 ++++++++++++++++++++++++++++++++++++++ src/adapters/websocket.js | 100 ++++++-------------- src/chain.js | 2 +- src/dup.js | 18 ++-- src/on.js | 6 +- src/root.js | 12 +-- test/panic/b2s2s2b.js | 4 +- 10 files changed, 244 insertions(+), 100 deletions(-) create mode 100644 src/adapters/mesh.js diff --git a/gun.js b/gun.js index ce6e0b37..7945d324 100644 --- a/gun.js +++ b/gun.js @@ -808,7 +808,7 @@ //tmp = at.ack; root.on('in', { '@': msg['#'], - how: 'mem', by: root.PID, + how: 'mem', put: node, gun: gun }); @@ -1789,7 +1789,6 @@ try{store.setItem(opt.file, JSON.stringify(disk)); }catch(e){ Gun.log(err = e || "localStorage failure") } if(!err && !Gun.obj.empty(opt.peers)){ return } // only ack if there are no peers. - console.log("@@@", ack); Gun.obj.map(ack, function(yes, id){ root.on('in', { '@': id, diff --git a/gun.min.js b/gun.min.js index 8c46e2cb..c6ddcb8c 100644 --- a/gun.min.js +++ b/gun.min.js @@ -1 +1 @@ -!function(){function t(n){function o(t){return t.split("/").slice(-1).toString().replace(".js","")}return n.slice?t[o(n)]:function(e,i){n(e={exports:{}}),t[o(i)]=e.exports}}var n;"undefined"!=typeof window&&(n=window),"undefined"!=typeof global&&(n=global);var o=(n=n||{}).console||{log:function(){}};if("undefined"!=typeof module)var e=module;t(function(t){var n={};n.fns=n.fn={is:function(t){return!!t&&"function"==typeof t}},n.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},n.num={is:function(t){return!e(t)&&(t-parseFloat(t)+1>=0||1/0===t||-1/0===t)}},n.text={is:function(t){return"string"==typeof t}},n.text.ify=function(t){return n.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},n.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";t>0;)o+=n.charAt(Math.floor(Math.random()*n.length)),t--;return o},n.text.match=function(t,o){var e=!1;if(t=t||"",o=n.text.is(o)?{"=":o}:o||{},n.obj.has(o,"~")&&(t=t.toLowerCase(),o["="]=(o["="]||o["~"]).toLowerCase()),n.obj.has(o,"="))return t===o["="];if(n.obj.has(o,"*")){if(t.slice(0,o["*"].length)!==o["*"])return!1;e=!0,t=t.slice(o["*"].length)}if(n.obj.has(o,"!")){if(t.slice(-o["!"].length)!==o["!"])return!1;e=!0}if(n.obj.has(o,"+")&&n.list.map(n.list.is(o["+"])?o["+"]:[o["+"]],function(n){if(!(t.indexOf(n)>=0))return!0;e=!0}))return!1;if(n.obj.has(o,"-")&&n.list.map(n.list.is(o["-"])?o["-"]:[o["-"]],function(n){if(!(t.indexOf(n)<0))return!0;e=!0}))return!1;if(n.obj.has(o,">")){if(!(t>o[">"]))return!1;e=!0}if(n.obj.has(o,"<")){if(!(to?1:0):0}},n.list.map=function(t,n,o){return a(t,n,o)},n.list.index=1,n.obj={is:function(t){return!!t&&(t instanceof Object&&t.constructor===Object||"Object"===Object.prototype.toString.call(t).match(/^\[object (\w+)\]$/)[1])}},n.obj.put=function(t,n,o){return(t||{})[n]=o,t},n.obj.has=function(t,n){return t&&Object.prototype.hasOwnProperty.call(t,n)},n.obj.del=function(t,n){if(t)return t[n]=null,delete t[n],t},n.obj.as=function(t,n,o,e){return t[n]=t[n]||(e===o?{}:o)},n.obj.ify=function(t){if(r(t))return t;try{t=JSON.parse(t)}catch(n){t={}}return t},function(){function t(t,n){u(this,n)&&o!==this[n]||(this[n]=t)}var o;n.obj.to=function(n,o){return o=o||{},a(n,t,o),o}}(),n.obj.copy=function(t){return t?JSON.parse(JSON.stringify(t)):t},function(){function t(t,n){var o=this.n;if(!o||!(n===o||r(o)&&u(o,n)))return!!n||void 0}n.obj.empty=function(n,o){return!n||!a(n,t,{n:o})}}(),function(){function t(n,o){if(2===arguments.length)return t.r=t.r||{},void(t.r[n]=o);t.r=t.r||[],t.r.push(n)}var i=Object.keys;n.obj.map=function(a,s,f){var c,l,p,g,h,d=0,v=o(s);if(t.r=null,i&&r(a)&&(g=i(a),h=!0),e(a)||g)for(l=(g||a).length;d",o.drift=0,o.is=function(t,n,e){var i=n&&t&&t[k]&&t[k][o._]||e;if(i)return b(i=i[n])?i:-1/0},o.lex=function(){return o().toString(36).replace(".","")},o.ify=function(t,n,e,r,u){if(!t||!t[k]){if(!u)return;t=i.soul.ify(t,u)}var a=g(t[k],o._);return l!==n&&n!==k&&(b(e)&&(a[n]=e),l!==r&&(t[n]=r)),t},o.to=function(t,n,e){var r=t[n];return d(r)&&(r=_(r)),o.ify(e,n,o.is(t,n),r,i.soul(t))},function(){function t(t,n){k!==n&&o.ify(this.o,n,this.s)}o.map=function(n,e,i){var r,u=d(u=n||e)?u:null;return n=m(n=n||e)?n:null,u&&!n?(e=b(e)?e:o(),u[k]=u[k]||{},v(u,t,{o:u,s:e}),u):(i=i||d(e)?e:r,e=b(e)?e:o(),function(o,u,a,s){if(!n)return t.call({o:a,s:e},o,u),o;n.call(i||this||{},o,u,a,s),h(a,u)&&r===a[u]||t.call({o:a,s:e},o,u)})}}();var l,p=e.obj,g=p.as,h=p.has,d=p.is,v=p.map,_=p.copy,b=e.num.is,m=e.fn.is,k=i._;n.exports=o})(t,"./state"),t(function(n){var o=t("./type"),e=t("./val"),i=t("./node"),r={};!function(){function t(t,o){if(!t||o!==i.soul(t)||!i.is(t,this.fn,this.as))return!0;this.cb&&(n.n=t,n.as=this.as,this.cb.call(n.as,t,o,n))}function n(t){t&&i.is(n.n,t,n.as)}r.is=function(n,o,e,i){return!(!n||!s(n)||l(n))&&!g(n,t,{cb:o,fn:e,as:i})}}(),function(){function t(t,r){var u;return(u=l(t,r))?u:(r.env=t,r.soul=o,i.ify(r.obj,n,r)&&(t.graph[e.rel.is(r.rel)]=r.node),r)}function n(n,o,r){var s,l,p=this,g=p.env;if(i._===o&&c(n,e.rel._))return r._;if(s=a(n,o,r,p,g)){if(o||(p.node=p.node||r||{},c(n,i._)&&(p.node._=h(n._)),p.node=i.soul.ify(p.node,e.rel.is(p.rel)),p.rel=p.rel||e.rel.ify(i.soul(p.node))),(l=g.map)&&(l.call(g.as||{},n,o,r,p),c(r,o))){if(n=r[o],u===n)return void f(r,o);if(!(s=a(n,o,r,p,g)))return}if(!o)return p.node;if(!0===s)return n;if((l=t(g,{obj:n,path:p.path.concat(o)})).node)return l.rel}}function o(t){var n=this,o=e.rel.is(n.rel),r=n.env.graph;n.rel=n.rel||e.rel.ify(t),n.rel[e.rel._]=t,n.node&&n.node[i._]&&(n.node[i._][e.rel._]=t),c(r,o)&&(r[t]=r[o],f(r,o))}function a(t,n,o,i,r){var u;return!!e.is(t)||(s(t)?1:(u=r.invalid)?(t=u.call(r.as||{},t,n,o),a(t,n,o,i,r)):void(r.err="Invalid value at '"+i.path.concat(n).join(".")+"'!"))}function l(t,n){for(var o,e=t.seen,i=e.length;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}r.ify=function(n,o,i){var r={path:[],obj:n};return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o.map=o):o={},o.soul&&(r.rel=e.rel.ify(o.soul)),o.graph=o.graph||{},o.seen=o.seen||[],o.as=o.as||i,t(o,r),o.root=r.node,o.graph}}(),r.node=function(t){var n=i.soul(t);if(n)return p({},n,t)},function(){function t(t,n){var o,u;if(i._!==n)(o=e.rel.is(t))?(u=this.opt.seen[o])?this.obj[n]=u:this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt):this.obj[n]=t;else{if(l(t,e.rel._))return;this.obj[n]=h(t)}}r.to=function(n,o,e){if(n){var i={};return e=e||{seen:{}},g(n[o],t,{obj:i,graph:n,opt:e}),i}}}();o.fn.is;var u,a=o.obj,s=a.is,f=a.del,c=a.has,l=a.empty,p=a.put,g=a.map,h=a.copy;n.exports=r})(t,"./graph"),t(function(n){t("./onto"),n.exports=function(t,n){if(this.on){if(!(t instanceof Function)){if(!t||!n)return;var o=t["#"]||t,e=(this.tag||empty)[o];if(!e)return;return e=this.on(o,n),clearTimeout(e.err),!0}o=n&&n["#"]||Math.random().toString(36).slice(2);if(!t)return o;var i=this.on(o,t,n);return i.err=i.err||setTimeout(function(){i.next({err:"Error: No ACK received yet."}),i.off()},(this.opt||{}).lack||9e3),o}}})(t,"./ask"),t(function(n){var o=t("./type"),e=o.time.is;n.exports=function(t){var n={s:{}};return t=t||{max:1e3,age:9e3},n.check=function(t){return!!n.s[t]&&n.track(t)},n.track=function(i){return n.s[i]=e(),n.to||(n.to=setTimeout(function(){o.obj.map(n.s,function(i,r){t.age>e()-i||o.obj.del(n.s,r)}),n.to=null},t.age)),i},n}})(t,"./dup"),t(function(n){function i(t){return t instanceof i?(this._={gun:this}).gun:this instanceof i?i.create(this._={gun:this,opt:t}):new i(t)}i.is=function(t){return t instanceof i},i.version=.9,i.chain=i.prototype,i.chain.toJSON=function(){};var r=t("./type");r.obj.to(r,i),i.HAM=t("./HAM"),i.val=t("./val"),i.node=t("./node"),i.state=t("./state"),i.graph=t("./graph"),i.on=t("./onto"),i.ask=t("./ask"),i.dup=t("./dup"),function(){function t(t){var n,o=this.as,e=o.gun;(n=t["#"])||(n=t["#"]=c(9)),o.dup.check(n)||(o.dup.track(n),t=h(t),o.ask(t["@"],t)||(t.get&&i.on.get(t,e),t.put&&i.on.put(t,e)),o.on("out",t))}i.create=function(n){n.root=n.root||n.gun,n.graph=n.graph||{},n.on=n.on||i.on,n.ask=n.ask||i.ask,n.dup=n.dup||i.dup();var o=n.gun.opt(n.opt);return n.once||(n.on("in",t,n),n.on("out",t,n)),n.once=1,o}}(),function(){function t(t,n,o,e){var r=this,u=i.state.is(o,n);if(!u)return r.err="Error: No state on '"+n+"' in node '"+e+"'!";var a=r.graph[e]||m,s=i.state.is(a,n,!0),f=a[n],c=i.HAM(r.machine,u,s,t,f);c.incoming?(r.put[e]=i.state.to(o,n,r.put[e]),(r.diff||(r.diff={}))[e]=i.state.to(o,n,r.diff[e]),r.souls[e]=!0):c.defer&&(r.defer=u<(r.defer||1/0)?u:r.defer)}function n(t,n){var i=this,u=i.gun._,a=(u.next||m)[n];if(a){var s=i.map[n]={put:t,get:n,gun:a},f={ctx:i,msg:s};i.async=!!u.tag.node,i.ack&&(s["@"]=i.ack),d(t,o,f),i.async&&(i.and||u.on("node",function(t){this.to.next(t),t===i.map[t.get]&&(i.souls[t.get]=!1,d(t.put,e,t),d(i.souls,function(t){if(t)return t})||i.c||(i.c=1,this.off(),u.stop={},d(i.map,r,i)))}),i.and=!0,u.on("node",s))}else i.souls[n]=!1}function o(t,n){var o=this.ctx,e=o.graph,r=this.msg,u=r.get,a=r.put,s=r.gun._;e[u]=i.state.to(a,n,e[u]),o.async||(s.put=i.state.to(a,n,s.put))}function e(t,n){var o=this,e=o.put,r=o.gun._;r.put=i.state.to(e,n,r.put)}function r(t,n){t.gun&&t.gun._.on("in",t)}i.on.put=function(o,e){var a=e._,s={gun:e,graph:a.graph,put:{},map:{},souls:{},machine:i.state(),ack:o["@"]};if(i.graph.is(o.put,null,t,s)||(s.err="Error: Invalid graph!"),s.err)return a.on("in",{"@":o["#"],err:i.log(s.err)});d(s.put,n,s),s.async||(a.stop={},d(s.map,r,s)),u!==s.defer&&setTimeout(function(){i.on.put(o,e)},s.defer-s.machine),s.diff&&a.on("put",h(o,{put:s.diff}))},i.on.get=function(t,n){var o=n._,e=t.get[_],r=o.graph[e],u=t.get[b],a=((o.next||(o.next={}))[e]||m)._;if(!r||!a)return o.on("get",t);if(u){if(!g(r,u))return o.on("get",t);r=i.state.to(r,u)}else r=i.obj.copy(r);r=i.graph.node(r),o.on("in",{"@":t["#"],put:r,gun:n}),o.on("get",t)}}(),i.chain.opt=function(t){t=t||{};var n=this,o=n._,e=t.peers||t;return p(t)||(t={}),p(o.opt)||(o.opt=t),f(e)&&(e=[e]),a(e)&&(e=d(e,function(t,n,o){o(t,{url:t})}),p(o.opt.peers)||(o.opt.peers={}),o.opt.peers=h(e,o.opt.peers)),o.opt.peers=o.opt.peers||{},h(t,o.opt),i.on("opt",o),o.opt.uuid=o.opt.uuid||function(){return v()+c(12)},n};var u,a=i.list.is,s=i.text,f=s.is,c=s.random,l=i.obj,p=l.is,g=l.has,h=l.to,d=l.map,v=(l.copy,i.state.lex),_=i.val.rel._,b=".",m=(i.node._,i.val.rel.is,{});o.debug=function(t,n){return o.debug.i&&t===o.debug.i&&o.debug.i++&&(o.log.apply(o,arguments)||n)},i.log=function(){return!i.log.off&&o.log.apply(o,arguments),[].slice.call(arguments).join(" ")},i.log.once=function(t,n,o){return(o=i.log.once)[t]=o[t]||0,o[t]++||i.log(n)},i.log.once("welcome","Hello wonderful person! :) Thanks for using GUN, feel free to ask for help on https://gitter.im/amark/gun and ask StackOverflow questions tagged with 'gun'!"),"undefined"!=typeof window&&(window.Gun=i);try{void 0!==e&&(e.exports=i)}catch(t){}n.exports=i})(t,"./root"),t(function(n){var o=t("./root");o.chain.back=function(t,n){if(-1===(t=t||1)||1/0===t)return this._.root;if(1===t)return this._.back||this;var r=this,u=r._;if("string"==typeof t&&(t=t.split(".")),!(t instanceof Array)){if(t instanceof Function){for(var a,s={back:r};(s=s.back)&&(s=s._)&&!(a=t(s,n)););return a}return o.num.is(t)?u.back.back(t-1):this}var f=0,c=t.length,s=u;for(f;f=(n.batch||1e3))return s();o||(o=setTimeout(s,n.wait||1))}),t.on("get",function(o){this.to.next(o);var e,i,r=o.get;if(r&&(e=r["#"])){var a=r["."];(i=u[e]||void 0)&&a&&(i=Gun.state.to(i,a)),(i||Gun.obj.empty(n.peers))&&t.on("in",{"@":o["#"],put:Gun.graph.node(i),how:"lS"})}});var a=function(t,n,o,e){u[e]=Gun.state.to(o,n,u[e])},s=function(){var a;r=0,clearTimeout(o),o=!1;var s=i;i={};try{e.setItem(n.file,JSON.stringify(u))}catch(t){Gun.log(a=t||"localStorage failure")}(a||Gun.obj.empty(n.peers))&&Gun.obj.map(s,function(n,o){t.on("in",{"@":o,err:a,ok:0})})}}})}})(t,"./adapters/localStorage"),t(function(n){var o,e=t("./index");"undefined"!=typeof WebSocket?o=WebSocket:("undefined"!=typeof webkitWebSocket&&(o=webkitWebSocket),"undefined"!=typeof mozWebSocket&&(o=mozWebSocket)),e.on("opt",function(t){function n(t){var n=this,o=c,e=t.wire||u(t,n);e&&(e.readyState!==e.OPEN?(t.queue=t.queue||[]).push(o):e.send(o))}function r(t,n,o){if(o&&t){try{t=JSON.parse(t.data||t)}catch(t){}if(t instanceof Array)for(var e,u=0;e=t[u++];)r(e,n,o);else 1==f.who&&(t.ws=i),o.on("in",t)}}function u(i,u){if(i&&i.url){var s=i.url.replace("http","ws"),f=i.wire=new o(s);return f.onclose=function(){t.on("bye",i),a(i,u)},f.onerror=function(t){a(i,u),t&&t.code},f.onopen=function(){t.on("hi",i);var o=i.queue;i.queue=[],e.obj.map(o,function(t){c=t,n.call(u,i)})},f.onmessage=function(t){r(t,i,u)},f}}function a(t,n){clearTimeout(t.defer),t.defer=setTimeout(function(){u(t,n)},2e3)}this.to.next(t);var s=t.opt;if(!t.once&&o&&!1!==s.WebSocket){var f=s.ws||(s.ws={});if(f.who=0,e.obj.map(s.peers,function(){++f.who}),!t.once){var c;t.on("out",function(o){this.to.next(o),o.ws&&1==f.who||(c=JSON.stringify(o),f.drain?f.drain.push(c):(f.drain=[],setTimeout(function(){if(f.drain){var o=f.drain;f.drain=null,o.length&&(c=JSON.stringify(o),e.obj.map(s.peers,n,t))}},s.wait||1),e.obj.map(s.peers,n,t)))})}}});var i=function(){}})(t,"./adapters/websocket")}(); \ No newline at end of file +!function(){function t(n){function o(t){return t.split("/").slice(-1).toString().replace(".js","")}return n.slice?t[o(n)]:function(e,i){n(e={exports:{}}),t[o(i)]=e.exports}}var n;"undefined"!=typeof window&&(n=window),"undefined"!=typeof global&&(n=global);var o=(n=n||{}).console||{log:function(){}};if("undefined"!=typeof module)var e=module;t(function(t){var n={};n.fns=n.fn={is:function(t){return!!t&&"function"==typeof t}},n.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},n.num={is:function(t){return!e(t)&&(t-parseFloat(t)+1>=0||1/0===t||-1/0===t)}},n.text={is:function(t){return"string"==typeof t}},n.text.ify=function(t){return n.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},n.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";t>0;)o+=n.charAt(Math.floor(Math.random()*n.length)),t--;return o},n.text.match=function(t,o){var e=!1;if(t=t||"",o=n.text.is(o)?{"=":o}:o||{},n.obj.has(o,"~")&&(t=t.toLowerCase(),o["="]=(o["="]||o["~"]).toLowerCase()),n.obj.has(o,"="))return t===o["="];if(n.obj.has(o,"*")){if(t.slice(0,o["*"].length)!==o["*"])return!1;e=!0,t=t.slice(o["*"].length)}if(n.obj.has(o,"!")){if(t.slice(-o["!"].length)!==o["!"])return!1;e=!0}if(n.obj.has(o,"+")&&n.list.map(n.list.is(o["+"])?o["+"]:[o["+"]],function(n){if(!(t.indexOf(n)>=0))return!0;e=!0}))return!1;if(n.obj.has(o,"-")&&n.list.map(n.list.is(o["-"])?o["-"]:[o["-"]],function(n){if(!(t.indexOf(n)<0))return!0;e=!0}))return!1;if(n.obj.has(o,">")){if(!(t>o[">"]))return!1;e=!0}if(n.obj.has(o,"<")){if(!(to?1:0):0}},n.list.map=function(t,n,o){return a(t,n,o)},n.list.index=1,n.obj={is:function(t){return!!t&&(t instanceof Object&&t.constructor===Object||"Object"===Object.prototype.toString.call(t).match(/^\[object (\w+)\]$/)[1])}},n.obj.put=function(t,n,o){return(t||{})[n]=o,t},n.obj.has=function(t,n){return t&&Object.prototype.hasOwnProperty.call(t,n)},n.obj.del=function(t,n){if(t)return t[n]=null,delete t[n],t},n.obj.as=function(t,n,o,e){return t[n]=t[n]||(e===o?{}:o)},n.obj.ify=function(t){if(r(t))return t;try{t=JSON.parse(t)}catch(n){t={}}return t},function(){function t(t,n){u(this,n)&&o!==this[n]||(this[n]=t)}var o;n.obj.to=function(n,o){return o=o||{},a(n,t,o),o}}(),n.obj.copy=function(t){return t?JSON.parse(JSON.stringify(t)):t},function(){function t(t,n){var o=this.n;if(!o||!(n===o||r(o)&&u(o,n)))return!!n||void 0}n.obj.empty=function(n,o){return!n||!a(n,t,{n:o})}}(),function(){function t(n,o){if(2===arguments.length)return t.r=t.r||{},void(t.r[n]=o);t.r=t.r||[],t.r.push(n)}var i=Object.keys;n.obj.map=function(a,s,f){var c,l,p,h,g,d=0,v=o(s);if(t.r=null,i&&r(a)&&(h=i(a),g=!0),e(a)||h)for(l=(h||a).length;d",o.drift=0,o.is=function(t,n,e){var i=n&&t&&t[k]&&t[k][o._]||e;if(i)return _(i=i[n])?i:-1/0},o.lex=function(){return o().toString(36).replace(".","")},o.ify=function(t,n,e,r,u){if(!t||!t[k]){if(!u)return;t=i.soul.ify(t,u)}var a=h(t[k],o._);return l!==n&&n!==k&&(_(e)&&(a[n]=e),l!==r&&(t[n]=r)),t},o.to=function(t,n,e){var r=t[n];return d(r)&&(r=b(r)),o.ify(e,n,o.is(t,n),r,i.soul(t))},function(){function t(t,n){k!==n&&o.ify(this.o,n,this.s)}o.map=function(n,e,i){var r,u=d(u=n||e)?u:null;return n=m(n=n||e)?n:null,u&&!n?(e=_(e)?e:o(),u[k]=u[k]||{},v(u,t,{o:u,s:e}),u):(i=i||d(e)?e:r,e=_(e)?e:o(),function(o,u,a,s){if(!n)return t.call({o:a,s:e},o,u),o;n.call(i||this||{},o,u,a,s),g(a,u)&&r===a[u]||t.call({o:a,s:e},o,u)})}}();var l,p=e.obj,h=p.as,g=p.has,d=p.is,v=p.map,b=p.copy,_=e.num.is,m=e.fn.is,k=i._;n.exports=o})(t,"./state"),t(function(n){var o=t("./type"),e=t("./val"),i=t("./node"),r={};!function(){function t(t,o){if(!t||o!==i.soul(t)||!i.is(t,this.fn,this.as))return!0;this.cb&&(n.n=t,n.as=this.as,this.cb.call(n.as,t,o,n))}function n(t){t&&i.is(n.n,t,n.as)}r.is=function(n,o,e,i){return!(!n||!s(n)||l(n))&&!h(n,t,{cb:o,fn:e,as:i})}}(),function(){function t(t,r){var u;return(u=l(t,r))?u:(r.env=t,r.soul=o,i.ify(r.obj,n,r)&&(t.graph[e.rel.is(r.rel)]=r.node),r)}function n(n,o,r){var s,l,p=this,h=p.env;if(i._===o&&c(n,e.rel._))return r._;if(s=a(n,o,r,p,h)){if(o||(p.node=p.node||r||{},c(n,i._)&&(p.node._=g(n._)),p.node=i.soul.ify(p.node,e.rel.is(p.rel)),p.rel=p.rel||e.rel.ify(i.soul(p.node))),(l=h.map)&&(l.call(h.as||{},n,o,r,p),c(r,o))){if(n=r[o],u===n)return void f(r,o);if(!(s=a(n,o,r,p,h)))return}if(!o)return p.node;if(!0===s)return n;if((l=t(h,{obj:n,path:p.path.concat(o)})).node)return l.rel}}function o(t){var n=this,o=e.rel.is(n.rel),r=n.env.graph;n.rel=n.rel||e.rel.ify(t),n.rel[e.rel._]=t,n.node&&n.node[i._]&&(n.node[i._][e.rel._]=t),c(r,o)&&(r[t]=r[o],f(r,o))}function a(t,n,o,i,r){var u;return!!e.is(t)||(s(t)?1:(u=r.invalid)?(t=u.call(r.as||{},t,n,o),a(t,n,o,i,r)):void(r.err="Invalid value at '"+i.path.concat(n).join(".")+"'!"))}function l(t,n){for(var o,e=t.seen,i=e.length;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}r.ify=function(n,o,i){var r={path:[],obj:n};return o?"string"==typeof o?o={soul:o}:o instanceof Function&&(o.map=o):o={},o.soul&&(r.rel=e.rel.ify(o.soul)),o.graph=o.graph||{},o.seen=o.seen||[],o.as=o.as||i,t(o,r),o.root=r.node,o.graph}}(),r.node=function(t){var n=i.soul(t);if(n)return p({},n,t)},function(){function t(t,n){var o,u;if(i._!==n)(o=e.rel.is(t))?(u=this.opt.seen[o])?this.obj[n]=u:this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt):this.obj[n]=t;else{if(l(t,e.rel._))return;this.obj[n]=g(t)}}r.to=function(n,o,e){if(n){var i={};return e=e||{seen:{}},h(n[o],t,{obj:i,graph:n,opt:e}),i}}}();o.fn.is;var u,a=o.obj,s=a.is,f=a.del,c=a.has,l=a.empty,p=a.put,h=a.map,g=a.copy;n.exports=r})(t,"./graph"),t(function(n){t("./onto"),n.exports=function(t,n){if(this.on){if(!(t instanceof Function)){if(!t||!n)return;var o=t["#"]||t,e=(this.tag||empty)[o];if(!e)return;return e=this.on(o,n),clearTimeout(e.err),!0}o=n&&n["#"]||Math.random().toString(36).slice(2);if(!t)return o;var i=this.on(o,t,n);return i.err=i.err||setTimeout(function(){i.next({err:"Error: No ACK received yet."}),i.off()},(this.opt||{}).lack||9e3),o}}})(t,"./ask"),t(function(n){var o=t("./type"),e=o.time.is;n.exports=function(t){var n={s:{}};return t=t||{max:1e3,age:9e3},n.check=function(t){var o;return!!(o=n.s[t])&&(o.pass?o.pass=!1:n.track(t))},n.track=function(i,r){var u=n.s[i]||(n.s[i]={});return u.was=e(),r&&(u.pass=!0),n.to||(n.to=setTimeout(function(){o.obj.map(n.s,function(i,r){t.age>e()-i.was||o.obj.del(n.s,r)}),n.to=null},t.age)),u},n}})(t,"./dup"),t(function(n){function i(t){return t instanceof i?(this._={gun:this}).gun:this instanceof i?i.create(this._={gun:this,opt:t}):new i(t)}i.is=function(t){return t instanceof i},i.version=.9,i.chain=i.prototype,i.chain.toJSON=function(){};var r=t("./type");r.obj.to(r,i),i.HAM=t("./HAM"),i.val=t("./val"),i.node=t("./node"),i.state=t("./state"),i.graph=t("./graph"),i.on=t("./onto"),i.ask=t("./ask"),i.dup=t("./dup"),function(){function t(t){var n,o,e=this.as,r=e.gun;(o=t["#"])||(o=t["#"]=c(9)),(n=e.dup).check(o)||(n.track(o),e.ask(t["@"],t)||(t.get&&i.on.get(t,r),t.put&&i.on.put(t,r)),e.on("out",t))}i.create=function(n){n.root=n.root||n.gun,n.graph=n.graph||{},n.on=n.on||i.on,n.ask=n.ask||i.ask,n.dup=n.dup||i.dup();var o=n.gun.opt(n.opt);return n.once||(n.on("in",t,n),n.on("out",t,n)),n.once=1,o}}(),function(){function t(t,n,o,e){var r=this,u=i.state.is(o,n);if(!u)return r.err="Error: No state on '"+n+"' in node '"+e+"'!";var a=r.graph[e]||m,s=i.state.is(a,n,!0),f=a[n],c=i.HAM(r.machine,u,s,t,f);c.incoming?(r.put[e]=i.state.to(o,n,r.put[e]),(r.diff||(r.diff={}))[e]=i.state.to(o,n,r.diff[e]),r.souls[e]=!0):c.defer&&(r.defer=u<(r.defer||1/0)?u:r.defer)}function n(t,n){var i=this,u=i.gun._,a=(u.next||m)[n];if(a){var s=i.map[n]={put:t,get:n,gun:a},f={ctx:i,msg:s};i.async=!!u.tag.node,i.ack&&(s["@"]=i.ack),d(t,o,f),i.async&&(i.and||u.on("node",function(t){this.to.next(t),t===i.map[t.get]&&(i.souls[t.get]=!1,d(t.put,e,t),d(i.souls,function(t){if(t)return t})||i.c||(i.c=1,this.off(),u.stop={},d(i.map,r,i)))}),i.and=!0,u.on("node",s))}else i.souls[n]=!1}function o(t,n){var o=this.ctx,e=o.graph,r=this.msg,u=r.get,a=r.put,s=r.gun._;e[u]=i.state.to(a,n,e[u]),o.async||(s.put=i.state.to(a,n,s.put))}function e(t,n){var o=this,e=o.put,r=o.gun._;r.put=i.state.to(e,n,r.put)}function r(t,n){t.gun&&t.gun._.on("in",t)}i.on.put=function(o,e){var a=e._,s={gun:e,graph:a.graph,put:{},map:{},souls:{},machine:i.state(),ack:o["@"]};if(i.graph.is(o.put,null,t,s)||(s.err="Error: Invalid graph!"),s.err)return a.on("in",{"@":o["#"],err:i.log(s.err)});d(s.put,n,s),s.async||(a.stop={},d(s.map,r,s)),u!==s.defer&&setTimeout(function(){i.on.put(o,e)},s.defer-s.machine),s.diff&&a.on("put",g(o,{put:s.diff}))},i.on.get=function(t,n){var o=n._,e=t.get[b],r=o.graph[e],u=t.get[_],a=((o.next||(o.next={}))[e]||m)._;if(!r||!a)return o.on("get",t);if(u){if(!h(r,u))return o.on("get",t);r=i.state.to(r,u)}else r=i.obj.copy(r);r=i.graph.node(r),o.on("in",{"@":t["#"],how:"mem",put:r,gun:n}),o.on("get",t)}}(),i.chain.opt=function(t){t=t||{};var n=this,o=n._,e=t.peers||t;return p(t)||(t={}),p(o.opt)||(o.opt=t),f(e)&&(e=[e]),a(e)&&(e=d(e,function(t,n,o){o(t,{url:t})}),p(o.opt.peers)||(o.opt.peers={}),o.opt.peers=g(e,o.opt.peers)),o.opt.peers=o.opt.peers||{},g(t,o.opt),i.on("opt",o),o.opt.uuid=o.opt.uuid||function(){return v()+c(12)},n};var u,a=i.list.is,s=i.text,f=s.is,c=s.random,l=i.obj,p=l.is,h=l.has,g=l.to,d=l.map,v=(l.copy,i.state.lex),b=i.val.rel._,_=".",m=(i.node._,i.val.rel.is,{});o.debug=function(t,n){return o.debug.i&&t===o.debug.i&&o.debug.i++&&(o.log.apply(o,arguments)||n)},i.log=function(){return!i.log.off&&o.log.apply(o,arguments),[].slice.call(arguments).join(" ")},i.log.once=function(t,n,o){return(o=i.log.once)[t]=o[t]||0,o[t]++||i.log(n)},i.log.once("welcome","Hello wonderful person! :) Thanks for using GUN, feel free to ask for help on https://gitter.im/amark/gun and ask StackOverflow questions tagged with 'gun'!"),"undefined"!=typeof window&&(window.Gun=i);try{void 0!==e&&(e.exports=i)}catch(t){}n.exports=i})(t,"./root"),t(function(n){var o=t("./root");o.chain.back=function(t,n){if(-1===(t=t||1)||1/0===t)return this._.root;if(1===t)return this._.back||this;var r=this,u=r._;if("string"==typeof t&&(t=t.split(".")),!(t instanceof Array)){if(t instanceof Function){for(var a,s={back:r};(s=s.back)&&(s=s._)&&!(a=t(s,n)););return a}return o.num.is(t)?u.back.back(t-1):this}var f=0,c=t.length,s=u;for(f;f .once, apologies unexpected."),this.once(t,n)},i.chain.once=function(t,n){var o=this,u=o._,a=u.put;if(0=(n.batch||1e3))return s();o||(o=setTimeout(s,n.wait||1))}),t.on("get",function(o){this.to.next(o);var e,i,r=o.get;if(r&&(e=r["#"])){var a=r["."];(i=u[e]||void 0)&&a&&(i=Gun.state.to(i,a)),(i||Gun.obj.empty(n.peers))&&t.on("in",{"@":o["#"],put:Gun.graph.node(i),how:"lS"})}});var a=function(t,n,o,e){u[e]=Gun.state.to(o,n,u[e])},s=function(){var a;r=0,clearTimeout(o),o=!1;var s=i;i={};try{e.setItem(n.file,JSON.stringify(u))}catch(t){Gun.log(a=t||"localStorage failure")}(a||Gun.obj.empty(n.peers))&&Gun.obj.map(s,function(n,o){t.on("in",{"@":o,err:a,ok:0})})}}})}})(t,"./adapters/localStorage"),t(function(n){function o(t){var n=function(){};return n.out=function(o){var e;if(this.to&&this.to.next(o),(e=o["@"])&&(e=t.dup.s[e])&&(e=e.it))return n.say(o,e.mesh.via),void(e["##"]=o["##"]);n.say(o)},n.hear=function(o,i){if(o){var r,u,a=t.dup,s=o[0];try{o=JSON.parse(o)}catch(t){}if("{"===s){if(a.check(r=o["#"]))return;if(a.track(r,!0).it=o,(s=o["@"])&&o.put&&(u=o["##"]||(o["##"]=n.hash(o)),(s+=u)!=r)){if(a.check(s))return;(s=a.s)[u]=s[r]}return(o.mesh=function(){}).via=i,(s=o["><"])&&(o.mesh.to=e.obj.map(s.split(","),function(t,n,o){o(t,!0)})),void t.on("in",o)}if("["!==s);else for(var f,c=0;f=o[c++];)n.hear(f,i)}},function(){function o(t,n){var o=n.wire;try{o.send?o.readyState===o.OPEN?o.send(t):(n.queue=n.queue||[]).push(t):n.say&&n.say(t)}catch(o){(n.queue=n.queue||[]).push(t)}}n.say=function(i,u){if(u){var a,s,f;(u.wire||t.opt.wire&&t.opt.wire(u))&&(s=i.mesh||r,u!==s.via&&((f=s.raw)||(f=n.raw(i)),(a=i["@"])&&(a=t.dup.s[a])&&(a=a.it)&&a.get&&a["##"]&&a["##"]===i["##"]||(a=s.to)&&(a[u.url]||a[u.id])||(u.batch?u.batch.push(f):(u.batch=[],setTimeout(function(){var t=u.batch;t&&(u.batch=null,t.length&&o(JSON.stringify(t),u))},t.opt.wait||1),o(f,u)))))}else e.obj.map(t.opt.peers,function(t){n.say(i,t)})}}(),function(){function r(t,n){var o;return n instanceof Object?(e.obj.map(Object.keys(n).sort(),u,{to:o={},on:n}),o):n}function u(t){this.to[t]=this.on[t]}n.raw=function(o){if(!o)return"";var u,f,c,l=t.dup,p=o.mesh||{};if(c=p.raw)return c;if("string"==typeof o)return o;o["@"]&&(c=o.put)&&((f=o["##"])||(u=a(c,r)||"",f=n.hash(o,u),o["##"]=f),(c=l.s)[f=o["@"]+f]=c[o["#"]],o["#"]=f,u&&((o=e.obj.to(o)).put=s)),o["><"]=(e.obj.map(t.opt.peers,function(t,n,o){o(t.url||t.id)})||[]).join();var h=a(o);return i!==u&&(h=h.replace('"'+s+'"',u)),p&&(p.raw=h),h},n.hash=function(t,n){return o.hash(n||a(t.put,r)||"")||t["#"]||e.text.random(9)};var a=JSON.stringify,s=":])([:"}(),n.hi=function(o){t.on("hi",o);var i=o.queue;o.queue=[],e.obj.map(i,function(t){n.say(t,o)})},n}var e=t("./type");o.hash=function(t){if("string"!=typeof t)return{err:1};var n=0;if(!t.length)return n;for(var o=0,e=t.length;o<'])){ + msg.mesh.to = Type.obj.map(tmp.split(','), function(k,i,m){m(k,true)}); + } + ctx.on('in', msg); + + return; + } else + if('[' === tmp){ + + var i = 0, m; + while(m = msg[i++]){ + mesh.hear(m, peer); + } + + return; + } + } + + ;(function(){ + mesh.say = function(msg, peer){ + /* + TODO: Plenty of performance optimizations + that can be made just based off of ordering, + and reducing function calls for cached writes. + */ + if(!peer){ + Type.obj.map(ctx.opt.peers, function(peer){ + mesh.say(msg, peer); + }); + return; + } + var tmp, wire = peer.wire || ((ctx.opt.wire) && ctx.opt.wire(peer)), msh, raw;// || open(peer, ctx); // TODO: Reopen! + if(!wire){ return } + msh = msg.mesh || empty; + if(peer === msh.via){ return } + if(!(raw = msh.raw)){ raw = mesh.raw(msg) } + if((tmp = msg['@']) + && (tmp = ctx.dup.s[tmp]) + && (tmp = tmp.it)){ + if(tmp.get && tmp['##'] && tmp['##'] === msg['##']){ // PERF: move this condition outside say? + return; // TODO: this still needs to be tested in the browser! + } + } + if((tmp = msh.to) && (tmp[peer.url] || tmp[peer.id])){ return } // TODO: still needs to be tested + if(peer.batch){ + peer.batch.push(raw); + return; + } + peer.batch = []; + setTimeout(function(){ + var tmp = peer.batch; + if(!tmp){ return } + peer.batch = null; + if(!tmp.length){ return } + send(JSON.stringify(tmp), peer); + }, ctx.opt.wait || 1); + send(raw, peer); + } + function send(raw, peer){ + var wire = peer.wire; + try{ + if(wire.send){ + if(wire.readyState === wire.OPEN){ + wire.send(raw); + } else { + (peer.queue = peer.queue || []).push(raw); + } + } else + if(peer.say){ + peer.say(raw); + } + }catch(e){ + (peer.queue = peer.queue || []).push(raw); + } + } + + }()); + + ;(function(){ + + mesh.raw = function(msg){ + if(!msg){ return '' } + var dup = ctx.dup, msh = msg.mesh || {}, put, hash, tmp; + if(tmp = msh.raw){ return tmp } + if(typeof msg === 'string'){ return msg } + if(msg['@'] && (tmp = msg.put)){ + if(!(hash = msg['##'])){ + put = $(tmp, sort) || ''; + hash = mesh.hash(msg, put); + msg['##'] = hash; + } + (tmp = dup.s)[hash = msg['@']+hash] = tmp[msg['#']]; + msg['#'] = hash; + if(put){ (msg = Type.obj.to(msg)).put = _ } + } + msg['><'] = (Type.obj.map(ctx.opt.peers, function(p,k,m){ + m(p.url || p.id); + }) || []).join(); + var raw = $(msg); + if(u !== put){ + raw = raw.replace('"'+ _ +'"', put); + } + if(msh){ + msh.raw = raw; + } + return raw; + } + + mesh.hash = function(msg, hash){ + return Mesh.hash(hash || $(msg.put, sort) || '') || msg['#'] || Type.text.random(9); + } + + function sort(k, v){ var tmp; + if(!(v instanceof Object)){ return v } + Type.obj.map(Object.keys(v).sort(), map, {to: tmp = {}, on: v}); + return tmp; + } + + function map(k){ + this.to[k] = this.on[k]; + } + var $ = JSON.stringify, _ = ':])([:' + + }()); + + mesh.hi = function(peer){ + ctx.on('hi', peer); + var queue = peer.queue; + peer.queue = []; + Type.obj.map(queue, function(msg){ + mesh.say(msg, peer); + }); + } + + return mesh; +} + +Mesh.hash = function(s){ // via SO + if(typeof s !== 'string'){ return {err: 1} } + var c = 0; + if(!s.length){ return c } + for(var i=0,l=s.length,n; i (time_is() - time)){ return } + Type.obj.map(dup.s, function(it, id){ + if(opt.age > (time_is() - it.was)){ return } Type.obj.del(dup.s, id); }); dup.to = null; }, opt.age); } - return id; + return it; } return dup; } diff --git a/src/on.js b/src/on.js index b63eb80a..4b76dbbc 100644 --- a/src/on.js +++ b/src/on.js @@ -53,6 +53,10 @@ function ok(at, ev){ var opt = this; } Gun.chain.val = function(cb, opt){ + Gun.log.once("onceval", "Future Breaking API Change: .val -> .once, apologies unexpected."); + return this.once(cb, opt); +} +Gun.chain.once = function(cb, opt){ var gun = this, at = gun._, data = at.put; if(0 < at.ack && u !== data){ (cb || noop).call(gun, data, at.get); @@ -67,7 +71,7 @@ Gun.chain.val = function(cb, opt){ } else { Gun.log.once("valonce", "Chainable val is experimental, its behavior and API may change moving forward. Please play with it and report bugs and ideas on how to improve it."); var chain = gun.chain(); - chain._.val = gun.val(function(){ + chain._.val = gun.once(function(){ chain._.on('in', gun._); }); return chain; diff --git a/src/root.js b/src/root.js index e9616342..ef1eea78 100644 --- a/src/root.js +++ b/src/root.js @@ -40,13 +40,13 @@ Gun.dup = require('./dup'); return gun; } function root(msg){ - //console.log("add to.next(at)"); // TODO: BUG!!! - var ev = this, at = ev.as, gun = at.gun, tmp; + //console.log("add to.next(at)"); // TODO: MISSING FEATURE!!! + var ev = this, at = ev.as, gun = at.gun, dup, tmp; //if(!msg.gun){ msg.gun = at.gun } if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) } - if(at.dup.check(tmp)){ return } - at.dup.track(tmp); - msg = obj_to(msg);//, {gun: at.gun}); + if((dup = at.dup).check(tmp)){ return } + dup.track(tmp); + //msg = obj_to(msg);//, {gun: at.gun}); // can we delete this now? if(!at.ask(msg['@'], msg)){ if(msg.get){ Gun.on.get(msg, gun); @@ -159,7 +159,7 @@ Gun.dup = require('./dup'); //tmp = at.ack; root.on('in', { '@': msg['#'], - //how: 'mem', + how: 'mem', put: node, gun: gun }); diff --git a/test/panic/b2s2s2b.js b/test/panic/b2s2s2b.js index b0fc8da0..457a6855 100644 --- a/test/panic/b2s2s2b.js +++ b/test/panic/b2s2s2b.js @@ -1,8 +1,8 @@ var config = { IP: require('ip').address(), port: 8080, - servers: 4, - browsers: 4, + servers: 2, + browsers: 2, each: 10000, burst: 100, wait: 1, From 78044347373d04e1ac9848fdd4d4c68e313f7a7c Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 13 Mar 2018 10:14:45 -0700 Subject: [PATCH 6/6] bump version for mesh networking optimizations! +5X efficiency! --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2adf0d0e..8ed49796 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.96", + "version": "0.9.97", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.", "main": "index.js", "browser": "gun.min.js",