have NTS use DAM + fix other utils

This commit is contained in:
Mark Nadal 2020-09-15 04:22:51 -07:00
parent 356a971ddc
commit bac0e5b7ed
6 changed files with 68 additions and 76 deletions

View File

@ -181,7 +181,7 @@
$('.chat__message-input').val('').focus(); $('.chat__message-input').val('').focus();
} }
chat.map().val(function (msg, id) { chat.map().once(function (msg, id) {
if (!msg) { return } if (!msg) { return }
var messageList = $('.chat__message-list'); var messageList = $('.chat__message-list');
var last = sort(msg.when, messageList.children('li').last()); var last = sort(msg.when, messageList.children('li').last());

50
gun.js
View File

@ -189,18 +189,17 @@
} }
var dt = dup.track = function(id){ var dt = dup.track = function(id){
var it = s[id] || (s[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) } if(!dup.to){ dup.to = setTimeout(dup.drop, opt.age + 9) }
return it; return it;
} }
dup.drop = function(age){ 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; 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; return dup;
} }
@ -288,6 +287,7 @@
DBG && (DBG.uc = +new Date); DBG && (DBG.uc = +new Date);
eve.to.next(msg); eve.to.next(msg);
DBG && (DBG.ua = +new Date); 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); msg.out = universe; at.on('out', msg);
DBG && (DBG.ue = +new Date); DBG && (DBG.ue = +new Date);
} }
@ -324,7 +324,7 @@
if(!(tmp = node._)){ err = ERR+cut(soul)+"no meta." } else if(!(tmp = node._)){ err = ERR+cut(soul)+"no meta." } else
if(soul !== tmp['#']){ err = ERR+cut(soul)+"soul not same." } else if(soul !== tmp['#']){ err = ERR+cut(soul)+"soul not same." } else
if(!(states = tmp['>'])){ err = ERR+cut(soul)+"no state." } if(!(states = tmp['>'])){ err = ERR+cut(soul)+"no state." }
kl = Object.keys(node||{}); kl = Object.keys(node||{}); // TODO: .keys( is slow
} }
if(err){ if(err){
console.log("handle error!", err) // handle! 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 //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||'')._||'')['#']; 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(){ node && (function got(){
var i = 0, k, put = {}; var i = 0, k, put = {};
while(i < 9 && (k = keys[i++])){ 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; 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 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 } if('_' == k || !(state = state_is(tmp, k))){ return }
cat.on('in', {put: {'#': tmp._['#'], '.': k, ':': tmp[k], '>': state}}); cat.on('in', {put: {'#': tmp._['#'], '.': k, ':': tmp[k], '>': state}});
}); });
@ -648,10 +648,10 @@
} else {} } else {}
eve.to.next(msg); // 1st API job is to call all the listeners. 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); (act = cat.act[act]) && act(msg);
},0,99); },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 } if(!(lat = cat.echo[lat])){ return }
lat.on('in', msg); lat.on('in', msg);
},0,99); },0,99);
@ -659,7 +659,7 @@
if(u === change){ // 1st edge case: If we have a brand new database, no data will be found. 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. 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.? 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 } if(!(sat = cat.next[get])){ return }
sat.on('in', {get: get, put: u, $: sat.$}); sat.on('in', {get: get, put: u, $: sat.$});
},0,99); },0,99);
@ -679,7 +679,7 @@
if((tmp = cat.ask||'')['']){ if((tmp = cat.ask||'')['']){
sat.on('out', {get: {'#': link}}); sat.on('out', {get: {'#': link}});
} else { } 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 } if(!(sat = cat.ask[get])){ return }
sat.on('out', {get: {'#': link, '.': get}}); // go get it. sat.on('out', {get: {'#': link, '.': get}}); // go get it.
},0,99); },0,99);
@ -781,7 +781,7 @@
if(cat.jam){ return cat.jam.push([cb, as]) } if(cat.jam){ return cat.jam.push([cb, as]) }
cat.jam = [[cb,as]]; cat.jam = [[cb,as]];
gun.get(function go(msg, eve){ 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; return;
} }
eve.rid(msg); eve.rid(msg);
@ -878,7 +878,7 @@
} }
if(k && v){ at.node = state_ify(at.node, k, s, d) } // handle soul later. if(k && v){ at.node = state_ify(at.node, k, s, d) } // handle soul later.
else { 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); at.node = state_ify(at.node, k, s, cat.link);
!g && to.push(cat); !g && to.push(cat);
// --------------- // ---------------
@ -922,7 +922,7 @@
}, as.opt), acks = 0, stun = as.stun; }, as.opt), acks = 0, stun = as.stun;
if((tmp = cat.root.stun) && --tmp._ === 0){ delete cat.root.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. (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 ^ }).hatch = tmp; // this is not official yet ^
(as.via._).on('out', {put: as.out = as.graph, opt: as.opt, '#': ask, _: tmp}); (as.via._).on('out', {put: as.out = as.graph, opt: as.opt, '#': ask, _: tmp});
} }
@ -1023,29 +1023,29 @@
at.ack = 0; // so can resubscribe. at.ack = 0; // so can resubscribe.
if(tmp = cat.next){ if(tmp = cat.next){
if(tmp[at.get]){ if(tmp[at.get]){
obj_del(tmp, at.get); delete tmp[at.get];
} else { } else {
} }
} }
if(tmp = cat.ask){ if(tmp = cat.ask){
obj_del(tmp, at.get); delete tmp[at.get];
} }
if(tmp = cat.put){ if(tmp = cat.put){
obj_del(tmp, at.get); delete tmp[at.get];
} }
if(tmp = at.soul){ if(tmp = at.soul){
obj_del(cat.root.graph, tmp); delete cat.root.graph[tmp];
} }
if(tmp = at.map){ 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){ if(at.link){
cat.root.$.get(at.link).off(); cat.root.$.get(at.link).off();
} }
}); });
} }
if(tmp = at.next){ 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(); neat.$.off();
}); });
} }
@ -1228,7 +1228,7 @@
if(!peer && mesh.way){ return mesh.way(msg) } if(!peer && mesh.way){ return mesh.way(msg) }
if(!peer || !peer.id){ if(!peer || !peer.id){
if(!Object.plain(peer || opt.peers)){ return false } 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(){ ;(function go(){
var S = +new Date; var S = +new Date;
//Type.obj.map(peer || opt.peers, each); // in case peer is a peer list. //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); root.on('hi', function(peer, tmp){ this.to.next(peer);
if(!(tmp = peer.url) || !gets[tmp]){ return } delete gets[tmp]; if(!(tmp = peer.url) || !gets[tmp]){ return } delete gets[tmp];
if(opt.super){ return } // temporary (?) until we have better fix/solution? 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. tmp = {}; tmp[soul] = root.graph[soul]; tmp = String.hash(tmp); // TODO: BUG! This is broken.
mesh.say({'##': tmp, get: {'#': soul}}, peer); mesh.say({'##': tmp, get: {'#': soul}}, peer);
}); });

View File

@ -25,11 +25,10 @@
var S = +new Date; var S = +new Date;
var souls = Object.keys(root.graph||empty); var souls = Object.keys(root.graph||empty);
var toss = Math.ceil(souls.length * 0.01); var toss = Math.ceil(souls.length * 0.01);
//var S = +new Date; setTimeout.each(souls, function(soul){
Gun.list.map(souls, function(soul){ if(--toss < 0){ return 1 }
if(--toss < 0){ return }
root.$.get(soul).off(); root.$.get(soul).off();
}); },0,99);
root.dup.drop(1000 * 9); // clean up message tracker root.dup.drop(1000 * 9); // clean up message tracker
console.STAT && console.STAT(S, +new Date - S, 'evict'); console.STAT && console.STAT(S, +new Date - S, 'evict');
} }

View File

@ -41,9 +41,9 @@ Gun.on('opt', function(root){
stats.cpu = process.cpuUsage() || {}; stats.cpu = process.cpuUsage() || {};
stats.cpu.loadavg = os.loadavg(); stats.cpu.loadavg = os.loadavg();
stats.peers = {}; 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 = {};
stats.node.count = Object.keys(root.graph||{}).length; stats.node.count = Object.keys(root.graph||{}).length; // TODO: .keys( is slow
stats.all = all; stats.all = all;
var dam = root.opt.mesh; var dam = root.opt.mesh;
if(dam){ if(dam){
@ -58,16 +58,18 @@ Gun.on('opt', function(root){
} }
console.STAT && console.STAT(S, +new Date - S, 'stats'); console.STAT && console.STAT(S, +new Date - S, 'stats');
S = +new Date; 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.over = S;
stats.gap = {}; stats.gap = {};
exec("top -b -n 1", function(err, out){ out && fs.writeFile(__dirname+'/../stats.top.'+root.opt.file, out, noop) }); exec("top -b -n 1", function(err, out){ out && fs.writeFile(__dirname+'/../stats.top.'+root.opt.file, out, noop) });
}, 1000 * 15); }, 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(){}; var exec = require("child_process").exec, noop = function(){};
require('./yson');
var log = Gun.log, all = {}, max = 1000; var log = Gun.log, all = {}, max = 1000;
Gun.log = console.STAT = function(a,b,c,d){ Gun.log = console.STAT = function(a,b,c,d){

View File

@ -4,7 +4,7 @@ Gun.on('create', function(root){
if(Gun.TESTING){ root.opt.file = 'radatatest' } if(Gun.TESTING){ root.opt.file = 'radatatest' }
this.to.next(root); this.to.next(root);
var opt = root.opt, empty = {}, u; 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 Radisk = (Gun.window && Gun.window.Radisk) || require('./radisk');
var Radix = Radisk.Radix; var Radix = Radisk.Radix;
var dare = Radisk(opt), esc = String.fromCharCode(27); var dare = Radisk(opt), esc = String.fromCharCode(27);

61
nts.js
View File

@ -1,49 +1,40 @@
;(function(){ ;(function(){
// NOTE: While the algorithm is P2P, var Gun = (typeof window !== "undefined")? window.Gun : require('./gun');
// 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') }
}
Gun.on('opt', function(ctx){ Gun.on('create', function(root){ // switch to DAM, deprecated old
this.to.next(ctx); var opt = root.opt, mesh = opt.mesh;
if(ctx.once){ return } if(!mesh){ return }
ctx.on('in', function(at){ var asks = {};
if(!at.nts && !at.NTS){ mesh.hear['nts'] = function(msg, peer){
return this.to.next(at); if(msg.nts){
} (asks[msg['@']]||noop)(msg);
if(at['@']){
(ask[at['@']]||noop)(at);
return; return;
} }
if(env.window){ mesh.say({dam: 'nts', nts: Gun.state(), '@': msg['#']}, peer);
return this.to.next(at);
} }
this.to.next({'@': at['#'], nts: Gun.time.is()}); var peers = 0;
}); root.on('hi', function(peer){ this.to.next(peer);
var ask = {}, noop = function(){}; peers++;
if(!env.window){ return }
Gun.state.drift = Gun.state.drift || 0;
setTimeout(function ping(){ setTimeout(function ping(){
var NTS = {}, ack = Gun.text.random(), msg = {'#': ack, nts: true}; var NTS = {}, ack = String.random(3), msg = {'#': ack, dam: 'nts'};
NTS.start = Gun.state(); NTS.start = Gun.state();
ask[ack] = function(at){ asks[ack] = function(msg){
NTS.end = Gun.state(); NTS.end = Gun.state();
Gun.obj.del(ask, ack); delete asks[ack];
NTS.latency = (NTS.end - NTS.start)/2; NTS.latency = (NTS.end - NTS.start)/2;
if(!at.nts && !at.NTS){ return } if(!msg.nts){ return }
NTS.calc = NTS.latency + (at.NTS || at.nts); NTS.calc = NTS.latency + msg.nts;
Gun.state.drift -= (NTS.end - NTS.calc)/2; NTS.step = (NTS.end - NTS.calc)/2;
setTimeout(ping, 1000); 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
} }
ctx.on('out', msg); mesh.say(msg, peer);
}, 1); }, 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. // test by opening up examples/game/nts.html on devices that aren't NTP synced.
}()); }());