Merge pull request #853 from amark/dev

Dev
This commit is contained in:
Mark Nadal 2019-12-12 16:28:22 -08:00 committed by GitHub
commit fc00ed0239
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1606 additions and 93 deletions

29
axe.js
View File

@ -60,6 +60,20 @@
// with one common superpeer (with ready failovers) // with one common superpeer (with ready failovers)
// in case the p2p linear latency is high. // in case the p2p linear latency is high.
// Or there could be plenty of other better options. // Or there could be plenty of other better options.
/*
AXE should have a couple of threshold items...
let's pretend there is a variable max peers connected
mob = 10000
if we get more peers than that...
we should start sending those peers a remote command
that they should connect to this or that other peer
and then once they (or before they do?) drop them from us.
sake of the test... gonna set that peer number to 1.
The mob threshold might be determined by other factors,
like how much RAM or CPU stress we have.
*/
opt.mob = opt.mob || Infinity;
var mesh = opt.mesh = opt.mesh || Gun.Mesh(at); var mesh = opt.mesh = opt.mesh || Gun.Mesh(at);
console.log("AXE enabled."); console.log("AXE enabled.");
@ -256,7 +270,7 @@
this.to.next(peer); this.to.next(peer);
if(!peer.url){ return } if(!peer.url){ return }
axe.up[peer.id] = peer; axe.up[peer.id] = peer;
}) });
at.on('bye', function(peer){ this.to.next(peer); at.on('bye', function(peer){ this.to.next(peer);
if(peer.url){ delete axe.up[peer.id] } if(peer.url){ delete axe.up[peer.id] }
Gun.obj.map(peer.routes, function(route, hash){ Gun.obj.map(peer.routes, function(route, hash){
@ -266,6 +280,19 @@
} }
}); });
}); });
// handle rebalancing a mob of peers:
at.on('hi', function(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.
var count = Object.keys(opt.peers).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?
mesh.say({dam: 'mob', mob: count, peers: Object.keys(axe.up)}, peer);
//setTimeout(function(){ mesh.bye(peer) }, 9); // something with better perf? // UNCOMMENT WHEN WE ACTIVATE THIS FEATURE
});
at.on('bye', function(peer){
this.to.next(peer);
});
} }
function joindht(dht, soul, pids) { function joindht(dht, soul, pids) {

View File

@ -31,12 +31,18 @@
<script src="../../gun/lib/monotype.js"></script> <script src="../../gun/lib/monotype.js"></script>
<script src="../../gun/lib/meta.js"></script> <script src="../../gun/lib/meta.js"></script>
<script src="../../gun/lib/normalize.js"></script> <script src="../../gun/lib/normalize.js"></script>
<script async src="../../gun/lib/fun.js"></script>
<script async src="../../gun/lib/music.js"></script>
<!-- script async src="https://edide.io/music.lib"></script -->
<script> <script>
var gun = Gun('https://guntest.herokuapp.com/gun'); var gun = Gun(['https://guntest.herokuapp.com/gun', 'http://localhost:8765/gun']);
;(window.onhashchange = function(){ ;(window.onhashchange = function(){
var file = (location.hash||'').slice(1); var file = (location.hash||'').slice(1);
var S = +new Date; var S = +new Date;
$('#page').empty().attr('contenteditable', 'false');
gun.get('test/gun/docs/'+file).get('what').map().on(function render(data, i){ gun.get('test/gun/docs/'+file).get('what').map().on(function render(data, i){
if(window.LOCK){ return } if(window.LOCK){ return }
var p = $('#page').children().get(i); var p = $('#page').children().get(i);
@ -50,15 +56,8 @@ var gun = Gun('https://guntest.herokuapp.com/gun');
p.outerHTML = safe; p.outerHTML = safe;
r.restore(); r.restore();
}); });
return;
gun.get('test/gun/docs/'+file).get('what').once(function(data){
console.log(+new Date - S, 'ms load');
$('#page').html($.normalize(data));
});
})(); })();
$("<textarea id='debug'>").css({position: 'fixed', height: '5em', width: '100%', bottom: 0, left: 0, 'font-size': '18pt'}).appendTo('body')
document.execCommand('defaultParagraphSeparator', false, 'p'); document.execCommand('defaultParagraphSeparator', false, 'p');
meta.edit({ meta.edit({
name: "Edit", name: "Edit",
@ -66,21 +65,18 @@ meta.edit({
use: function(eve){ use: function(eve){
console.log('on'); console.log('on');
}, on: function(eve){ }, on: function(eve){
if($(eve.target).closest('p').length){ return }
var edit = this; var edit = this;
meta.flip(false); setTimeout(function(){ meta.flip(false) },1);
var doc = $('#page').attr('contenteditable', 'true'); edit.init();
if(!doc.text()){
doc.html('<p class="loud crack"></p>');
edit.select(doc.children().first().get(0));
}
$(document).on('keydown.tmp', '[contenteditable]', function(eve){ $(document).on('keydown.tmp', '[contenteditable]', function(eve){
if(eve.which != 13){ return } if(eve.which != 13){ return }
eve.preventDefault(); eve.preventDefault();
var r = window.getSelection().getRangeAt(0); var r = window.getSelection().getRangeAt(0);
var c = r.commonAncestorContainer; var c = r.commonAncestorContainer, p;
r.deleteContents(); r.deleteContents();
c.splitText(r.startOffset); var p = c.splitText? $(c.splitText(r.startOffset)).parent() : $(c);
var p = $(c).parent(), n = $("<"+p.get(0).tagName+">"), f; var n = $("<"+p.get(0).tagName+">"), f;
p.contents().each(function(){ p.contents().each(function(){
if(this === c){ return f = true } if(this === c){ return f = true }
if(!f){ return } if(!f){ return }
@ -94,10 +90,13 @@ meta.edit({
edit.save(this); edit.save(this);
}); });
}).on('keyup.tmp', '[contenteditable]', function(eve){ }).on('keyup.tmp', '[contenteditable]', function(eve){
$('#debug').val(doc.html()); //$('#debug').val(doc.html());
var p = $(window.getSelection().anchorNode).closest('p'); var p = $(window.getSelection().anchorNode).closest('p');
var r = monotype(p); var r = monotype(p);
var html = p.html() || ''; var html = p.html() || '';
if(!html && !p.prev().length && !p.next().length && !$('#page').html()){
edit.init();
}
var safe = $.normalize(html); var safe = $.normalize(html);
p.html(safe); p.html(safe);
r.restore(); r.restore();
@ -108,11 +107,19 @@ meta.edit({
console.log("UP"); console.log("UP");
$('[contenteditable=true]').off('.tmp'); $('[contenteditable=true]').off('.tmp');
}, },
init: function(){
var edit = this;
var doc = $('#page').attr('contenteditable', 'true');
if(!doc.text()){
doc.html('<p class="loud crack"></p>');
}
edit.select(doc.children().first().get(0));
},
save: function(p){ save: function(p){
p = $(p); p = $(p);
var i = p.index();// = Array.prototype.indexOf.call(parent.children, child); var i = p.index();// = Array.prototype.indexOf.call(parent.children, child);
var file = (location.hash||'').slice(1); var file = (location.hash||'').slice(1);
var data = p.get(0).outerHTML; var data = (p.get(0)||{}).outerHTML||'';
window.LOCK = true; window.LOCK = true;
gun.get('test/gun/docs/'+file).get('what').get(i).put(data); gun.get('test/gun/docs/'+file).get('what').get(i).put(data);
window.LOCK = false; window.LOCK = false;
@ -135,18 +142,100 @@ meta.edit({
} }
}); });
meta.edit({ ;(function(){
name: "Save",
combo: ['S'], fake: -1, meta.edit({name: "Layout", combo: ['L']});
meta.edit({name: "Fill", combo: ['L','F'],
use: function(eve){},
on: function(eve){ on: function(eve){
return; var on = meta.tap();
meta.tap.on.attr('contenteditable', 'false'); meta.ask('Color name, code, or URL?', function(color){
var what = $.normalize($('#page').html()); on.css('background', color);
var file = (location.hash||'').slice(1);
gun.get('test/gun/docs/'+file).put({what: what});
},
up: function(){}
}); });
},
up: function(eve){}
});
meta.edit({name: "Add", combo: ['L','A']});
meta.edit({name: "Row", combo: ['L','A', 'R'],
on: function(eve){
meta.tap().append('<div style="min-height: 9em; padding: 2%;">');
}
});
meta.edit({name: "Columns", combo: ['L','A','C'],
on: function(eve){
var on = meta.tap().addClass('center'), tmp, c;
var html = '<div class="unit col" style="min-height: 9em; padding: 2%;"></div>';
if(!on.children('.col').length){ html += html }
c = (tmp = on.append(html).children('.col')).length;
tmp.each(function(){
$(this).css('width', (100/c)+'%');
})
}
});
meta.edit({name: "Text", combo: ['L','A','T'],
on: function(eve){
var tag = $('<p>text</p>');
meta.tap().append(tag);
tag.focus();
}
});
}());
;(function(){
var song = {};
// TODO:
// 1. Manually OR automatically load music.js API, dependencies, and modules. - FINE for now
// 2. only export music API, not meta, not dom, not mouselock system, not UI/html, etc. better module isolation and export.
// 3. `var wave = Wave('a').play()` // also on `Music.now`
// defaults... instrument: pure tones, volume curve: |\_ , speed curve: 0.5
// 4. `wave.blur(0.5).itch(0.5);`
// 5. wave.long(2); // how long in seconds each note plays, optionally: wave.pace(60) is bpm
// 6. wave.loud(0.5); // 0% to 100% volume loudness of device output.
// 7. wave.vary(0.5); // slows down or speeds up wiggle per harmonic
// 8:
// wave structure, does ToneJS allow us to change the sine wave smoothness/type continuously or is it a pre-fixed type?
// wave structure: /\/\/, |_|, /|/, \|\| do some research with ToneJS whether these are dynamic or fixed
// wave.itch(); // changes the shape of the wiggle from smooth sine to square or triangle
// wave.blur(220hz); // blur may not apply/work on pure notes other than filtering them.
meta.edit({name: "Music", combo: ['M']});
meta.edit({name: "Play", combo: ['M','P'],
on: function(eve){
// TODO: We still need to add to meta API ability to change name.
if(song.play){
music.stop();
song.play = false;
return;
}
song.play = true;
music.stop();
setTimeout(function(){
song.now = music.play($('#page').text());
},250);
}
});
meta.edit({name: "Blur", combo: ['M','B'],
on: function(eve){
$(document).on('mousemove.tmp', function(eve){
var x = eve.pageX;
song.now.blur(x);
});
},
up: function(){
$(document).off('.tmp');
}
});
$(document).on('keydown', function(eve){
music.play(String.fromCharCode(eve.which));
});
}());
</script> </script>
</body> </body>
</html> </html>

View File

@ -53,6 +53,10 @@
$('#hours').text((data.up.time / 60 / 60).toFixed(0)); $('#hours').text((data.up.time / 60 / 60).toFixed(0));
Stats('memory').line.append(+new Date, data.memory.heapTotal / 1024 / 1024); Stats('memory').line.append(+new Date, data.memory.heapTotal / 1024 / 1024);
try{ Stats('dam # in').line.append(+new Date, data.dam.in.count); }catch(e){}
try{ Stats('dam in MB').line.append(+new Date, data.dam.in.done / 1024 / 1024); }catch(e){}
try{ Stats('dam # out').line.append(+new Date, data.dam.out.count); }catch(e){}
try{ Stats('dam out MB').line.append(+new Date, data.dam.out.done / 1024 / 1024); }catch(e){}
console.log('data',data); console.log('data',data);
//fetch keys in all, these may be dynamically changing //fetch keys in all, these may be dynamically changing

4
gun.js
View File

@ -961,7 +961,7 @@
if(obj_has(back, 'put')){ if(obj_has(back, 'put')){
back.on('in', back); back.on('in', back);
} }
if(tmp){ return } if(tmp && u !== back.put){ return } //if(tmp){ return }
msg.$ = back.$; msg.$ = back.$;
} else } else
if(obj_has(back.put, get)){ // TODO: support #LEX ! if(obj_has(back.put, get)){ // TODO: support #LEX !
@ -1174,7 +1174,7 @@
if(u === tmp && u !== at.put){ return true } if(u === tmp && u !== at.put){ return true }
neat.put = u; neat.put = u;
if(neat.ack){ if(neat.ack){
neat.ack = -1; // TODO: BUG? Should this be 0? neat.ack = -1; // Shouldn't this be reset to 0? If we do that, SEA test `set user ref should be found` fails, odd.
} }
neat.on('in', { neat.on('in', {
get: key, get: key,

View File

@ -17,6 +17,7 @@
/* UNBUILD */ /* UNBUILD */
;USE(function(module){ ;USE(function(module){
var noop = function(){}, u; var noop = function(){}, u;
$.fn.or = function(s){ return this.length ? this : $(s||'body') }; $.fn.or = function(s){ return this.length ? this : $(s||'body') };
var m = window.meta = {edit:[]}; var m = window.meta = {edit:[]};
@ -30,17 +31,16 @@
var key = (k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode; var key = (k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode;
// ADDED // ADDED
if(!m.flip.is() && !k.meta[key]){ return } // cancel non-open events when closed TODO make optional //if(!m.flip.is() && !k.meta[key]){ return } // cancel non-open events when closed TODO make optional
if(!k.meta[key] && withMeta(eve) && !k.at[key]) { return m.flip(false) } // cancel and close when no action and "meta key" held down (e.g. ctrl+c) if(!k.meta[key] && withMeta(eve) && !k.at[key]) { return m.flip(false) } // cancel and close when no action and "meta key" held down (e.g. ctrl+c)
if(!eve.fake && key === k.last){ return }; k.last = key; // jussi: polyfilling eve.repeat? if(!eve.fake && key === k.last){ return }; k.last = key; // jussi: polyfilling eve.repeat?
if(!eve.fake && $(eve.target).closest('input, textarea, [contenteditable=true]').length){ if(!eve.fake && $(eve.target).closest('input, textarea, [contenteditable=true]').length && !$(eve.target).closest('#meta').length){
if(!meta.flip.is() && !withMeta(eve)){ // cancel meta/hud during text input UNLESS hud is open OR cmd key is held down.
return;
}
//if(k.meta[key]){ k.down.meta = key = -1 } //if(k.meta[key]){ k.down.meta = key = -1 }
//if(!k.down.meta){ return } //if(!k.down.meta){ return }
// prevent typing with meta open
if(meta.flip.is() && !withMeta(eve)) eve.preventDefault()
// hmmm? // hmmm?
//if(!k.meta[key] && !meta.flip.is()) return // aserwed //if(!k.meta[key] && !meta.flip.is()) return // aserwed
} }
@ -53,7 +53,7 @@
} }
k.up = function(eve){ var tmp; k.up = function(eve){ var tmp;
var key = (k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode; var key = (k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode;
if(!m.flip.is() && !k.meta[key]){ return } // ADDED cancel non-open events when closed TODO make optional //if(!m.flip.is() && !k.meta[key]){ return } // ADDED cancel non-open events when closed TODO make optional
// if(!eve.fake && $(eve.target).closest('input, textarea, [contenteditable=true]').length){ // if(!eve.fake && $(eve.target).closest('input, textarea, [contenteditable=true]').length){
// if(k.meta[key]){ // if(k.meta[key]){
// k.down.meta = null; // k.down.meta = null;
@ -131,7 +131,8 @@
eve.preventDefault(); eve.preventDefault();
cb($put.val()); cb($put.val());
$li.remove(); $li.remove();
k.wipe(); //k.wipe();
m.list(k.at);
}); });
var $li = $('<li>').append($form); var $li = $('<li>').append($form);
$ul.append($li); $ul.append($li);
@ -147,7 +148,7 @@
m.tap = function(){ m.tap = function(){
var on = $('.meta-on') var on = $('.meta-on')
.or($($(document.querySelectorAll(':hover')).get().reverse()).first()) .or($($(document.querySelectorAll(':hover')).get().reverse()).first())
.or($(document.elementFromPoint(meta.tap.x, meta.tap.y))); .or($(document.elementFromPoint(meta.tap.x||0, meta.tap.y||0)));
return on; return on;
} }
meta.edit = function(edit){ meta.edit = function(edit){
@ -236,7 +237,8 @@
'border-radius': '1em', 'border-radius': '1em',
'margin-left': '0.25em', 'margin-left': '0.25em',
'margin-top': '0.25em', 'margin-top': '0.25em',
'float': 'right' 'float': 'right',
'cursor': 'pointer'
}, },
'#meta a': {color: 'black'}, '#meta a': {color: 'black'},
// '#meta:hover': {opacity: 1}, // '#meta:hover': {opacity: 1},
@ -274,6 +276,7 @@
})(USE, './metaUI'); })(USE, './metaUI');
;USE(function(module){ ;USE(function(module){
// include basic text editing by default. // include basic text editing by default.
var monotype = window.monotype || function(){console.log("monotype needed")}; var monotype = window.monotype || function(){console.log("monotype needed")};
var m = meta; var m = meta;
@ -420,13 +423,13 @@
})(USE, './metaText'); })(USE, './metaText');
;USE(function(module){ ;USE(function(module){
var m = meta, k = m.key; var m = meta, k = m.key;
$(window).on('blur', k.wipe.bind(null, false)).on('focus', k.wipe.bind(null, false)); $(window).on('focus', k.wipe.bind(null, false)); // .on('blur', k.wipe.bind(null, false))
//$(document).on('mousedown mousemove mouseup', function(eve){ $(document).on('mousedown mousemove mouseup', function(eve){
// m.tap.eve = eve; m.tap.eve = eve;
// m.tap.x = eve.pageX||0; m.tap.x = eve.pageX||0;
// m.tap.y = eve.pageY||0; m.tap.y = eve.pageY||0;
// m.tap.on = $(eve.target); m.tap.on = $(eve.target);
//}) })
// Setting m.tap.edit has been commented, so should never end up here? // Setting m.tap.edit has been commented, so should never end up here?
//.on('mousedown touchstart', function(eve){ //.on('mousedown touchstart', function(eve){
// var tmp = m.tap.edit; // var tmp = m.tap.edit;
@ -437,11 +440,16 @@
//$(document).on('touchstart', '#meta .meta-start', function(eve){ m.tap.stun = true }); //$(document).on('touchstart', '#meta .meta-start', function(eve){ m.tap.stun = true });
$(document).on('click', '#meta .meta-menu li', function(eve){ var [start, end] = 'ontouchstart' in window
? ['touchstart', 'touchend']
: ['mousedown', 'mouseup']
$(document).on(start, '#meta .meta-menu li', function(eve){
var combo = $(this).data().combo; var combo = $(this).data().combo;
eve.fake = eve.which = combo && combo.slice(-1)[0].charCodeAt(0); eve.fake = eve.which = combo && combo.slice(-1)[0].charCodeAt(0);
eve.tap = true; eve.tap = true;
k.down(eve); k.up(eve); k.down(eve);
$(document).one(end, () => k.up(eve))
return; return;
// if(m.tap.stun){ return m.tap.stun = false } // if(m.tap.stun){ return m.tap.stun = false }
// if(!(eve.fake = eve.which = (($(this).text().match(/[A-Z]/)||{})[0]||'').toUpperCase().charCodeAt(0))){ return } // if(!(eve.fake = eve.which = (($(this).text().match(/[A-Z]/)||{})[0]||'').toUpperCase().charCodeAt(0))){ return }
@ -451,6 +459,11 @@
}); });
$(document).on('keydown', k.down).on('keyup', k.up); $(document).on('keydown', k.down).on('keyup', k.up);
$('#meta').on('click', function(ev) {
if (ev.target.tagName == 'LI' || ev.target.tagName == 'UL') return
meta.flip()
})
//$(document).on('select contextmenu keyup mouseup', '[contenteditable=true]', m.text.on); //$(document).on('select contextmenu keyup mouseup', '[contenteditable=true]', m.text.on);

View File

@ -22,7 +22,7 @@ Gun.on('create', function(root){
socket.bind({port: udp.port, exclusive: true}, function(){ socket.bind({port: udp.port, exclusive: true}, function(){
socket.setBroadcast(true); socket.setBroadcast(true);
socket.setMulticastTTL(128); socket.setMulticastTTL(128);
socket.addMembership(udp.address); try{ socket.addMembership(udp.address); }catch(e){}
}); });
socket.on("listening", function(){ socket.on("listening", function(){

1175
lib/music.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
var Gun = require('../gun'), u; var Gun = require('../gun'), u;
Gun.serve = require('./serve'); Gun.serve = require('./serve');
//process.env.GUN_ENV = process.env.GUN_ENV || 'debug'; //process.env.GUN_ENV = process.env.GUN_ENV || 'debug';
console.LOG = true; // only temporarily, REVERT THIS IN FUTURE!
Gun.on('opt', function(root){ Gun.on('opt', function(root){
if(u === root.opt.super){ if(u === root.opt.super){
root.opt.super = true; root.opt.super = true;

View File

@ -66,7 +66,7 @@ Gun.log = function(a,b,c,d){
if('number' == typeof a && 'number' == typeof b && 'string' == typeof c){ if('number' == typeof a && 'number' == typeof b && 'string' == typeof c){
var tmp = (all[c] || (all[c] = [])); var tmp = (all[c] || (all[c] = []));
if(max < tmp.push([a,b])){ all[c] = [] } // reset if(max < tmp.push([a,b])){ all[c] = [] } // reset
return; //return;
} }
return log.apply(Gun, arguments); return log.apply(Gun, arguments);
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "gun", "name": "gun",
"version": "0.2019.1120", "version": "0.2019.1211",
"description": "A realtime, decentralized, offline-first, graph data synchronization engine.", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.",
"main": "index.js", "main": "index.js",
"browser": "gun.js", "browser": "gun.js",

4
sea.js
View File

@ -190,8 +190,8 @@
//console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); //console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed.");
//} //}
}catch(e){ }catch(e){
console.log("node-webcrypto-ossl and text-encoding may not be included by default, please add it to your package.json!"); console.log("text-encoding and @peculiar/webcrypto may not be included by default, please add it to your package.json!");
OSSL_WEBCRYPTO_OR_TEXT_ENCODING_NOT_INSTALLED; TEXT_ENCODING_OR_PECULIAR_WEBCRYPTO_NOT_INSTALLED;
}} }}
module.exports = api module.exports = api

View File

@ -3774,6 +3774,24 @@ describe('Gun', function(){
done(); done();
}) })
}); });
/*describe('talk to live server tests', function(){
this.timeout(1000 * 9);
it.only('Second once on undefined should call', function(done){ // this test is passing when it fails by hand?
var gun = Gun('https://gunjs.herokuapp.com/gun');
gun.get('~@O8H2BJa4pNfecWamWN7efd888Pg1@hackernoon').once(function(data){
console.log(1, data);
expect(data).to.not.be.ok();
setTimeout(function(){
gun.get('~@O8H2BJa4pNfecWamWN7efd888Pg1@hackernoon').once(function(data){
console.log(2, data);
expect(data).to.not.be.ok();
done();
});
}, 3000);
});
});
});*/
return; return;
it('Nested listener should be called', function(done){ it('Nested listener should be called', function(done){

View File

@ -2,13 +2,51 @@
This is the first in a series of basic networking correctness tests. 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.
Alice: [Bob]
Bob: [Carl]
Carl: [Bob]
Dave: [Carl]
Ed: [?]
100,000 browsers
1 relay peer
50,000 browsers on Bob
50,000 browsers on Carl
//var gun = Gun(['https://gunjs.herokuapp.com/gun', 'https://guntest.herokuapp.com/gun']);
pretend we have 3TB of data.
300K browsers.
suppose we have 3 nodejs peers that are shards
var superpeer1 = Gun(AXE({shard: 'a~m'}));
var superpeer2 = Gun(AXE({shard: 'n~r'}));
var superpeer3 = Gun(AXE({shard: 's~z'}));
300K browsers join a popular app and they have to do this
via the browser, so they all go to superpeer1.com
then 2/3 of them should get sharded to superpeer2 & superpeer3
first all connect to:
..s1-----s2--s3
./\.\.
b1.b2.b3
then be load balanced to:
..s1--s2--s3
./....|....\.
b1....b2....b3
*/ */
var config = { var config = {
IP: require('ip').address(), IP: require('ip').address(),
port: 8765, port: 8765,
servers: 2, servers: 3,
browsers: 2, browsers: 3,
route: { route: {
'/': __dirname + '/index.html', '/': __dirname + '/index.html',
'/gun.js': __dirname + '/../../gun.js', '/gun.js': __dirname + '/../../gun.js',
@ -35,11 +73,15 @@ manager.start({
}); });
var servers = clients.filter('Node.js'); var servers = clients.filter('Node.js');
var bob = servers.pluck(1); var s1 = servers.pluck(1);
var carl = servers.excluding(bob).pluck(1); var s2 = servers.excluding(s1).pluck(1);
var s3 = servers.excluding([s1,s2]).pluck(1);
var browsers = clients.excluding(servers); var browsers = clients.excluding(servers);
var alice = browsers.pluck(1); var b1 = browsers.pluck(1);
var dave = browsers.excluding(alice).pluck(1); var b2 = servers.excluding(b1).pluck(1);
var b3 = servers.excluding([b1,b2]).pluck(1);
describe("Put ACK", function(){ describe("Put ACK", function(){
//this.timeout(5 * 60 * 1000); //this.timeout(5 * 60 * 1000);
@ -65,12 +107,13 @@ describe("Put ACK", function(){
var peers = [], i = env.config.servers; var peers = [], i = env.config.servers;
while(i--){ while(i--){
var tmp = (env.config.port + (i + 1)); var tmp = (env.config.port + (i + 1));
if(port != tmp){ // ignore ourselves //if(port != tmp){ // ignore ourselves
peers.push('http://'+ env.config.IP + ':' + tmp + '/gun'); peers.push('http://'+ env.config.IP + ':' + tmp + '/gun');
} //}
} }
console.log(port, " connect to ", peers); console.log(port, " connect to ", peers);
var gun = Gun({file: env.i+'data', peers: peers, web: server}); var gun = Gun({file: env.i+'data', peers: peers, web: server, mob: 1});
global.gun = gun;
server.listen(port, function(){ server.listen(port, function(){
test.done(); test.done();
}); });
@ -85,13 +128,23 @@ describe("Put ACK", function(){
}); });
it("Browsers initialized gun!", function(){ it("Browsers initialized gun!", function(){
var tests = [], i = 1; var tests = [], i = 0;
browsers.each(function(client, id){ browsers.each(function(browser, id){
tests.push(client.run(function(test){ tests.push(browser.run(function(test){
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');
// SOME NEXT TEST HERE LOL
var mesh = gun.back('opt.mesh');
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.
console.log("we got a message!", msg);
try{ peer.wire.close(); }catch(e){ console.log("err:", e) }
}
console.log("connected to who superpeer(s)?", gun._.opt.peers);
window.gun = gun; window.gun = gun;
window.ref = gun.get('test'); window.ref = gun.get('test');
}, {i: i += 1, config: config})); }, {i: i += 1, config: config}));
@ -99,20 +152,16 @@ describe("Put ACK", function(){
return Promise.all(tests); return Promise.all(tests);
}); });
it("Alice", function(){ it("Got Load Balanced to Different Peer", function(){
return alice.run(function(test){ var tests = [], i = 0;
console.log("I AM ALICE"); browsers.each(function(browser, id){
//test.async(); tests.push(browser.run(function(test){
console.log(gun._.opt.peers);
});
});
it("Dave", function(){ console.log("...");
return dave.run(function(test){
console.log("I AM DAVE"); }, {i: i += 1, config: config}));
//test.async();
console.log(gun._.opt.peers);
}); });
return Promise.all(tests);
}); });
it("All finished!", function(done){ it("All finished!", function(done){

137
test/panic/bulkimport.js Normal file
View File

@ -0,0 +1,137 @@
/*
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,
puts: 1000,
route: {
'/': __dirname + '/index.html',
'/gun.js': __dirname + '/../../gun.js',
'/jquery.js': __dirname + '/../../examples/jquery.js'
}
}
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 carl = browsers.excluding(alice).pluck(1);
describe("Put ACK", 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 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.ref = gun.get('test');
}, {i: i += 1, config: config}));
});
return Promise.all(tests);
});
it("Puts", function(){
return alice.run(function(test){
console.log("I AM ALICE");
test.async();
var i = test.props.puts, d = 0;
while(i--){ go(i) }
function go(i){
ref.get(i).put({hello: 'world'}, function(ack){
if(ack.err){ put_failed }
if(++d !== test.props.puts){ return }
console.log("all success", d);
test.done();
});
}
}, {puts: config.puts});
});
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();
});
});
});