temporary push for @Dletta to update stats

This commit is contained in:
Mark Nadal 2019-10-25 15:44:07 -07:00
parent d387a4f790
commit 026b278311
14 changed files with 317 additions and 74 deletions

69
examples/docs.html Normal file
View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html>
<head>
<!-- always start with these two lines to set a clean baseline for different devices -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="style.css">
<script src="jquery.js"></script>
<title>Docs</title>
</head>
<body class="black whitet">
<style>
/*
Choose white text on a black background so you can add color in.
Pick your favorite font and choose a font size.
*/
@import url('https://fonts.googleapis.com/css?family=Oxygen');
html, body {
font-family: "Oxygen", sans-serif;
}
[contenteditable]:focus {
outline: none;
}
</style>
<div class="hold full hue2">
<div id="page" class="max focus gap" style="padding-top: 9%;">
<p class="loud crack">Docs</p>
<p id="p1">The contemporary tendency in our society is to base our distribution on scarcity, which has vanished, and to compress our abundance into the overfed mouths of the middle and upper classes until they gag with superfluity. If democracy is to have breadth of meaning, it is necessary to adjust this inequity. It is not only moral, but it is also intelligent. We are wasting and degrading human life by clinging to archaic thinking.</p>
</div>
</div>
<script src="../../gun/gun.js"></script>
<script src="../../gun/lib/meta.js"></script>
<script>
var gun = Gun('https://guntest.herokuapp.com/gun');
;(window.onhashchange = function(){
var file = (location.hash||'').slice(1);
var S = +new Date;
gun.get('test/gun/docs/'+file).get('what').once(function(data){
console.log(+new Date - S, 'ms load');
$('#p1').text(data);
});
})();
meta.edit({
name: "Edit",
combo: ['E'],
on: function(eve){
console.log("TRIGGERED!!!!");
meta.tap.on.attr('contenteditable', 'true');
},
up: function(){}
});
meta.edit({
name: "Save",
combo: ['S'], fake: -1,
on: function(eve){
meta.tap.on.attr('contenteditable', 'false');
var what = $('#p1').text();
var file = (location.hash||'').slice(1);
gun.get('test/gun/docs/'+file).put({what: what});
},
up: function(){}
});
</script>
</body>
</html>

43
gun.js
View File

@ -811,20 +811,16 @@
// Maybe... in case the in-memory key we have is a local write // Maybe... in case the in-memory key we have is a local write
// we still need to trigger a pull/merge from peers. // we still need to trigger a pull/merge from peers.
} else { } else {
//var S = +new Date;
node = Gun.obj.copy(node); node = Gun.obj.copy(node);
//console.log(+new Date - S, 'copy node');
} }
node = Gun.graph.node(node); node = Gun.graph.node(node);
tmp = (at||empty).ack; tmp = (at||empty).ack;
//var S = +new Date;
root.on('in', { root.on('in', {
'@': msg['#'], '@': msg['#'],
how: 'mem', how: 'mem',
put: node, put: node,
$: gun $: gun
}); });
//console.log(+new Date - S, 'root got send');
//if(0 < tmp){ return } //if(0 < tmp){ return }
root.on('get', msg); root.on('get', msg);
} }
@ -1317,7 +1313,6 @@
function use(msg){ function use(msg){
var eve = this, as = eve.as, cat = as.at, root = cat.root, gun = msg.$, at = (gun||{})._ || {}, data = msg.put || at.put, tmp; var eve = this, as = eve.as, cat = as.at, root = cat.root, gun = msg.$, at = (gun||{})._ || {}, data = msg.put || at.put, tmp;
if((tmp = root.now) && eve !== tmp[as.now]){ return eve.to.next(msg) } if((tmp = root.now) && eve !== tmp[as.now]){ return eve.to.next(msg) }
//console.log("USE:", cat.id, cat.soul, cat.has, cat.get, msg, root.mum);
//if(at.async && msg.root){ return } //if(at.async && msg.root){ return }
//if(at.async === 1 && cat.async !== true){ return } //if(at.async === 1 && cat.async !== true){ return }
//if(root.stop && root.stop[at.id]){ return } root.stop && (root.stop[at.id] = true); //if(root.stop && root.stop[at.id]){ return } root.stop && (root.stop[at.id] = true);
@ -1545,7 +1540,7 @@
as = as.as; as = as.as;
if(!msg.$ || !msg.$._){ return } // TODO: Handle if(!msg.$ || !msg.$._){ return } // TODO: Handle
if(msg.err){ // TODO: Handle if(msg.err){ // TODO: Handle
console.log("Please report this as an issue! Put.any.err"); Gun.log("Please report this as an issue! Put.any.err");
return; return;
} }
var at = (msg.$._), data = at.put, opt = as.opt||{}, root, tmp; var at = (msg.$._), data = at.put, opt = as.opt||{}, root, tmp;
@ -1554,7 +1549,7 @@
if(as.ref !== as.$){ if(as.ref !== as.$){
tmp = (as.$._).get || at.get; tmp = (as.$._).get || at.get;
if(!tmp){ // TODO: Handle if(!tmp){ // TODO: Handle
console.log("Please report this as an issue! Put.no.get"); // TODO: BUG!?? Gun.log("Please report this as an issue! Put.no.get"); // TODO: BUG!??
return; return;
} }
as.data = obj_put({}, tmp, as.data); as.data = obj_put({}, tmp, as.data);
@ -1814,7 +1809,7 @@
var root, noop = function(){}, store, u; var root, noop = function(){}, store, u;
try{store = (Gun.window||noop).localStorage}catch(e){} try{store = (Gun.window||noop).localStorage}catch(e){}
if(!store){ if(!store){
console.log("Warning: No localStorage exists to persist data to!"); Gun.log("Warning: No localStorage exists to persist data to!");
store = {setItem: function(k,v){this[k]=v}, removeItem: function(k){delete this[k]}, getItem: function(k){return this[k]}}; store = {setItem: function(k,v){this[k]=v}, removeItem: function(k){delete this[k]}, getItem: function(k){return this[k]}};
} }
/* /*
@ -1920,7 +1915,6 @@
data = Gun.state.to(data, has); data = Gun.state.to(data, has);
} }
//if(!data && !Gun.obj.empty(opt.peers)){ return } // if data not found, don't ack if there are peers. // Hmm, what if we have peers but we are disconnected? //if(!data && !Gun.obj.empty(opt.peers)){ return } // if data not found, don't ack if there are peers. // Hmm, what if we have peers but we are disconnected?
//console.log("lS get", lex, data);
root.on('in', {'@': msg['#'], put: Gun.graph.node(data), how: 'lS', lS: msg.$});// || root.$}); root.on('in', {'@': msg['#'], put: Gun.graph.node(data), how: 'lS', lS: msg.$});// || root.$});
}; };
Gun.debug? setTimeout(to,1) : to(); Gun.debug? setTimeout(to,1) : to();
@ -1976,15 +1970,14 @@
if('[' === tmp){ if('[' === tmp){
try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)} try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)}
if(!msg){ return } if(!msg){ return }
//console.log('hear batch length of', msg.length); LOG && opt.log(+new Date, msg.length, 'in hear batch');
(function go(){ (function go(){
var S = +new Date; // STATS! var S; LOG && (S = +new Date); // STATS!
var m, c = 100; // hardcoded for now? var m, c = 100; // hardcoded for now?
while(c-- && (m = msg.shift())){ while(c-- && (m = msg.shift())){
mesh.hear(m, peer); mesh.hear(m, peer);
} }
//console.log(+new Date - S, 'hear batch'); LOG && opt.log(S, +new Date - S, 'batch heard');
(mesh.hear.long || (mesh.hear.long = [])).push(+new Date - S);
if(!msg.length){ return } if(!msg.length){ return }
puff(go, 0); puff(go, 0);
}()); }());
@ -1995,7 +1988,7 @@
}catch(e){return opt.log('DAM JSON parse error', e)} }catch(e){return opt.log('DAM JSON parse error', e)}
if(!msg){ return } if(!msg){ return }
if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) }
if(msg.DBG_s){ console.log(+new Date - msg.DBG_s, 'to hear', id) } if(msg.DBG_s){ opt.log(+new Date - msg.DBG_s, 'to hear', id) }
if(dup.check(id)){ return } if(dup.check(id)){ return }
dup.track(id, true).it = msg; // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore? dup.track(id, true).it = msg; // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore?
if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) }
@ -2011,9 +2004,9 @@
} }
return; return;
} }
//var S = +new Date; var S; LOG && (S = +new Date);
root.on('in', msg); root.on('in', msg);
//!msg.nts && console.log(+new Date - S, 'msg', msg['#']); LOG && !msg.nts && opt.log(S, +new Date - S, 'msg', msg['#']);
return; return;
} }
} }
@ -2027,7 +2020,7 @@
if(this.to){ this.to.next(msg) } // compatible with middleware adapters. if(this.to){ this.to.next(msg) } // compatible with middleware adapters.
if(!msg){ return false } if(!msg){ return false }
var id, hash, tmp, raw; var id, hash, tmp, raw;
//var S = +new Date; //msg.DBG_s = msg.DBG_s || +new Date; var S; LOG && (S = +new Date); //msg.DBG_s = msg.DBG_s || +new Date;
var meta = msg._||(msg._=function(){}); var meta = msg._||(msg._=function(){});
if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) }
if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) }
@ -2041,15 +2034,15 @@
} }
} }
} }
//console.log(+new Date - S, 'mesh say prep'); LOG && opt.log(S, +new Date - S, 'say prep');
dup.track(id).it = msg; // track for 9 seconds, default. Earth<->Mars would need more! dup.track(id).it = msg; // track for 9 seconds, default. Earth<->Mars would need more!
if(!peer){ peer = (tmp = dup.s[msg['@']]) && (tmp = tmp.it) && (tmp = tmp._) && (tmp = tmp.via) } if(!peer){ peer = (tmp = dup.s[msg['@']]) && (tmp = tmp.it) && (tmp = tmp._) && (tmp = tmp.via) }
if(!peer && mesh.way){ return mesh.way(msg) } if(!peer && mesh.way){ return mesh.way(msg) }
if(!peer || !peer.id){ message = msg; if(!peer || !peer.id){ message = msg;
if(!Type.obj.is(peer || opt.peers)){ return false } if(!Type.obj.is(peer || opt.peers)){ return false }
//var S = +new Date; var S; LOG && (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.
//console.log(+new Date - S, 'mesh say loop'); LOG && opt.log(S, +new Date - S, 'say loop');
return; return;
} }
if(!peer.wire && mesh.wire){ mesh.wire(peer) } if(!peer.wire && mesh.wire){ mesh.wire(peer) }
@ -2073,10 +2066,10 @@
peer.batch = peer.tail = null; peer.batch = peer.tail = null;
if(!tmp){ return } if(!tmp){ return }
if(!tmp.length){ return } // if(3 > tmp.length){ return } // TODO: ^ if(!tmp.length){ return } // if(3 > tmp.length){ return } // TODO: ^
//var S = +new Date; var S; LOG && (S = +new Date);
try{tmp = (1 === tmp.length? tmp[0] : JSON.stringify(tmp)); try{tmp = (1 === tmp.length? tmp[0] : JSON.stringify(tmp));
}catch(e){return opt.log('DAM JSON stringify error', e)} }catch(e){return opt.log('DAM JSON stringify error', e)}
//console.log(+new Date - S, 'mesh flush', tmp.length); LOG && opt.log(S, +new Date - S, 'say stringify', tmp.length);
if(!tmp){ return } if(!tmp){ return }
send(tmp, peer); send(tmp, peer);
} }
@ -2086,14 +2079,14 @@
// for now - find better place later. // for now - find better place later.
function send(raw, peer){ try{ function send(raw, peer){ try{
var wire = peer.wire; var wire = peer.wire;
//var S = +new Date; var S; LOG && (S = +new Date);
if(peer.say){ if(peer.say){
peer.say(raw); peer.say(raw);
} else } else
if(wire.send){ if(wire.send){
wire.send(raw); wire.send(raw);
} }
//console.log(+new Date - S, 'wire send', raw.length); LOG && opt.log(S, +new Date - S, 'wire send', raw.length);
mesh.say.d += raw.length||0; ++mesh.say.c; // STATS! mesh.say.d += raw.length||0; ++mesh.say.c; // STATS!
}catch(e){ }catch(e){
(peer.queue = peer.queue || []).push(raw); (peer.queue = peer.queue || []).push(raw);
@ -2143,6 +2136,7 @@
root.on('bye', peer); root.on('bye', peer);
var tmp = +(new Date); tmp = (tmp - (peer.met||tmp)); var tmp = +(new Date); tmp = (tmp - (peer.met||tmp));
mesh.bye.time = ((mesh.bye.time || tmp) + tmp) / 2; mesh.bye.time = ((mesh.bye.time || tmp) + tmp) / 2;
LOG = console.LOG; // dirty place to cheaply update LOG settings over time.
} }
mesh.hear['!'] = function(msg, peer){ opt.log('Error:', msg.err) } mesh.hear['!'] = function(msg, peer){ opt.log('Error:', msg.err) }
mesh.hear['?'] = function(msg, peer){ mesh.hear['?'] = function(msg, peer){
@ -2223,6 +2217,7 @@
}()); }());
var empty = {}, ok = true, u; var empty = {}, ok = true, u;
var LOG = console.LOG;
try{ module.exports = Mesh }catch(e){} try{ module.exports = Mesh }catch(e){}

2
gun.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -149,7 +149,7 @@
/* UI */ /* UI */
if(meta.css){ return } if(meta.css){ return }
var $m = $('<div>').attr('id', 'meta'); var $m = $('<div>').attr('id', 'meta');
$m.append($('<span>').text('+').addClass('meta-start')); $m.append($('<span>').html('&#9776;').addClass('meta-start'));
$m.append($('<div>').addClass('meta-menu meta-none').append('<ul>')); $m.append($('<div>').addClass('meta-menu meta-none').append('<ul>'));
$(document.body).append($m); $(document.body).append($m);
css({ css({
@ -161,7 +161,7 @@
background: 'white', background: 'white',
'font-size': '18pt', 'font-size': '18pt',
'font-family': 'Tahoma, arial', 'font-family': 'Tahoma, arial',
'box-shadow': '0px 0px 1px #000044', //'box-shadow': '0px 0px 1px #000044',
'border-radius': '1em', 'border-radius': '1em',
'text-align': 'center', 'text-align': 'center',
'z-index': 999999, 'z-index': 999999,

View File

@ -19,7 +19,7 @@
function ename(t){ return encodeURIComponent(t).replace(/\*/g, '%2A') } function ename(t){ return encodeURIComponent(t).replace(/\*/g, '%2A') }
function atomic(v){ return u !== v && (!v || 'object' != typeof v) } function atomic(v){ return u !== v && (!v || 'object' != typeof v) }
var map = Gun.obj.map; var map = Gun.obj.map;
var LOG = false; var LOG = console.LOG;
if(!opt.store){ if(!opt.store){
return opt.log("ERROR: Radisk needs `opt.store` interface with `{get: fn, put: fn (, list: fn)}`!"); return opt.log("ERROR: Radisk needs `opt.store` interface with `{get: fn, put: fn (, list: fn)}`!");
@ -46,7 +46,7 @@
cb = val; cb = val;
var S; LOG && (S = +new Date); var S; LOG && (S = +new Date);
val = r.batch(key); val = r.batch(key);
LOG && console.log(+new Date - S, 'rad mem'); LOG && opt.log(S, +new Date - S, 'rad mem');
if(u !== val){ if(u !== val){
cb(u, r.range(val, o), o); cb(u, r.range(val, o), o);
if(atomic(val)){ return } if(atomic(val)){ return }
@ -77,6 +77,7 @@
r.thrash = function(){ r.thrash = function(){
var thrash = r.thrash; var thrash = r.thrash;
if(thrash.ing){ return thrash.more = true } if(thrash.ing){ return thrash.more = true }
LOG = console.LOG; // dirty place to cheaply update LOG settings over time.
thrash.more = false; thrash.more = false;
thrash.ing = true; thrash.ing = true;
var batch = thrash.at = r.batch, i = 0; var batch = thrash.at = r.batch, i = 0;
@ -174,9 +175,9 @@
} }
f.write = function(){ f.write = function(){
var tmp = ename(file); var tmp = ename(file);
var start; LOG && (start = +new Date); // comment this out! var S; LOG && (S = +new Date);
opt.store.put(tmp, f.text, function(err){ opt.store.put(tmp, f.text, function(err){
LOG && console.log("wrote to disk in", (+new Date) - start, tmp); // comment this out! LOG && opt.log(S, +new Date - S, "wrote disk", tmp);
if(err){ return cb(err) } if(err){ return cb(err) }
r.list.add(tmp, cb); r.list.add(tmp, cb);
}); });
@ -205,10 +206,10 @@
r.write.jsonify = function(f, file, rad, cb, o){ r.write.jsonify = function(f, file, rad, cb, o){
var raw; var raw;
var start; LOG && (start = +new Date); // comment this out! var S; LOG && (S = +new Date);
try{raw = JSON.stringify(rad.$); try{raw = JSON.stringify(rad.$);
}catch(e){ return cb("Record too big!") } }catch(e){ return cb("Record too big!") }
LOG && console.log("stringified JSON in", +new Date - start); // comment this out! LOG && opt.log(S, +new Date - S, "rad stringified JSON");
if(opt.chunk < raw.length && !o.force){ if(opt.chunk < raw.length && !o.force){
if(Radix.map(rad, f.each, true)){ return } if(Radix.map(rad, f.each, true)){ return }
} }
@ -234,7 +235,7 @@
if(RAD && !o.next){ // cache if(RAD && !o.next){ // cache
var S; LOG && (S = +new Date); var S; LOG && (S = +new Date);
var val = RAD(key); var val = RAD(key);
LOG && console.log(+new Date - S, 'rad cached'); LOG && opt.log(S, +new Date - S, 'rad cached');
//if(u !== val){ //if(u !== val){
//cb(u, val, o); //cb(u, val, o);
if(atomic(val)){ cb(u, val, o); return } if(atomic(val)){ cb(u, val, o); return }
@ -247,7 +248,7 @@
file = (u === file)? u : decodeURIComponent(file); file = (u === file)? u : decodeURIComponent(file);
tmp = o.next || key || (o.reverse? o.end || '\uffff' : o.start || ''); tmp = o.next || key || (o.reverse? o.end || '\uffff' : o.start || '');
if(!file || (o.reverse? file < tmp : file > tmp)){ if(!file || (o.reverse? file < tmp : file > tmp)){
LOG && console.log(+new Date - S, 'rad read lex'); S = +new Date; LOG && opt.log(S, +new Date - S, 'rad read lex'); S = +new Date;
if(o.next || o.reverse){ g.file = file } if(o.next || o.reverse){ g.file = file }
if(tmp = Q[g.file]){ if(tmp = Q[g.file]){
tmp.push({key: key, ack: cb, file: g.file, opt: o}); tmp.push({key: key, ack: cb, file: g.file, opt: o});
@ -268,9 +269,9 @@
g.info = info; g.info = info;
if(disk){ RAD = g.disk = disk } if(disk){ RAD = g.disk = disk }
disk = Q[g.file]; delete Q[g.file]; disk = Q[g.file]; delete Q[g.file];
LOG && console.log(+new Date - S, 'rad read it in, now ack to:', disk.length); S = +new Date; LOG && opt.log(S, +new Date - S, 'rad read in, ack', disk.length); S = +new Date;
map(disk, g.ack); map(disk, g.ack);
LOG && console.log(+new Date - S, 'rad read acked'); LOG && opt.log(S, +new Date - S, 'rad read acked');
} }
g.ack = function(as){ g.ack = function(as){
if(!as.ack){ return } if(!as.ack){ return }
@ -315,7 +316,7 @@
var p = function Parse(){}, info = {}; var p = function Parse(){}, info = {};
p.disk = Radix(); p.disk = Radix();
p.read = function(err, data){ var tmp; p.read = function(err, data){ var tmp;
LOG && console.log('read disk in', +new Date - S, ename(file)); // keep this commented out in LOG && opt.log(S, +new Date - S, 'read disk', ename(file));
delete Q[file]; delete Q[file];
if((p.err = err) || (p.not = !data)){ if((p.err = err) || (p.not = !data)){
return map(q, p.ack); return map(q, p.ack);
@ -332,12 +333,12 @@
} }
info.parsed = data.length; info.parsed = data.length;
LOG && (S = +new Date); // keep this commented out in production! LOG && (S = +new Date);
if(opt.jsonify || '{' === data[0]){ // temporary testing idea if(opt.jsonify || '{' === data[0]){ // temporary testing idea
try{ try{
var json = JSON.parse(data); var json = JSON.parse(data);
p.disk.$ = json; p.disk.$ = json;
LOG && console.log('parsed JSON in', +new Date - S); // keep this commented out in production! LOG && opt.log(S, +new Date - S, 'rad parsed JSON');
map(q, p.ack); map(q, p.ack);
return; return;
}catch(e){ tmp = e } }catch(e){ tmp = e }
@ -346,7 +347,7 @@
return map(q, p.ack); return map(q, p.ack);
} }
} }
LOG && (S = +new Date); // keep this commented out in production! LOG && (S = +new Date);
var tmp = p.split(data), pre = [], i, k, v; var tmp = p.split(data), pre = [], i, k, v;
if(!tmp || 0 !== tmp[1]){ if(!tmp || 0 !== tmp[1]){
p.err = "File '"+file+"' does not have root radix! "; p.err = "File '"+file+"' does not have root radix! ";
@ -369,7 +370,7 @@
if(u !== k && u !== v){ p.disk(pre.join(''), v) } if(u !== k && u !== v){ p.disk(pre.join(''), v) }
tmp = p.split(tmp[2]); tmp = p.split(tmp[2]);
} }
LOG && console.log('parsed RAD in', +new Date - S); // keep this commented out in production! LOG && opt.log(S, +new Date - S, 'parsed RAD');
//cb(err, p.disk); //cb(err, p.disk);
map(q, p.ack); map(q, p.ack);
}; };
@ -389,7 +390,7 @@
if(p.err || p.not){ return cb(p.err, u, info) } if(p.err || p.not){ return cb(p.err, u, info) }
cb(u, p.disk, info); cb(u, p.disk, info);
} }
var S; LOG && (S = +new Date); // keep this commented out in production! var S; LOG && (S = +new Date);
if(raw){ return p.read(null, raw) } if(raw){ return p.read(null, raw) }
opt.store.get(ename(file), p.read); opt.store.get(ename(file), p.read);
} }

View File

@ -6,6 +6,7 @@
if(u === root.opt.super){ if(u === root.opt.super){
root.opt.super = true; root.opt.super = true;
} }
root.opt.log = root.opt.log || Gun.log;
this.to.next(root); this.to.next(root);
}) })
require('../nts'); require('../nts');

View File

@ -39,6 +39,7 @@ Gun.on('opt', function(root){
stats.peers.count = Object.keys(root.opt.peers||{}).length; stats.peers.count = Object.keys(root.opt.peers||{}).length;
stats.node = {}; stats.node = {};
stats.node.count = Object.keys(root.graph||{}).length; stats.node.count = Object.keys(root.graph||{}).length;
stats.all = all;
var dam = root.opt.mesh; var dam = root.opt.mesh;
if(dam){ if(dam){
stats.dam = {'in': {count: dam.hear.c, done: dam.hear.d, long: dam.hear.long}, 'out': {count: dam.say.c, done: dam.say.d}}; stats.dam = {'in': {count: dam.hear.c, done: dam.hear.d, long: dam.hear.long}, 'out': {count: dam.say.c, done: dam.say.d}};
@ -57,3 +58,14 @@ Gun.on('opt', function(root){
}, 1000 * 15); }, 1000 * 15);
Object.keys = Object.keys || function(o){ return Gun.obj.map(o, function(v,k,t){t(k)}) } Object.keys = Object.keys || function(o){ return Gun.obj.map(o, function(v,k,t){t(k)}) }
}); });
var log = Gun.log, all = {}, max = 1000;
Gun.log = function(a,b,c,d){
if('number' == typeof a && 'number' == typeof b && 'string' == typeof c){
var tmp = (all[c] || (all[c] = []));
if(max < tmp.push([a,b])){ all[c] = [] } // reset
return;
}
return log.apply(Gun, arguments);
}

View File

@ -30,12 +30,12 @@ Gun.on('create', function(root){
val = Radisk.encode(val, null, esc)+'>'+Radisk.encode(Gun.state.is(node, key), null, esc); val = Radisk.encode(val, null, esc)+'>'+Radisk.encode(Gun.state.is(node, key), null, esc);
rad(soul+esc+key, val, (track? ack : u)); rad(soul+esc+key, val, (track? ack : u));
}); });
//console.log(+new Date - S, 'put loop'); Gun.log(S, +new Date - S, 'put loop');
function ack(err, ok){ function ack(err, ok){
acks--; acks--;
if(ack.err){ return } if(ack.err){ return }
if(ack.err = err){ if(ack.err = err){
try{opt.store.stats.put.err = err}catch(e){} // STATS! //Gun.log(); //try{opt.store.stats.put.err = err}catch(e){} // STATS!
root.on('in', {'@': id, err: err}); root.on('in', {'@': id, err: err});
return; return;
} }
@ -45,7 +45,7 @@ Gun.on('create', function(root){
}catch(e){} // STATS! }catch(e){} // STATS!
//console.log(+new Date - S, 'put'); S = +new Date; //console.log(+new Date - S, 'put'); S = +new Date;
root.on('in', {'@': id, ok: 1}); root.on('in', {'@': id, ok: 1});
//console.log(+new Date - S, 'put sent'); //console.log(S, +new Date - S, 'put sent');
} }
}); });
@ -89,7 +89,7 @@ Gun.on('create', function(root){
if(err){ opt.store.stats.get.err = err } if(err){ opt.store.stats.get.err = err }
}catch(e){} // STATS! }catch(e){} // STATS!
//if(u === data && o.chunks > 1){ return } // if we already sent a chunk, ignore ending empty responses. // this causes tests to fail. //if(u === data && o.chunks > 1){ return } // if we already sent a chunk, ignore ending empty responses. // this causes tests to fail.
//console.log(+new Date - S, 'got'); S = +new Date; Gun.log(S, +new Date - S, 'got'); S = +new Date; // MARK RETURN HERE!!!! Gun.log will always log unless off :/ switch to something like LOG && whatever?
if(data){ if(data){
if(typeof data !== 'string'){ if(typeof data !== 'string'){
if(o.atom){ if(o.atom){
@ -100,11 +100,10 @@ Gun.on('create', function(root){
} }
if(!graph && data){ each(data, '') } if(!graph && data){ each(data, '') }
} }
//console.log(+new Date - S, 'got prep'); S = +new Date; Gun.log(S, +new Date - S, 'got prep');
root.on('in', {'@': id, put: graph, '%': o.more? 1 : u, err: err? err : u, _: each}); root.on('in', {'@': id, put: graph, '%': o.more? 1 : u, err: err? err : u, _: each});
//console.log(+new Date - S, 'got sent');
}, o); }, o);
//console.log(+new Date - S, 'get call'); Gun.log(S, +new Date - S, 'get call');
function each(val, has, a,b){ function each(val, has, a,b){
if(!val){ return } if(!val){ return }
has = (key+has).split(esc); has = (key+has).split(esc);

View File

@ -4,7 +4,7 @@ if(typeof Gun === 'undefined'){ return } // TODO: localStorage is Browser only.
var root, noop = function(){}, store, u; var root, noop = function(){}, store, u;
try{store = (Gun.window||noop).localStorage}catch(e){} try{store = (Gun.window||noop).localStorage}catch(e){}
if(!store){ if(!store){
console.log("Warning: No localStorage exists to persist data to!"); Gun.log("Warning: No localStorage exists to persist data to!");
store = {setItem: function(k,v){this[k]=v}, removeItem: function(k){delete this[k]}, getItem: function(k){return this[k]}}; store = {setItem: function(k,v){this[k]=v}, removeItem: function(k){delete this[k]}, getItem: function(k){return this[k]}};
} }
/* /*
@ -110,7 +110,6 @@ Gun.on('create', function(root){
data = Gun.state.to(data, has); data = Gun.state.to(data, has);
} }
//if(!data && !Gun.obj.empty(opt.peers)){ return } // if data not found, don't ack if there are peers. // Hmm, what if we have peers but we are disconnected? //if(!data && !Gun.obj.empty(opt.peers)){ return } // if data not found, don't ack if there are peers. // Hmm, what if we have peers but we are disconnected?
//console.log("lS get", lex, data);
root.on('in', {'@': msg['#'], put: Gun.graph.node(data), how: 'lS', lS: msg.$});// || root.$}); root.on('in', {'@': msg['#'], put: Gun.graph.node(data), how: 'lS', lS: msg.$});// || root.$});
}; };
Gun.debug? setTimeout(to,1) : to(); Gun.debug? setTimeout(to,1) : to();

View File

@ -19,15 +19,14 @@ function Mesh(root){
if('[' === tmp){ if('[' === tmp){
try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)} try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)}
if(!msg){ return } if(!msg){ return }
//console.log('hear batch length of', msg.length); LOG && opt.log(msg.length, 'in hear batch');
(function go(){ (function go(){
var S = +new Date; // STATS! var S; LOG && (S = +new Date); // STATS!
var m, c = 100; // hardcoded for now? var m, c = 100; // hardcoded for now?
while(c-- && (m = msg.shift())){ while(c-- && (m = msg.shift())){
mesh.hear(m, peer); mesh.hear(m, peer);
} }
//console.log(+new Date - S, 'hear batch'); LOG && opt.log(+new Date - S, 'batch heard');
(mesh.hear.long || (mesh.hear.long = [])).push(+new Date - S);
if(!msg.length){ return } if(!msg.length){ return }
puff(go, 0); puff(go, 0);
}()); }());
@ -38,7 +37,7 @@ function Mesh(root){
}catch(e){return opt.log('DAM JSON parse error', e)} }catch(e){return opt.log('DAM JSON parse error', e)}
if(!msg){ return } if(!msg){ return }
if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) }
if(msg.DBG_s){ console.log(+new Date - msg.DBG_s, 'to hear', id) } if(msg.DBG_s){ opt.log(+new Date - msg.DBG_s, 'to hear', id) }
if(dup.check(id)){ return } if(dup.check(id)){ return }
dup.track(id, true).it = msg; // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore? dup.track(id, true).it = msg; // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore?
if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) }
@ -54,9 +53,9 @@ function Mesh(root){
} }
return; return;
} }
//var S = +new Date; var S; LOG && (S = +new Date);
root.on('in', msg); root.on('in', msg);
//!msg.nts && console.log(+new Date - S, 'msg', msg['#']); LOG && !msg.nts && opt.log(+new Date - S, 'msg', msg['#']);
return; return;
} }
} }
@ -70,7 +69,7 @@ function Mesh(root){
if(this.to){ this.to.next(msg) } // compatible with middleware adapters. if(this.to){ this.to.next(msg) } // compatible with middleware adapters.
if(!msg){ return false } if(!msg){ return false }
var id, hash, tmp, raw; var id, hash, tmp, raw;
//var S = +new Date; //msg.DBG_s = msg.DBG_s || +new Date; var S; LOG && (S = +new Date); //msg.DBG_s = msg.DBG_s || +new Date;
var meta = msg._||(msg._=function(){}); var meta = msg._||(msg._=function(){});
if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) }
if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) }
@ -84,15 +83,15 @@ function Mesh(root){
} }
} }
} }
//console.log(+new Date - S, 'mesh say prep'); LOG && opt.log(+new Date - S, 'say prep');
dup.track(id).it = msg; // track for 9 seconds, default. Earth<->Mars would need more! dup.track(id).it = msg; // track for 9 seconds, default. Earth<->Mars would need more!
if(!peer){ peer = (tmp = dup.s[msg['@']]) && (tmp = tmp.it) && (tmp = tmp._) && (tmp = tmp.via) } if(!peer){ peer = (tmp = dup.s[msg['@']]) && (tmp = tmp.it) && (tmp = tmp._) && (tmp = tmp.via) }
if(!peer && mesh.way){ return mesh.way(msg) } if(!peer && mesh.way){ return mesh.way(msg) }
if(!peer || !peer.id){ message = msg; if(!peer || !peer.id){ message = msg;
if(!Type.obj.is(peer || opt.peers)){ return false } if(!Type.obj.is(peer || opt.peers)){ return false }
//var S = +new Date; var S; LOG && (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.
//console.log(+new Date - S, 'mesh say loop'); LOG && opt.log(+new Date - S, 'say loop');
return; return;
} }
if(!peer.wire && mesh.wire){ mesh.wire(peer) } if(!peer.wire && mesh.wire){ mesh.wire(peer) }
@ -116,10 +115,10 @@ function Mesh(root){
peer.batch = peer.tail = null; peer.batch = peer.tail = null;
if(!tmp){ return } if(!tmp){ return }
if(!tmp.length){ return } // if(3 > tmp.length){ return } // TODO: ^ if(!tmp.length){ return } // if(3 > tmp.length){ return } // TODO: ^
//var S = +new Date; var S; LOG && (S = +new Date);
try{tmp = (1 === tmp.length? tmp[0] : JSON.stringify(tmp)); try{tmp = (1 === tmp.length? tmp[0] : JSON.stringify(tmp));
}catch(e){return opt.log('DAM JSON stringify error', e)} }catch(e){return opt.log('DAM JSON stringify error', e)}
//console.log(+new Date - S, 'mesh flush', tmp.length); LOG && opt.log(+new Date - S, 'say stringify', tmp.length);
if(!tmp){ return } if(!tmp){ return }
send(tmp, peer); send(tmp, peer);
} }
@ -129,14 +128,14 @@ function Mesh(root){
// for now - find better place later. // for now - find better place later.
function send(raw, peer){ try{ function send(raw, peer){ try{
var wire = peer.wire; var wire = peer.wire;
//var S = +new Date; var S; LOG && (S = +new Date);
if(peer.say){ if(peer.say){
peer.say(raw); peer.say(raw);
} else } else
if(wire.send){ if(wire.send){
wire.send(raw); wire.send(raw);
} }
//console.log(+new Date - S, 'wire send', raw.length); LOG && opt.log(+new Date - S, 'wire send', raw.length);
mesh.say.d += raw.length||0; ++mesh.say.c; // STATS! mesh.say.d += raw.length||0; ++mesh.say.c; // STATS!
}catch(e){ }catch(e){
(peer.queue = peer.queue || []).push(raw); (peer.queue = peer.queue || []).push(raw);
@ -186,6 +185,7 @@ function Mesh(root){
root.on('bye', peer); root.on('bye', peer);
var tmp = +(new Date); tmp = (tmp - (peer.met||tmp)); var tmp = +(new Date); tmp = (tmp - (peer.met||tmp));
mesh.bye.time = ((mesh.bye.time || tmp) + tmp) / 2; mesh.bye.time = ((mesh.bye.time || tmp) + tmp) / 2;
LOG = console.LOG; // dirty place to cheaply update LOG settings over time.
} }
mesh.hear['!'] = function(msg, peer){ opt.log('Error:', msg.err) } mesh.hear['!'] = function(msg, peer){ opt.log('Error:', msg.err) }
mesh.hear['?'] = function(msg, peer){ mesh.hear['?'] = function(msg, peer){
@ -266,6 +266,7 @@ function Mesh(root){
}()); }());
var empty = {}, ok = true, u; var empty = {}, ok = true, u;
var LOG = console.LOG;
try{ module.exports = Mesh }catch(e){} try{ module.exports = Mesh }catch(e){}

View File

@ -89,7 +89,6 @@ function soul(gun, cb, opt, as){
function use(msg){ function use(msg){
var eve = this, as = eve.as, cat = as.at, root = cat.root, gun = msg.$, at = (gun||{})._ || {}, data = msg.put || at.put, tmp; var eve = this, as = eve.as, cat = as.at, root = cat.root, gun = msg.$, at = (gun||{})._ || {}, data = msg.put || at.put, tmp;
if((tmp = root.now) && eve !== tmp[as.now]){ return eve.to.next(msg) } if((tmp = root.now) && eve !== tmp[as.now]){ return eve.to.next(msg) }
//console.log("USE:", cat.id, cat.soul, cat.has, cat.get, msg, root.mum);
//if(at.async && msg.root){ return } //if(at.async && msg.root){ return }
//if(at.async === 1 && cat.async !== true){ return } //if(at.async === 1 && cat.async !== true){ return }
//if(root.stop && root.stop[at.id]){ return } root.stop && (root.stop[at.id] = true); //if(root.stop && root.stop[at.id]){ return } root.stop && (root.stop[at.id] = true);

View File

@ -177,7 +177,7 @@ function any(soul, as, msg, eve){
as = as.as; as = as.as;
if(!msg.$ || !msg.$._){ return } // TODO: Handle if(!msg.$ || !msg.$._){ return } // TODO: Handle
if(msg.err){ // TODO: Handle if(msg.err){ // TODO: Handle
console.log("Please report this as an issue! Put.any.err"); Gun.log("Please report this as an issue! Put.any.err");
return; return;
} }
var at = (msg.$._), data = at.put, opt = as.opt||{}, root, tmp; var at = (msg.$._), data = at.put, opt = as.opt||{}, root, tmp;
@ -186,7 +186,7 @@ function any(soul, as, msg, eve){
if(as.ref !== as.$){ if(as.ref !== as.$){
tmp = (as.$._).get || at.get; tmp = (as.$._).get || at.get;
if(!tmp){ // TODO: Handle if(!tmp){ // TODO: Handle
console.log("Please report this as an issue! Put.no.get"); // TODO: BUG!?? Gun.log("Please report this as an issue! Put.no.get"); // TODO: BUG!??
return; return;
} }
as.data = obj_put({}, tmp, as.data); as.data = obj_put({}, tmp, as.data);

View File

@ -162,20 +162,16 @@ Gun.dup = require('./dup');
// Maybe... in case the in-memory key we have is a local write // Maybe... in case the in-memory key we have is a local write
// we still need to trigger a pull/merge from peers. // we still need to trigger a pull/merge from peers.
} else { } else {
//var S = +new Date;
node = Gun.obj.copy(node); node = Gun.obj.copy(node);
//console.log(+new Date - S, 'copy node');
} }
node = Gun.graph.node(node); node = Gun.graph.node(node);
tmp = (at||empty).ack; tmp = (at||empty).ack;
//var S = +new Date;
root.on('in', { root.on('in', {
'@': msg['#'], '@': msg['#'],
how: 'mem', how: 'mem',
put: node, put: node,
$: gun $: gun
}); });
//console.log(+new Date - S, 'root got send');
//if(0 < tmp){ return } //if(0 < tmp){ return }
root.on('get', msg); root.on('get', msg);
} }

171
test/panic/livestream.js Normal file
View File

@ -0,0 +1,171 @@
/*
This is the first in a series of basic networking correctness tests.
Each test itself might be dumb and simple, but built up together,
they prove desired end goals for behavior at scale.
1. (this file) Is a browser write is confirmed as save by multiple peers even if by daisy chain.
2.
*/
var config = {
IP: require('ip').address(),
port: 8765,
servers: 1,
browsers: 2,
route: {
'/': __dirname + '/index.html',
'/gun.js': __dirname + '/../../gun.js',
'/jquery.js': __dirname + '/../../examples/jquery.js',
'/livestream.html': __dirname + '/livestream.html',
}
}
var panic = require('panic-server');
panic.server().on('request', function(req, res){
config.route[req.url] && require('fs').createReadStream(config.route[req.url]).pipe(res);
}).listen(config.port);
var clients = panic.clients;
var manager = require('panic-manager')();
manager.start({
clients: Array(config.servers).fill().map(function(u, i){
return {
type: 'node',
port: config.port + (i + 1)
}
}),
panic: 'http://' + config.IP + ':' + config.port
});
var servers = clients.filter('Node.js');
var bob = servers.pluck(1);
var browsers = clients.excluding(servers);
var alice = browsers.pluck(1);
var others = clients.excluding(alice);
describe("Broadcast Video", function(){
//this.timeout(5 * 60 * 1000);
this.timeout(10 * 60 * 1000);
it("Servers have joined!", function(){
return servers.atLeast(config.servers);
});
it("GUN started!", function(){
var tests = [], i = 0;
servers.each(function(client){
tests.push(client.run(function(test){
var env = test.props;
test.async();
try{ require('fs').unlinkSync(env.i+'data') }catch(e){}
try{ require('gun/lib/fsrm')(env.i+'data') }catch(e){}
var server = require('http').createServer(function(req, res){
res.end("I am "+ env.i +"!");
});
var port = env.config.port + env.i;
var Gun = require('gun');
var peers = [], i = env.config.servers;
while(i--){
var tmp = (env.config.port + (i + 1));
if(port != tmp){ // ignore ourselves
peers.push('http://'+ env.config.IP + ':' + tmp + '/gun');
}
}
console.log(port, " connect to ", peers);
var gun = Gun({file: env.i+'data', peers: peers, web: server});
server.listen(port, function(){
test.done();
});
}, {i: i += 1, config: config}));
});
return Promise.all(tests);
});
it(config.browsers +" browser(s) have joined!", function(){
console.log("PLEASE OPEN http://"+ config.IP +":"+ config.port +" IN "+ config.browsers +" BROWSER(S)!");
return browsers.atLeast(config.browsers);
});
it("Browsers load QVDev's streaming!", function(){
var tests = [], i = 0;
browsers.each(function(client, id){
tests.push(client.run(function(test){
test.async();
console.log("load?");
function load(src, cb){
var script = document.createElement('script');
script.onload = cb; script.src = src;
document.head.appendChild(script);
}
load('https://cdn.jsdelivr.net/gh/QVDev/GunStreamer/js/GunRecorder.js', function(){
load('https://cdn.jsdelivr.net/gh/QVDev/GunStreamer/js/GunStreamer.js', function(){
test.done();
});
});
$('body').append('<video id="video" width="100%" autoplay></video>');
}, {i: i += 1, config: config}));
});
return Promise.all(tests);
});
it("Browsers initialized gun!", function(){
var tests = [], i = 0;
browsers.each(function(client, id){
tests.push(client.run(function(test){
try{ localStorage.clear() }catch(e){}
try{ indexedDB.deleteDatabase('radata') }catch(e){}
var env = test.props;
var gun = Gun('http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun');
window.gun = gun;
}, {i: i += 1, config: config}));
});
return Promise.all(tests);
});
it("Stream", function(){
return alice.run(function(test){
console.log("I AM ALICE");
test.async();
var stream = window.stream = new GunStreamer({
url: "https://cdn.jsdelivr.net/gh/QVDev/GunStreamer/js/parser_worker.js",
gun: gun,
streamId: 'livestream',
dbRecord: 'streams'
});
var record = window.record = new GunRecorder({
mimeType: 'video/webm; codecs="opus,vp8"',
//audioBitsPerSecond: 6000,//Audio bits per second this is the lowest quality
//videoBitsPerSecond: 100000,//Video bits per second this is the lowest quality
cameraOptions: {video:{width: 1280, height: 720, facingMode: "environment", frameRate: 60}, audio: true},
video_id: "video",
recordInterval: 1000, // how long each chunk?
onRecordStateChange: function(state){ /* change play/pause buttons */ },
onDataAvailable: function(data){ console.log('r -> s', data); stream.onDataAvailable(data) } // pass recorded data to streamer
});
record.startCamera();
$('#video').on('playing', function(eve){
console.log("YES!!!");
record.record();
});
console.log("start recording!");
}, {acks: config.servers});
});
it("All finished!", function(done){
console.log("Done! Cleaning things up...");
setTimeout(function(){
done();
},1000);
});
after("Everything shut down.", function(){
browsers.run(function(){
//location.reload();
//setTimeout(function(){
//}, 15 * 1000);
});
return servers.run(function(){
process.exit();
});
});
});