diff --git a/examples/chat/index.html b/examples/chat/index.html index c15f4229..8a3c74aa 100644 --- a/examples/chat/index.html +++ b/examples/chat/index.html @@ -181,7 +181,7 @@ $('.chat__message-input').val('').focus(); } - chat.map().val(function (msg, id) { + chat.map().once(function (msg, id) { if (!msg) { return } var messageList = $('.chat__message-list'); var last = sort(msg.when, messageList.children('li').last()); diff --git a/gun.js b/gun.js index fbb69a1e..0de16b90 100644 --- a/gun.js +++ b/gun.js @@ -189,18 +189,17 @@ } var dt = dup.track = function(id){ var it = s[id] || (s[id] = {}); - it.was = +new Date; + it.was = dup.now = +new Date; if(!dup.to){ dup.to = setTimeout(dup.drop, opt.age + 9) } return it; } dup.drop = function(age){ - var now = +new Date; - Object.keys(s).forEach(function(id){ var it = s[id]; - if(it && (age || opt.age) > (now - it.was)){ return } - delete s[id]; - }); dup.to = null; - console.STAT && (age = +new Date - now) > 9 && console.STAT(now, age, 'dup drop'); + dup.now = +new Date; + setTimeout.each(Object.keys(s), function(id){ var it = s[id]; // TODO: .keys( is slow + if(it && (age || opt.age) > (dup.now - it.was)){ return } + delete s[id]; + },0,99); } return dup; } @@ -288,6 +287,7 @@ DBG && (DBG.uc = +new Date); eve.to.next(msg); DBG && (DBG.ua = +new Date); + if(msg.nts || msg.NTS){ return } // TODO: This shouldn't be in core, but fast way to prevent NTS spread. Delete this line after all peers have upgraded to newer versions. msg.out = universe; at.on('out', msg); DBG && (DBG.ue = +new Date); } @@ -324,7 +324,7 @@ if(!(tmp = node._)){ err = ERR+cut(soul)+"no meta." } else if(soul !== tmp['#']){ err = ERR+cut(soul)+"soul not same." } else if(!(states = tmp['>'])){ err = ERR+cut(soul)+"no state." } - kl = Object.keys(node||{}); + kl = Object.keys(node||{}); // TODO: .keys( is slow } if(err){ console.log("handle error!", err) // handle! @@ -411,7 +411,7 @@ } //Gun.window? Gun.obj.copy(node) : node; // HNPERF: If !browser bump Performance? Is this too dangerous to reference root graph? Copy / shallow copy too expensive for big nodes. Gun.obj.to(node); // 1 layer deep copy // Gun.obj.copy(node); // too slow on big nodes var ack = msg['#'], id = text_rand(9), keys = Object.keys(node||''), soul = ((node||'')._||'')['#']; - // PERF: Consider commenting this out to force disk-only reads for perf testing? + // PERF: Consider commenting this out to force disk-only reads for perf testing? // TODO: .keys( is slow node && (function got(){ var i = 0, k, put = {}; while(i < 9 && (k = keys[i++])){ @@ -618,7 +618,7 @@ var eve = this, cat = eve.as, root = cat.root, gun = msg.$ || (msg.$ = cat.$), at = (gun||'')._ || empty, tmp = msg.put||'', soul = tmp['#'], key = tmp['.'], change = tmp['=']||tmp[':'], state = tmp['>'] || -Infinity, link, sat; if(tmp && tmp._ && tmp._['#']){ // convert from old format - return setTimeout.each(Object.keys(tmp).sort(), function(k){ + return setTimeout.each(Object.keys(tmp).sort(), function(k){ // TODO: .keys( is slow if('_' == k || !(state = state_is(tmp, k))){ return } cat.on('in', {put: {'#': tmp._['#'], '.': k, ':': tmp[k], '>': state}}); }); @@ -648,10 +648,10 @@ } else {} eve.to.next(msg); // 1st API job is to call all the listeners. - setTimeout.each(Object.keys(cat.act||''), function(act){ // 1st API job is to call all chain listeners. + setTimeout.each(Object.keys(cat.act||''), function(act){ // 1st API job is to call all chain listeners. // TODO: .keys( is slow (act = cat.act[act]) && act(msg); },0,99); - setTimeout.each(Object.keys(cat.echo||''), function(lat){ // & linked chains + setTimeout.each(Object.keys(cat.echo||''), function(lat){ // & linked chains // TODO: .keys( is slow if(!(lat = cat.echo[lat])){ return } lat.on('in', msg); },0,99); @@ -659,7 +659,7 @@ if(u === change){ // 1st edge case: If we have a brand new database, no data will be found. cat.put = u; // empty out the cache if, for example, alice's car's color no longer exists (relative to alice) if alice no longer has a car. delete cat.link; // TODO: Empty out links, maps, echos, acks/asks, etc.? - setTimeout.each(Object.keys(cat.next||''), function(get, sat){ // empty out all sub properties. + setTimeout.each(Object.keys(cat.next||''), function(get, sat){ // empty out all sub properties. // TODO: .keys( is slow if(!(sat = cat.next[get])){ return } sat.on('in', {get: get, put: u, $: sat.$}); },0,99); @@ -679,7 +679,7 @@ if((tmp = cat.ask||'')['']){ sat.on('out', {get: {'#': link}}); } else { - setTimeout.each(Object.keys(tmp), function(get, sat){ // if sub chains are asking for data. + setTimeout.each(Object.keys(tmp), function(get, sat){ // if sub chains are asking for data. // TODO: .keys( is slow if(!(sat = cat.ask[get])){ return } sat.on('out', {get: {'#': link, '.': get}}); // go get it. },0,99); @@ -781,7 +781,7 @@ if(cat.jam){ return cat.jam.push([cb, as]) } cat.jam = [[cb,as]]; gun.get(function go(msg, eve){ - if(u === msg.put && !cat.root.opt.super && (tmp = Object.keys(cat.root.opt.peers).length) && ++acks <= tmp){ // TODO: super should not be in core code, bring AXE up into core instead to fix? + if(u === msg.put && !cat.root.opt.super && (tmp = Object.keys(cat.root.opt.peers).length) && ++acks <= tmp){ // TODO: super should not be in core code, bring AXE up into core instead to fix? // TODO: .keys( is slow return; } eve.rid(msg); @@ -878,7 +878,7 @@ } if(k && v){ at.node = state_ify(at.node, k, s, d) } // handle soul later. else { - as.seen.push(cat = {it: d, link: {}, todo: g? [] : Object.keys(d).sort().reverse()}); + as.seen.push(cat = {it: d, link: {}, todo: g? [] : Object.keys(d).sort().reverse()}); // Any perf reasons to CPU schedule this .keys( ? at.node = state_ify(at.node, k, s, cat.link); !g && to.push(cat); // --------------- @@ -922,7 +922,7 @@ }, as.opt), acks = 0, stun = as.stun; if((tmp = cat.root.stun) && --tmp._ === 0){ delete cat.root.stun } (tmp = function(){ // this is not official yet, but quick solution to hack in for now. - setTimeout.each(Object.keys(stun||''), function(cb){if(cb = stun[cb]){cb()}}); + setTimeout.each(Object.keys(stun||''), function(cb){if(cb = stun[cb]){cb()}}); // Any perf reasons to CPU schedule this .keys( ? }).hatch = tmp; // this is not official yet ^ (as.via._).on('out', {put: as.out = as.graph, opt: as.opt, '#': ask, _: tmp}); } @@ -1023,29 +1023,29 @@ at.ack = 0; // so can resubscribe. if(tmp = cat.next){ if(tmp[at.get]){ - obj_del(tmp, at.get); + delete tmp[at.get]; } else { } } if(tmp = cat.ask){ - obj_del(tmp, at.get); + delete tmp[at.get]; } if(tmp = cat.put){ - obj_del(tmp, at.get); + delete tmp[at.get]; } if(tmp = at.soul){ - obj_del(cat.root.graph, tmp); + delete cat.root.graph[tmp]; } if(tmp = at.map){ - obj_map(tmp, function(at){ + Object.keys(tmp).forEach(function(i,at){ at = tmp[i]; //obj_map(tmp, function(at){ if(at.link){ cat.root.$.get(at.link).off(); } }); } if(tmp = at.next){ - obj_map(tmp, function(neat){ + Object.keys(tmp).forEach(function(i,neat){ neat = tmp[i]; //obj_map(tmp, function(neat){ neat.$.off(); }); } @@ -1228,7 +1228,7 @@ if(!peer && mesh.way){ return mesh.way(msg) } if(!peer || !peer.id){ if(!Object.plain(peer || opt.peers)){ return false } - var P = opt.puff, ps = opt.peers, pl = Object.keys(peer || opt.peers || {}); + var P = opt.puff, ps = opt.peers, pl = Object.keys(peer || opt.peers || {}); // TODO: .keys( is slow ;(function go(){ var S = +new Date; //Type.obj.map(peer || opt.peers, each); // in case peer is a peer list. @@ -1390,7 +1390,7 @@ root.on('hi', function(peer, tmp){ this.to.next(peer); if(!(tmp = peer.url) || !gets[tmp]){ return } delete gets[tmp]; if(opt.super){ return } // temporary (?) until we have better fix/solution? - setTimeout.each(Object.keys(root.next), function(soul){ var node = root.next[soul]; + setTimeout.each(Object.keys(root.next), function(soul){ var node = root.next[soul]; // TODO: .keys( is slow tmp = {}; tmp[soul] = root.graph[soul]; tmp = String.hash(tmp); // TODO: BUG! This is broken. mesh.say({'##': tmp, get: {'#': soul}}, peer); }); diff --git a/lib/evict.js b/lib/evict.js index a4c144c0..7d6ff269 100644 --- a/lib/evict.js +++ b/lib/evict.js @@ -25,11 +25,10 @@ var S = +new Date; var souls = Object.keys(root.graph||empty); var toss = Math.ceil(souls.length * 0.01); - //var S = +new Date; - Gun.list.map(souls, function(soul){ - if(--toss < 0){ return } + setTimeout.each(souls, function(soul){ + if(--toss < 0){ return 1 } root.$.get(soul).off(); - }); + },0,99); root.dup.drop(1000 * 9); // clean up message tracker console.STAT && console.STAT(S, +new Date - S, 'evict'); } diff --git a/lib/stats.js b/lib/stats.js index 0f87d53e..c83dcdf8 100644 --- a/lib/stats.js +++ b/lib/stats.js @@ -41,9 +41,9 @@ Gun.on('opt', function(root){ stats.cpu = process.cpuUsage() || {}; stats.cpu.loadavg = os.loadavg(); stats.peers = {}; - stats.peers.count = Object.keys(root.opt.peers||{}).length; + stats.peers.count = Object.keys(root.opt.peers||{}).length; // TODO: .keys( is slow stats.node = {}; - stats.node.count = Object.keys(root.graph||{}).length; + stats.node.count = Object.keys(root.graph||{}).length; // TODO: .keys( is slow stats.all = all; var dam = root.opt.mesh; if(dam){ @@ -58,16 +58,18 @@ Gun.on('opt', function(root){ } console.STAT && console.STAT(S, +new Date - S, 'stats'); S = +new Date; - fs.writeFile(__dirname+'/../stats.'+root.opt.file, JSON.stringify(stats, null, 2), function(err){ console.STAT && console.STAT(S, +new Date - S, 'stats stash') }); + JSON.stringifyAsync(stats, function(err, raw){ if(err){ return } + fs.writeFile(__dirname+'/../stats.'+root.opt.file, raw, function(err){ console.STAT && console.STAT(S, +new Date - S, 'stats stash') }); + }); stats.over = S; stats.gap = {}; exec("top -b -n 1", function(err, out){ out && fs.writeFile(__dirname+'/../stats.top.'+root.opt.file, out, noop) }); }, 1000 * 15); - Object.keys = Object.keys || function(o){ return Gun.obj.map(o, function(v,k,t){t(k)}) } }); var exec = require("child_process").exec, noop = function(){}; +require('./yson'); var log = Gun.log, all = {}, max = 1000; Gun.log = console.STAT = function(a,b,c,d){ diff --git a/lib/store.js b/lib/store.js index 58102b68..0e990209 100644 --- a/lib/store.js +++ b/lib/store.js @@ -4,7 +4,7 @@ Gun.on('create', function(root){ if(Gun.TESTING){ root.opt.file = 'radatatest' } this.to.next(root); var opt = root.opt, empty = {}, u; - if(false === opt.radisk){ return } + if(false === opt.rad || false === opt.radisk){ return } var Radisk = (Gun.window && Gun.window.Radisk) || require('./radisk'); var Radix = Radisk.Radix; var dare = Radisk(opt), esc = String.fromCharCode(27); diff --git a/nts.js b/nts.js index c0ee6b5b..63788fe3 100644 --- a/nts.js +++ b/nts.js @@ -1,49 +1,40 @@ ;(function(){ - // NOTE: While the algorithm is P2P, - // the current implementation is one sided, - // only browsers self-modify, servers do not. - // Need to fix this! Since WebRTC is now working. - var env; - if(typeof global !== "undefined"){ env = global } - if(typeof window !== "undefined"){ var Gun = (env = window).Gun } - else { - if(typeof require !== "undefined"){ var Gun = require('./gun') } - } + var Gun = (typeof window !== "undefined")? window.Gun : require('./gun'); - Gun.on('opt', function(ctx){ - this.to.next(ctx); - if(ctx.once){ return } - ctx.on('in', function(at){ - if(!at.nts && !at.NTS){ - return this.to.next(at); - } - if(at['@']){ - (ask[at['@']]||noop)(at); + Gun.on('create', function(root){ // switch to DAM, deprecated old + var opt = root.opt, mesh = opt.mesh; + if(!mesh){ return } + var asks = {}; + mesh.hear['nts'] = function(msg, peer){ + if(msg.nts){ + (asks[msg['@']]||noop)(msg); return; } - if(env.window){ - return this.to.next(at); - } - this.to.next({'@': at['#'], nts: Gun.time.is()}); + mesh.say({dam: 'nts', nts: Gun.state(), '@': msg['#']}, peer); + } + var peers = 0; + root.on('hi', function(peer){ this.to.next(peer); + peers++; + setTimeout(function ping(){ + var NTS = {}, ack = String.random(3), msg = {'#': ack, dam: 'nts'}; + NTS.start = Gun.state(); + asks[ack] = function(msg){ + NTS.end = Gun.state(); + delete asks[ack]; + NTS.latency = (NTS.end - NTS.start)/2; + if(!msg.nts){ return } + NTS.calc = NTS.latency + msg.nts; + NTS.step = (NTS.end - NTS.calc)/2; + Gun.state.drift -= NTS.step * (1/(peers||1)); + NTS.next = Math.min(2e4, Math.max(250, 150000 / Math.abs((NTS.end - NTS.calc)||1))); + console.log("I am now", Gun.state(), "they are", NTS.calc, "time sync in", NTS.next/1000, 'sec.'); + setTimeout(ping, NTS.next); // Thanks @finwo ! https://discord.com/channels/612645357850984470/612645357850984473/755334349699809300 + } + mesh.say(msg, peer); + }, 1); }); - var ask = {}, noop = function(){}; - if(!env.window){ return } - - Gun.state.drift = Gun.state.drift || 0; - setTimeout(function ping(){ - var NTS = {}, ack = Gun.text.random(), msg = {'#': ack, nts: true}; - NTS.start = Gun.state(); - ask[ack] = function(at){ - NTS.end = Gun.state(); - Gun.obj.del(ask, ack); - NTS.latency = (NTS.end - NTS.start)/2; - if(!at.nts && !at.NTS){ return } - NTS.calc = NTS.latency + (at.NTS || at.nts); - Gun.state.drift -= (NTS.end - NTS.calc)/2; - setTimeout(ping, 1000); - } - ctx.on('out', msg); - }, 1); + root.on('bye', function(peer){ --peers; this.to.next(peer) }); }); + // test by opening up examples/game/nts.html on devices that aren't NTP synced. }()); \ No newline at end of file