mirror of
https://github.com/amark/gun.git
synced 2025-07-07 13:22:33 +00:00
put sampling, mob, tests
This commit is contained in:
parent
525d834784
commit
46d926e831
37
gun.js
37
gun.js
@ -1086,9 +1086,10 @@
|
|||||||
function ran(as){
|
function ran(as){
|
||||||
if(as.err){ ran.end(as.stun, as.root); return } // move log handle here.
|
if(as.err){ ran.end(as.stun, as.root); return } // move log handle here.
|
||||||
if(as.todo.length || as.end || !Object.empty(as.wait)){ return } as.end = 1;
|
if(as.todo.length || as.end || !Object.empty(as.wait)){ return } as.end = 1;
|
||||||
|
//(as.retry = function(){ as.acks = 0;
|
||||||
var cat = (as.$.back(-1)._), root = cat.root, ask = cat.ask(function(ack){
|
var cat = (as.$.back(-1)._), root = cat.root, ask = cat.ask(function(ack){
|
||||||
root.on('ack', ack);
|
root.on('ack', ack);
|
||||||
if(ack.err && as.ok){ Gun.log(ack) }
|
if(ack.err && !ack.lack){ Gun.log(ack) }
|
||||||
if(++acks > (as.acks || 0)){ this.off() } // Adjustable ACKs! Only 1 by default.
|
if(++acks > (as.acks || 0)){ this.off() } // Adjustable ACKs! Only 1 by default.
|
||||||
if(!as.ack){ return }
|
if(!as.ack){ return }
|
||||||
as.ack(ack, this);
|
as.ack(ack, this);
|
||||||
@ -1099,7 +1100,9 @@
|
|||||||
setTimeout.each(Object.keys(stun = stun.add||''), function(cb){ if(cb = stun[cb]){cb()} }); // resume the stunned reads // Any perf reasons to CPU schedule this .keys( ?
|
setTimeout.each(Object.keys(stun = stun.add||''), function(cb){ if(cb = stun[cb]){cb()} }); // resume the stunned reads // Any perf reasons to CPU schedule this .keys( ?
|
||||||
}).hatch = tmp; // this is not official yet ^
|
}).hatch = tmp; // this is not official yet ^
|
||||||
//console.log(1, "PUT", as.run, as.graph);
|
//console.log(1, "PUT", as.run, as.graph);
|
||||||
|
if(as.ack && !as.ok){ as.ok = as.acks || 9 } // TODO: In future! Remove this! This is just old API support.
|
||||||
(as.via._).on('out', {put: as.out = as.graph, ok: as.ok && {'@': as.ok+1}, opt: as.opt, '#': ask, _: tmp});
|
(as.via._).on('out', {put: as.out = as.graph, ok: as.ok && {'@': as.ok+1}, opt: as.opt, '#': ask, _: tmp});
|
||||||
|
//})();
|
||||||
}; ran.end = function(stun,root){
|
}; ran.end = function(stun,root){
|
||||||
stun.end = noop; // like with the earlier id, cheaper to make this flag a function so below callbacks do not have to do an extra type check.
|
stun.end = noop; // like with the earlier id, cheaper to make this flag a function so below callbacks do not have to do an extra type check.
|
||||||
if(stun.the.to === stun && stun === stun.the.last){ delete root.stun }
|
if(stun.the.to === stun && stun === stun.the.last){ delete root.stun }
|
||||||
@ -1479,11 +1482,10 @@
|
|||||||
if(!(hash = msg['##']) && u !== msg.put && !meta.via && ack){ mesh.hash(msg, peer); return } // TODO: Should broadcasts be hashed?
|
if(!(hash = msg['##']) && u !== msg.put && !meta.via && ack){ mesh.hash(msg, peer); return } // TODO: Should broadcasts be hashed?
|
||||||
if(!peer && ack){ peer = ((tmp = dup.s[ack]) && (tmp.via || ((tmp = tmp.it) && (tmp = tmp._) && tmp.via))) || ((tmp = mesh.last) && ack === tmp['#'] && mesh.leap) } // warning! mesh.leap could be buggy! mesh last check reduces this.
|
if(!peer && ack){ peer = ((tmp = dup.s[ack]) && (tmp.via || ((tmp = tmp.it) && (tmp = tmp._) && tmp.via))) || ((tmp = mesh.last) && ack === tmp['#'] && mesh.leap) } // warning! mesh.leap could be buggy! mesh last check reduces this.
|
||||||
if(!peer && ack){ // still no peer, then ack daisy chain 'tunnel' got lost.
|
if(!peer && ack){ // still no peer, then ack daisy chain 'tunnel' got lost.
|
||||||
if(dup.s[ack]){ return } // in dups but no peer hints that this was ack to self, ignore.
|
if(dup.s[ack]){ return } // in dups but no peer hints that this was ack to ourself, ignore.
|
||||||
console.STAT && console.STAT(+new Date, ++SMIA, 'total no peer to ack to');
|
console.STAT && console.STAT(+new Date, ++SMIA, 'total no peer to ack to'); // TODO: Delete this now. Dropping lost ACKs is protocol fine now.
|
||||||
return false;
|
return false;
|
||||||
} // TODO: Temporary? If ack via trace has been lost, acks will go to all peers, which trashes browser bandwidth. Not relaying the ack will force sender to ask for ack again. Note, this is technically wrong for mesh behavior.
|
} // TODO: Temporary? If ack via trace has been lost, acks will go to all peers, which trashes browser bandwidth. Not relaying the ack will force sender to ask for ack again. Note, this is technically wrong for mesh behavior.
|
||||||
if(msg.put && (tmp = msg.ok)){ msg.ok = {'@':(tmp['@']||1)-1, '/': (tmp['/']==msg._.near)? mesh.near : tmp['/']}; }
|
|
||||||
if(!peer && mesh.way){ return mesh.way(msg) }
|
if(!peer && mesh.way){ return mesh.way(msg) }
|
||||||
DBG && (DBG.yh = +new Date);
|
DBG && (DBG.yh = +new Date);
|
||||||
if(!(raw = meta.raw)){ mesh.raw(msg, peer); return }
|
if(!(raw = meta.raw)){ mesh.raw(msg, peer); return }
|
||||||
@ -1557,6 +1559,7 @@
|
|||||||
}
|
}
|
||||||
if(i > 1){ msg['><'] = to.join() } // TODO: BUG! This gets set regardless of peers sent to! Detect?
|
if(i > 1){ msg['><'] = to.join() } // TODO: BUG! This gets set regardless of peers sent to! Detect?
|
||||||
}
|
}
|
||||||
|
if(msg.put && (tmp = msg.ok)){ msg.ok = {'@':(tmp['@']||1)-1, '/': (tmp['/']==msg._.near)? mesh.near : tmp['/']}; }
|
||||||
if(put = meta.$put){
|
if(put = meta.$put){
|
||||||
tmp = {}; Object.keys(msg).forEach(function(k){ tmp[k] = msg[k] });
|
tmp = {}; Object.keys(msg).forEach(function(k){ tmp[k] = msg[k] });
|
||||||
tmp.put = ':])([:';
|
tmp.put = ':])([:';
|
||||||
@ -1603,7 +1606,7 @@
|
|||||||
(peer.queue = peer.queue || []).push(raw);
|
(peer.queue = peer.queue || []).push(raw);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
mesh.near = 0; // TODO: BUG! Mesh.near buggy, FIX!
|
mesh.near = 0;
|
||||||
mesh.hi = function(peer){
|
mesh.hi = function(peer){
|
||||||
var wire = peer.wire, tmp;
|
var wire = peer.wire, tmp;
|
||||||
if(!wire){ mesh.wire((peer.length && {url: peer, id: peer}) || peer); return }
|
if(!wire){ mesh.wire((peer.length && {url: peer, id: peer}) || peer); return }
|
||||||
@ -1614,8 +1617,11 @@
|
|||||||
mesh.say({dam: '?', pid: root.opt.pid}, opt.peers[tmp] = peer);
|
mesh.say({dam: '?', pid: root.opt.pid}, opt.peers[tmp] = peer);
|
||||||
delete dup.s[peer.last]; // IMPORTANT: see https://gun.eco/docs/DAM#self
|
delete dup.s[peer.last]; // IMPORTANT: see https://gun.eco/docs/DAM#self
|
||||||
}
|
}
|
||||||
peer.met = peer.met || +(new Date);
|
if(!peer.met){
|
||||||
if(!wire.hied){ root.on(wire.hied = 'hi', peer) }
|
mesh.near++;
|
||||||
|
peer.met = +(new Date);
|
||||||
|
root.on('hi', peer)
|
||||||
|
}
|
||||||
// @rogowski I need this here by default for now to fix go1dfish's bug
|
// @rogowski I need this here by default for now to fix go1dfish's bug
|
||||||
tmp = peer.queue; peer.queue = [];
|
tmp = peer.queue; peer.queue = [];
|
||||||
setTimeout.each(tmp||[],function(msg){
|
setTimeout.each(tmp||[],function(msg){
|
||||||
@ -1624,7 +1630,8 @@
|
|||||||
//Type.obj.native && Type.obj.native(); // dirty place to check if other JS polluted.
|
//Type.obj.native && Type.obj.native(); // dirty place to check if other JS polluted.
|
||||||
}
|
}
|
||||||
mesh.bye = function(peer){
|
mesh.bye = function(peer){
|
||||||
--mesh.near;
|
peer.met && --mesh.near;
|
||||||
|
delete peer.met;
|
||||||
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;
|
||||||
@ -1638,6 +1645,13 @@
|
|||||||
mesh.say({dam: '?', pid: opt.pid, '@': msg['#']}, peer);
|
mesh.say({dam: '?', pid: opt.pid, '@': msg['#']}, peer);
|
||||||
delete dup.s[peer.last]; // IMPORTANT: see https://gun.eco/docs/DAM#self
|
delete dup.s[peer.last]; // IMPORTANT: see https://gun.eco/docs/DAM#self
|
||||||
}
|
}
|
||||||
|
mesh.hear['mob'] = function(msg, peer){ // NOTE: AXE will overload this with better logic.
|
||||||
|
if(!msg.peers){ return }
|
||||||
|
var peers = Object.keys(msg.peers), one = peers[Math.floor(Math.random()*peers.length)];
|
||||||
|
if(!one){ return }
|
||||||
|
mesh.bye(peer);
|
||||||
|
mesh.hi(one);
|
||||||
|
}
|
||||||
|
|
||||||
root.on('create', function(root){
|
root.on('create', function(root){
|
||||||
root.opt.pid = root.opt.pid || String.random(9);
|
root.opt.pid = root.opt.pid || String.random(9);
|
||||||
@ -1776,10 +1790,11 @@
|
|||||||
|
|
||||||
root.on('put', function(msg){
|
root.on('put', function(msg){
|
||||||
this.to.next(msg); // remember to call next middleware adapter
|
this.to.next(msg); // remember to call next middleware adapter
|
||||||
var put = msg.put, soul = put['#'], key = put['.'], id = msg['#'], tmp; // pull data off wire envelope
|
var put = msg.put, soul = put['#'], key = put['.'], id = msg['#'], ok = msg.ok||'', tmp; // pull data off wire envelope
|
||||||
disk[soul] = Gun.state.ify(disk[soul], key, put['>'], put[':'], soul); // merge into disk object
|
disk[soul] = Gun.state.ify(disk[soul], key, put['>'], put[':'], soul); // merge into disk object
|
||||||
if(stop && size > (4999880)){ root.on('in', {'@': id, err: "localStorage max!"}); return; }
|
if(stop && size > (4999880)){ root.on('in', {'@': id, err: "localStorage max!"}); return; }
|
||||||
if(!msg['@']){ acks.push(id) } // then ack any non-ack write. // TODO: use batch id.
|
//if(!msg['@']){ acks.push(id) } // then ack any non-ack write. // TODO: use batch id.
|
||||||
|
if(!msg['@'] && (!msg._.via || Math.random() < (ok['@'] / ok['/']))){ acks.push(id) } // then ack any non-ack write. // TODO: use batch id.
|
||||||
if(to){ return }
|
if(to){ return }
|
||||||
to = setTimeout(flush, 9+(size / 333)); // 0.1MB = 0.3s, 5MB = 15s
|
to = setTimeout(flush, 9+(size / 333)); // 0.1MB = 0.3s, 5MB = 15s
|
||||||
});
|
});
|
||||||
@ -1795,7 +1810,7 @@
|
|||||||
}
|
}
|
||||||
size = tmp.length;
|
size = tmp.length;
|
||||||
|
|
||||||
if(!err && !Object.empty(opt.peers)){ return } // only ack if there are no peers. // Switch this to probabilistic mode
|
//if(!err && !Object.empty(opt.peers)){ return } // only ack if there are no peers. // Switch this to probabilistic mode
|
||||||
setTimeout.each(ack, function(id){
|
setTimeout.each(ack, function(id){
|
||||||
root.on('in', {'@': id, err: err, ok: 0}); // localStorage isn't reliable, so make its `ok` code be a low number.
|
root.on('in', {'@': id, err: err, ok: 0}); // localStorage isn't reliable, so make its `ok` code be a low number.
|
||||||
},0,99);
|
},0,99);
|
||||||
|
20
lib/axe.js
20
lib/axe.js
@ -4,9 +4,7 @@
|
|||||||
// but for now... I gotta rush this out!
|
// but for now... I gotta rush this out!
|
||||||
var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'), u;
|
var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'), u;
|
||||||
Gun.on('opt', function(at){ start(at); this.to.next(at) }); // make sure to call the "next" middleware adapter.
|
Gun.on('opt', function(at){ start(at); this.to.next(at) }); // make sure to call the "next" middleware adapter.
|
||||||
|
// TODO: BUG: panic test/panic/1 & test/panic/3 fail when AXE is on.
|
||||||
// For Future WebRTC notes: Chrome 500 max limit, however 256 likely - FF "none", webtorrent does 55 per torrent (thanks Feross! How'd you come to this number?).
|
|
||||||
|
|
||||||
function start(root){
|
function start(root){
|
||||||
if(root.axe){ return }
|
if(root.axe){ return }
|
||||||
var opt = root.opt, peers = opt.peers;
|
var opt = root.opt, peers = opt.peers;
|
||||||
@ -85,8 +83,8 @@ function start(root){
|
|||||||
var ref = root.$.get(soul)._, route = (ref||'').route;
|
var ref = root.$.get(soul)._, route = (ref||'').route;
|
||||||
//'test' === soul && console.log(Object.port, ''+msg['#'], has, val, route && route.keys());
|
//'test' === soul && console.log(Object.port, ''+msg['#'], has, val, route && route.keys());
|
||||||
if(!route){ return }
|
if(!route){ return }
|
||||||
q = Q[tmp = soul+has] || (Q[tmp] = {});
|
if(ref.skip){ ref.skip.now = msg['#']; return }
|
||||||
if(!Q[soul+has]){ setTimeout(function(){ id = Q[soul+has]; delete Q[soul+has]; // TODO: add debounce here!? hmm, scope would need sub. // Q is a quick hack!
|
(ref.skip = {now: msg['#']}).to = setTimeout(function(){
|
||||||
setTimeout.each(Object.maps(route), function(pid){ var peer, tmp;
|
setTimeout.each(Object.maps(route), function(pid){ var peer, tmp;
|
||||||
if(!(peer = route.get(pid))){ return }
|
if(!(peer = route.get(pid))){ return }
|
||||||
if(!peer.wire){ route.delete(pid); return } // bye!
|
if(!peer.wire){ route.delete(pid); return } // bye!
|
||||||
@ -101,16 +99,15 @@ function start(root){
|
|||||||
}
|
}
|
||||||
put[soul] = state_ify(put[soul], has, state, val, soul);
|
put[soul] = state_ify(put[soul], has, state, val, soul);
|
||||||
tmp = dup.track(peer.next = peer.next || String.random(9));
|
tmp = dup.track(peer.next = peer.next || String.random(9));
|
||||||
(tmp.back || (tmp.back = {}))[''+id] = 1;
|
(tmp.back || (tmp.back = {}))[''+ref.skip.now] = 1;
|
||||||
if(peer.to){ return }
|
if(peer.to){ return }
|
||||||
peer.to = setTimeout(function(){ flush(peer) }, opt.gap);
|
peer.to = setTimeout(function(){ flush(peer) }, opt.gap);
|
||||||
}) }, 9) }
|
}) }, 9);
|
||||||
Q[soul+has] = msg['#'];
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function flush(peer){
|
function flush(peer){
|
||||||
var msg = {'#': peer.next, put: peer.put, ok: {'@': 4, '/': mesh.near}}; // BUG: TODO: sub count!
|
var msg = {'#': peer.next, put: peer.put, ok: {'@': 3, '/': mesh.near}}; // BUG: TODO: sub count!
|
||||||
// TODO: what about DAM's >< dedup? Current thinking is, don't use it, however, you could store first msg# & latest msg#, and if here... latest === first then likely it is the same >< thing, so if(firstMsg['><'][peer.id]){ return } don't send.
|
// TODO: what about DAM's >< dedup? Current thinking is, don't use it, however, you could store first msg# & latest msg#, and if here... latest === first then likely it is the same >< thing, so if(firstMsg['><'][peer.id]){ return } don't send.
|
||||||
peer.next = peer.put = peer.to = null;
|
peer.next = peer.put = peer.to = null;
|
||||||
mesh.say(msg, peer);
|
mesh.say(msg, peer);
|
||||||
@ -141,7 +138,7 @@ function start(root){
|
|||||||
}());
|
}());
|
||||||
|
|
||||||
;(function(){ // THIS IS THE MOB MODULE;
|
;(function(){ // THIS IS THE MOB MODULE;
|
||||||
return; // WORK IN PROGRESS, TEST FINALIZED, NEED TO MAKE STABLE.
|
//return; // WORK IN PROGRESS, TEST FINALIZED, NEED TO MAKE STABLE.
|
||||||
/*
|
/*
|
||||||
AXE should have a couple of threshold items...
|
AXE should have a couple of threshold items...
|
||||||
let's pretend there is a variable max peers connected
|
let's pretend there is a variable max peers connected
|
||||||
@ -160,7 +157,8 @@ function start(root){
|
|||||||
root.on('hi', function(peer){
|
root.on('hi', function(peer){
|
||||||
this.to.next(peer);
|
this.to.next(peer);
|
||||||
if(peer.url){ return } // I am assuming that if we are wanting to make an outbound connection to them, that we don't ever want to drop them unless our actual config settings change.
|
if(peer.url){ return } // I am assuming that if we are wanting to make an outbound connection to them, that we don't ever want to drop them unless our actual config settings change.
|
||||||
var count = Object.keys(opt.peers).length || mesh.near; // TODO: BUG! This is slow, use .near, but near is buggy right now, fix in DAM.
|
var count = /*Object.keys(opt.peers).length ||*/ mesh.near; // TODO: BUG! This is slow, use .near, but near is buggy right now, fix in DAM.
|
||||||
|
//console.log("are we mobbed?", opt.mob, Object.keys(opt.peers).length, mesh.near);
|
||||||
if(opt.mob >= count){ return } // TODO: Make dynamic based on RAM/CPU also. Or possibly even weird stuff like opt.mob / axe.up length?
|
if(opt.mob >= count){ return } // TODO: Make dynamic based on RAM/CPU also. Or possibly even weird stuff like opt.mob / axe.up length?
|
||||||
var peers = {};Object.keys(axe.up).forEach(function(p){ p = axe.up[p]; p.url && (peers[p.url]={}) });
|
var peers = {};Object.keys(axe.up).forEach(function(p){ p = axe.up[p]; p.url && (peers[p.url]={}) });
|
||||||
// TODO: BUG!!! Infinite reconnection loop happens if not enough relays, or if some are missing. For instance, :8766 says to connect to :8767 which then says to connect to :8766. To not DDoS when system overload, figure clever way to tell peers to retry later, that network does not have enough capacity?
|
// TODO: BUG!!! Infinite reconnection loop happens if not enough relays, or if some are missing. For instance, :8766 says to connect to :8767 which then says to connect to :8766. To not DDoS when system overload, figure clever way to tell peers to retry later, that network does not have enough capacity?
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
;(function(){
|
;(function(){
|
||||||
var Gun = (typeof window !== "undefined")? window.Gun : require('../gun');
|
var Gun = (typeof window !== "undefined")? window.Gun : require('../gun');
|
||||||
|
|
||||||
Gun.on('opt', function(root){
|
Gun.on('opt', function(root){
|
||||||
this.to.next(root);
|
this.to.next(root);
|
||||||
var opt = root.opt;
|
var opt = root.opt;
|
||||||
@ -33,7 +32,7 @@
|
|||||||
// The above change corrects at least firefox RTC Peer handler where it **throws** on over 6 ice servers, and updates url: to urls: removing deprecation warning
|
// The above change corrects at least firefox RTC Peer handler where it **throws** on over 6 ice servers, and updates url: to urls: removing deprecation warning
|
||||||
opt.rtc.dataChannel = opt.rtc.dataChannel || {ordered: false, maxRetransmits: 2};
|
opt.rtc.dataChannel = opt.rtc.dataChannel || {ordered: false, maxRetransmits: 2};
|
||||||
opt.rtc.sdp = opt.rtc.sdp || {mandatory: {OfferToReceiveAudio: false, OfferToReceiveVideo: false}};
|
opt.rtc.sdp = opt.rtc.sdp || {mandatory: {OfferToReceiveAudio: false, OfferToReceiveVideo: false}};
|
||||||
opt.rtc.max = opt.rtc.max || 55; // is this a magic number?
|
opt.rtc.max = opt.rtc.max || 55; // is this a magic number? // For Future WebRTC notes: Chrome 500 max limit, however 256 likely - FF "none", webtorrent does 55 per torrent.
|
||||||
opt.rtc.room = opt.rtc.room || Gun.window && (location.hash.slice(1) || location.pathname.slice(1));
|
opt.rtc.room = opt.rtc.room || Gun.window && (location.hash.slice(1) || location.pathname.slice(1));
|
||||||
opt.announce = function(to){
|
opt.announce = function(to){
|
||||||
opt.rtc.start = +new Date; // handle room logic:
|
opt.rtc.start = +new Date; // handle room logic:
|
||||||
@ -57,7 +56,7 @@
|
|||||||
if(!msg.ok){ return }
|
if(!msg.ok){ return }
|
||||||
var rtc = msg.ok.rtc, peer, tmp;
|
var rtc = msg.ok.rtc, peer, tmp;
|
||||||
if(!rtc || !rtc.id || rtc.id === opt.pid){ return }
|
if(!rtc || !rtc.id || rtc.id === opt.pid){ return }
|
||||||
//console.log("webrtc:", rtc);
|
//console.log("webrtc:", JSON.stringify(msg));
|
||||||
if(tmp = rtc.answer){
|
if(tmp = rtc.answer){
|
||||||
if(!(peer = opt.peers[rtc.id] || open[rtc.id]) || peer.remoteSet){ return }
|
if(!(peer = opt.peers[rtc.id] || open[rtc.id]) || peer.remoteSet){ return }
|
||||||
tmp.sdp = tmp.sdp.replace(/\\r\\n/g, '\r\n');
|
tmp.sdp = tmp.sdp.replace(/\\r\\n/g, '\r\n');
|
||||||
@ -78,12 +77,10 @@
|
|||||||
wire.onopen = function(e){
|
wire.onopen = function(e){
|
||||||
delete open[rtc.id];
|
delete open[rtc.id];
|
||||||
mesh.hi(peer);
|
mesh.hi(peer);
|
||||||
//clearTimeout(wire.to);
|
|
||||||
//delete open[rtc.id];
|
|
||||||
}
|
}
|
||||||
wire.onmessage = function(msg){
|
wire.onmessage = function(msg){
|
||||||
if(!msg){ return }
|
if(!msg){ return }
|
||||||
console.log(opt.pid, "HEARD FROM WEBRTC:");
|
//console.log('via rtc');
|
||||||
mesh.hear(msg.data || msg, peer);
|
mesh.hear(msg.data || msg, peer);
|
||||||
};
|
};
|
||||||
peer.onicecandidate = function(e){ // source: EasyRTC!
|
peer.onicecandidate = function(e){ // source: EasyRTC!
|
||||||
@ -112,5 +109,4 @@
|
|||||||
return peer;
|
return peer;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var noop = function(){};
|
|
||||||
}());
|
}());
|
1884
package-lock.json
generated
1884
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -63,13 +63,13 @@
|
|||||||
"ws": "^7.2.1"
|
"ws": "^7.2.1"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@peculiar/webcrypto": "^1.1.1",
|
"@peculiar/webcrypto": "^1.1.1"
|
||||||
"emailjs": "^2.2.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"aws-sdk": "^2.528.0",
|
|
||||||
"ip": "^1.1.5",
|
|
||||||
"mocha": "^6.2.0",
|
"mocha": "^6.2.0",
|
||||||
|
"ip": "^1.1.5",
|
||||||
|
"aws-sdk": "^2.528.0",
|
||||||
|
"emailjs": "^2.2.0",
|
||||||
"uglify-js": "^3.6.0"
|
"uglify-js": "^3.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ This is the first in a series of basic networking correctness tests.
|
|||||||
Each test itself might be dumb and simple, but built up together,
|
Each test itself might be dumb and simple, but built up together,
|
||||||
they prove desired end goals for behavior at scale.
|
they prove desired end goals for behavior at scale.
|
||||||
|
|
||||||
1. (this file) Makes sure that a browser receives daisy chain acks that data was saved.
|
1. (this file) When Alice saves data, acks should daisy chain back to her.
|
||||||
2. (this file) Makes sure the browser receives a deduplicated ACK when data is requested across the daisy chains.
|
2. (this file) When Dave asks for data, Bob & Alice do not need to reply because it would be the same as Carl's reply.
|
||||||
|
|
||||||
Assume we have a 4 peer federated-like topology,
|
Assume we have a 4 peer federated-like topology,
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ describe("Put ACK", function(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(port, " connect to ", peers);
|
console.log(port, " connect to ", peers);
|
||||||
var gun = Gun({file: env.i+'data', peers: peers, web: server}); // Note: test with AXE on & off.
|
var gun = Gun({file: env.i+'data', peers: peers, web: server, axe: false}); // Note: test with AXE on & off.
|
||||||
server.listen(port, function(){
|
server.listen(port, function(){
|
||||||
test.done();
|
test.done();
|
||||||
});
|
});
|
||||||
@ -107,8 +107,10 @@ describe("Put ACK", function(){
|
|||||||
try{ localStorage.clear() }catch(e){}
|
try{ localStorage.clear() }catch(e){}
|
||||||
try{ indexedDB.deleteDatabase('radata') }catch(e){}
|
try{ indexedDB.deleteDatabase('radata') }catch(e){}
|
||||||
var env = test.props;
|
var env = test.props;
|
||||||
|
|
||||||
var gun = Gun('http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun');
|
var gun = Gun('http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun');
|
||||||
window.ref = gun.get('a');
|
window.ref = gun.get('a');
|
||||||
|
|
||||||
}, {i: i += 1, config: config}));
|
}, {i: i += 1, config: config}));
|
||||||
});
|
});
|
||||||
return Promise.all(tests);
|
return Promise.all(tests);
|
||||||
@ -122,34 +124,34 @@ describe("Put ACK", function(){
|
|||||||
var c = test.props.acks, acks = {}, tmp;
|
var c = test.props.acks, acks = {}, tmp;
|
||||||
c = c < 2? 2 : c; // at least 2 acks.
|
c = c < 2? 2 : c; // at least 2 acks.
|
||||||
ref.put({hello: 'world'}, function(ack){
|
ref.put({hello: 'world'}, function(ack){
|
||||||
//console.log("ack:", ack['#']);
|
|
||||||
acks[ack['#']] = 1; // uniquely list all the ack IDs.
|
acks[ack['#']] = 1; // uniquely list all the ack IDs.
|
||||||
tmp = Object.keys(acks).length;
|
tmp = Object.keys(acks).length;
|
||||||
console.log(tmp, "save");
|
|
||||||
if(tmp >= c){ // when there are enough
|
if(tmp >= c){ // when there are enough
|
||||||
|
setTimeout(function(){
|
||||||
test.done(); // confirm test passes
|
test.done(); // confirm test passes
|
||||||
wire(); // start sniffing for future tests
|
wire(); // start sniffing for future tests
|
||||||
|
}, 1000 * 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}, {acks: c});
|
}, {acks: c, ok: c*10}); // TODO: Upon breaking change (> 2020) update this test with the deprecated `acks` behavior.
|
||||||
|
|
||||||
function wire(){ // for the future tests, track how many wire messages are heard/sent.
|
function wire(){ // for the future tests, track how many wire messages are heard/sent.
|
||||||
ref.hear = ref.hear || [];
|
ref.hear = ref.hear || [];
|
||||||
var dam = ref.back('opt.mesh');
|
var dam = ref.back('opt.mesh');
|
||||||
var hear = dam.hear;
|
var hear = dam.hear;
|
||||||
dam.hear = function(raw, peer){ // hijack the listener
|
dam.hear = function(raw, peer){
|
||||||
var msg; try{msg = JSON.parse(raw);
|
|
||||||
}catch(e){ console.log("Note: This test not support RAD serialization format yet, use JSON.") }
|
|
||||||
hear(raw, peer);
|
hear(raw, peer);
|
||||||
ref.hear.push(msg || raw); // add to count
|
ref.hear.push(raw);
|
||||||
}
|
}
|
||||||
var say = dam.say;
|
|
||||||
dam.say = function(raw, peer){
|
var peers = ref.back('opt.peers');
|
||||||
var yes = say(raw, peer);
|
Object.keys(peers).forEach(function(peer){
|
||||||
if(yes === false){ return }
|
peer = peers[peer];
|
||||||
console.log(msg);
|
peer.say = function(raw){
|
||||||
(ref.say || (ref.say = [])).push(JSON.parse(msg)); // add to count.
|
(ref.say || (ref.say = [])).push(raw); // add to count.
|
||||||
|
peer.wire.send(raw);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, {acks: config.relays});
|
}, {acks: config.relays});
|
||||||
});
|
});
|
||||||
@ -176,7 +178,7 @@ describe("Put ACK", function(){
|
|||||||
var hear = dam.hear;
|
var hear = dam.hear;
|
||||||
dam.hear = function(raw, peer){ // hijack listener
|
dam.hear = function(raw, peer){ // hijack listener
|
||||||
var msg = JSON.parse(raw);
|
var msg = JSON.parse(raw);
|
||||||
console.log('hear:', msg);
|
//console.log('hear:', msg);
|
||||||
hear(raw, peer);
|
hear(raw, peer);
|
||||||
ref.hear.push(msg);
|
ref.hear.push(msg);
|
||||||
|
|
||||||
|
225
test/panic/4putackdedup.js
Normal file
225
test/panic/4putackdedup.js
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
Assume we have 5000 peers in a star topology,
|
||||||
|
|
||||||
|
..______r1______..
|
||||||
|
./.../..|...\...\.
|
||||||
|
b1..b2..b3..b4..b5
|
||||||
|
|
||||||
|
They are all subscribed to the same data and Alice makes a 1 byte change to it. Even if a save acknowledgement is 1 byte, that would be 5K times the change. This does not scale. So instead, Alice states a sample size of 3/X and then the peers saving data use that ratio to decide whether they ack.
|
||||||
|
|
||||||
|
Each time the message gets relayed we modify X to be how many peers this hop sent it to. We also should decrease the sample size by 1.
|
||||||
|
|
||||||
|
This test checks that we get fewer acks than (half) the peers connected.
|
||||||
|
This also tests that custom ACKs get sent back thru AXE to one of the sending peers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// <-- PANIC template, copy & paste, tweak a few settings if needed...
|
||||||
|
var ip; try{ ip = require('ip').address() }catch(e){}
|
||||||
|
var config = {
|
||||||
|
IP: ip || 'localhost',
|
||||||
|
port: 8765,
|
||||||
|
relays: 1,
|
||||||
|
browsers: 9,
|
||||||
|
route: {
|
||||||
|
'/': __dirname + '/index.html',
|
||||||
|
'/gun.js': __dirname + '/../../gun.js',
|
||||||
|
'/jquery.js': __dirname + '/../../examples/jquery.js'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var panic; try{ panic = require('panic-server') } catch(e){ console.log("PANIC not installed! `npm install panic-server panic-manager panic-client`") }
|
||||||
|
|
||||||
|
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.relays).fill().map(function(u, i){
|
||||||
|
return {
|
||||||
|
type: 'node',
|
||||||
|
port: config.port + (i + 1)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
panic: 'http://' + config.IP + ':' + config.port
|
||||||
|
});
|
||||||
|
|
||||||
|
var relays = clients.filter('Node.js');
|
||||||
|
var r1 = relays.pluck(1);
|
||||||
|
|
||||||
|
var browsers = clients.excluding(relays);
|
||||||
|
var b1 = browsers.pluck(1);
|
||||||
|
var others = browsers.excluding(b1);
|
||||||
|
var b2 = relays.excluding(b1).pluck(1);
|
||||||
|
var b3 = relays.excluding([b1,b2]).pluck(1);
|
||||||
|
var b4 = relays.excluding([b1,b2]).pluck(1);
|
||||||
|
var b5 = relays.excluding([b1,b2]).pluck(1);
|
||||||
|
|
||||||
|
// continue boiler plate, tweak a few defaults if needed, but give descriptive test names...
|
||||||
|
describe("Dedup load balancing GETs", function(){
|
||||||
|
//this.timeout(5 * 60 * 1000);
|
||||||
|
this.timeout(10 * 60 * 1000);
|
||||||
|
|
||||||
|
it("Relays have joined!", function(){
|
||||||
|
return relays.atLeast(config.relays);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("GUN started!", function(){
|
||||||
|
var tests = [], i = 0;
|
||||||
|
relays.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; try{ Gun = require('gun') }catch(e){ console.log("GUN not found! You need to link GUN to PANIC. Nesting the `gun` repo inside a `node_modules` parent folder often fixes this.") }
|
||||||
|
var peers = [], i = env.config.relays;
|
||||||
|
while(i--){
|
||||||
|
var tmp = (env.config.port + (i + 1));
|
||||||
|
if(port != tmp){ // ignore ourselves
|
||||||
|
peers.push('http://'+ env.config.IP + ':' + tmp + '/gun');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var gun = Gun({peers: peers, web: server, rad: false, radisk: false, file: false, localStorage: false, axe: false});
|
||||||
|
server.listen(port, function(){
|
||||||
|
test.done();
|
||||||
|
});
|
||||||
|
}, {i: i += 1, config: config}));
|
||||||
|
});
|
||||||
|
return Promise.all(tests);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(config.browsers +" browser(s) have joined!", function(){
|
||||||
|
require('./util/open').web(config.browsers, "http://"+ config.IP +":"+ config.port);
|
||||||
|
return browsers.atLeast(config.browsers);
|
||||||
|
});
|
||||||
|
// end PANIC template -->
|
||||||
|
|
||||||
|
it("Browsers initialized gun!", function(){
|
||||||
|
var tests = [], i = 0;
|
||||||
|
browsers.each(function(browser, id){
|
||||||
|
tests.push(browser.run(function(test){
|
||||||
|
try{ localStorage.clear() }catch(e){}
|
||||||
|
try{ indexedDB.deleteDatabase('radata') }catch(e){}
|
||||||
|
|
||||||
|
// start with the first peer:
|
||||||
|
var env = test.props;
|
||||||
|
var gun = Gun({peers: 'http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun', localStorage: false});
|
||||||
|
|
||||||
|
window.gun = gun;
|
||||||
|
window.ref = gun.get('test');
|
||||||
|
|
||||||
|
ref.on(function(data){ });
|
||||||
|
|
||||||
|
}, {i: i += 1, config: config}));
|
||||||
|
});
|
||||||
|
return Promise.all(tests);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ACK", function(){
|
||||||
|
var tests = [], i = 0;
|
||||||
|
others.each(function(browser, id){
|
||||||
|
tests.push(browser.run(function(test){
|
||||||
|
var id = test.props.i;
|
||||||
|
|
||||||
|
// these lines are for debugging...
|
||||||
|
/*var dam = ref.back('opt.mesh');
|
||||||
|
var say = dam.say;
|
||||||
|
dam.say = function(raw, peer){
|
||||||
|
say(raw, peer);
|
||||||
|
//console.log("said:", JSON.stringify(raw));
|
||||||
|
}
|
||||||
|
var hear = dam.hear;
|
||||||
|
dam.hear = function(raw, peer){
|
||||||
|
//console.log("heard:", raw);
|
||||||
|
hear(raw, peer);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
gun.on('put', function(msg){
|
||||||
|
var ok = msg.ok;
|
||||||
|
if(ok['@'] > 2){
|
||||||
|
console.log("Relay did not decrement!")
|
||||||
|
test.fail("Relay did not decrement!");
|
||||||
|
_relay_did_not_decrement;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(Math.random() > (ok['@'] / ok['/'])){ return }
|
||||||
|
console.log('ack?', JSON.stringify(msg));
|
||||||
|
//console.log("WAS THE SPECIAL ONE TO ACK!", JSON.stringify(msg));
|
||||||
|
gun.on('out', {'@': msg['#'], ok: {yay: 1}});
|
||||||
|
});
|
||||||
|
|
||||||
|
}, {i: i += 1, config: config}));
|
||||||
|
});
|
||||||
|
return Promise.all(tests);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("wait...", function(done){
|
||||||
|
setTimeout(function(){
|
||||||
|
done();
|
||||||
|
},2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Alice saves data", function(){
|
||||||
|
return b1.run(function(test){
|
||||||
|
test.async();
|
||||||
|
|
||||||
|
// these lines are for debugging...
|
||||||
|
/*var dam = ref.back('opt.mesh');
|
||||||
|
var say = dam.say;
|
||||||
|
dam.say = function(raw, peer){
|
||||||
|
say(raw, peer);
|
||||||
|
//console.log("said:", JSON.stringify(raw), dam.near, Object.keys(gun._.opt.peers).join(','));
|
||||||
|
}
|
||||||
|
var hear = dam.hear;
|
||||||
|
dam.hear = function(raw, peer){
|
||||||
|
hear(raw, peer);
|
||||||
|
//console.log("heard:", raw);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
var many = test.props.config.browsers;
|
||||||
|
console.log("Alice is saving...");
|
||||||
|
test.c = 0;
|
||||||
|
ref.put({hello: 'world'}, function(ack){
|
||||||
|
if(!ack.ok.yay){
|
||||||
|
test.fail("ERROR: No custom ack!");
|
||||||
|
console.log("ERROR: No custom ack!");
|
||||||
|
return no_custom_ack;
|
||||||
|
}
|
||||||
|
//console.log("I saved data, this is the ACK", JSON.stringify(ack));
|
||||||
|
test.c++;
|
||||||
|
clearTimeout(test.to);
|
||||||
|
test.to = setTimeout(function(){
|
||||||
|
if(test.c >= (many/2)){
|
||||||
|
test.fail("ERROR: Too many acks!");
|
||||||
|
console.log("ERROR: Too many acks!");
|
||||||
|
return too_many_acks;
|
||||||
|
}
|
||||||
|
test.done();
|
||||||
|
}, 999);
|
||||||
|
|
||||||
|
}, {ok: 3, acks: 9999});
|
||||||
|
}, {config: config});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("All finished!", function(done){
|
||||||
|
console.log("Done! Cleaning things up...");
|
||||||
|
setTimeout(function(){
|
||||||
|
done();
|
||||||
|
},1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
after("Everything shut down.", function(){
|
||||||
|
console.log("REMINDER: RUN THIS TEST WITH AXE ON & OFF!");
|
||||||
|
require('./util/open').cleanup();
|
||||||
|
return relays.run(function(){
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -131,17 +131,18 @@ describe("Mob test.", function(){
|
|||||||
var gun = Gun('http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun');
|
var gun = Gun('http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun');
|
||||||
|
|
||||||
// NOTE: This "mob" logic will be moved into axe.js (or maybe gun.js itself), but while we're building the logic it is easier to quickly hack/iterate by prototyping here in the test itself until it passes. But it needs to be refactored into the actual code or else you might have false positives of this test overloading "mob" logic.
|
// NOTE: This "mob" logic will be moved into axe.js (or maybe gun.js itself), but while we're building the logic it is easier to quickly hack/iterate by prototyping here in the test itself until it passes. But it needs to be refactored into the actual code or else you might have false positives of this test overloading "mob" logic.
|
||||||
|
// ^^^^^^^^^ THIS HAS BEEN MOVED TO GUN CORE, HOWEVER,
|
||||||
|
// ^^^^^^^^^ EXPERIMENT WITH MORE ADVANCED LOGIC THAT AXE OVERLOADS CORE.
|
||||||
var mesh = gun.back('opt.mesh'); // overload...
|
var mesh = gun.back('opt.mesh'); // overload...
|
||||||
mesh.hear['mob'] = function(msg, peer){
|
/*mesh.hear['mob'] = function(msg, peer){
|
||||||
// TODO: NOTE, code AXE DHT to aggressively drop new peers AFTER superpeer sends this rebalance/disconnect message that contains some other superpeers.
|
// TODO: NOTE, code AXE DHT to aggressively drop new peers AFTER superpeer sends this rebalance/disconnect message that contains some other superpeers.
|
||||||
clearTimeout(gun.TO); gun.TO = setTimeout(end, 2000);
|
clearTimeout(gun.TO); gun.TO = setTimeout(end, 2000);
|
||||||
console.log("getting mobbed", msg);
|
|
||||||
if(!msg.peers){ return }
|
if(!msg.peers){ return }
|
||||||
var peers = Object.keys(msg.peers), one = peers[Math.floor(Math.random()*peers.length)];
|
var peers = Object.keys(msg.peers), one = peers[Math.floor(Math.random()*peers.length)];
|
||||||
console.log('Browser', env.i, 'chooses', one, 'from', JSON.stringify(peers), 'that', peer.url, 'suggested, because it is mobbed.');//, 'from', msg.peers+'');
|
console.log('Browser', env.i, 'chooses', one, 'from', JSON.stringify(peers), 'that', peer.url, 'suggested, because it is mobbed.');//, 'from', msg.peers+'');
|
||||||
mesh.bye(peer); // Idea: Should keep track of failed ones to reduce repeats. For another feature/module that deserves its own separate test.
|
mesh.bye(peer); // Idea: Should keep track of failed ones to reduce repeats. For another feature/module that deserves its own separate test.
|
||||||
mesh.hi(one);
|
mesh.hi(one);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
//console.log('Browser', env.i, "started with:", Object.keys(gun._.opt.peers)+'');
|
//console.log('Browser', env.i, "started with:", Object.keys(gun._.opt.peers)+'');
|
||||||
window.gun = gun;
|
window.gun = gun;
|
Loading…
x
Reference in New Issue
Block a user