prep for stash

This commit is contained in:
Mark Nadal 2022-03-06 04:53:15 -08:00
parent ba7c3e8bda
commit 2bbbe36e13
11 changed files with 403 additions and 61 deletions

View File

@ -10,12 +10,12 @@
<p id="debug" style="position: fixed; bottom: 0px; color: white; height: 1em;"></p>
<script src="../jquery.js"></script>
<script src="../../../gun/gun.js"></script>
<script src="../../../gun/nts.js"></script>
<!-- script src="../../../gun/nts.js"></script -->
<script src="../../../gun/lib/webrtc.js"></script>
<script>
// Thanks to https://github.com/dmcinnes/HTML5-Asteroids
//var gun = Gun();
var gun = Gun(location.host? location.origin+'/gun' : 'http://localhost:8765/gun');
var gun = GUN(location.origin + '/gun');
var game = {gun: gun.get('example/game/space'), area: {}, ships: {}};
game.keys = {38: 'up', 37: 'left', 39: 'right', 40: 'down', 32: 'space'};
$(document).on('keydown', function(e){
@ -50,7 +50,7 @@
}
game.ship = function(d, el){
if(!d){ // spawn our ship
var id = Gun.text.random(1, 'abcdefghijklmno');
var id = String.random(1, 'abcdefghijklmno');
game.me = game.ships[id] = {data: d = {id: id, t: game.now}};
game.me.gun = game.gun.get('players').get(d.id).put(d);
return;
@ -101,7 +101,8 @@
s.ay = 0;
}
Gun.obj.map(game.ships, function(ship){
Object.keys(game.ships).forEach(function(key, ship){
ship = game.ships[key];
if(ship.gun){ return }
if(!ship.l){ return }
if(ship.x-50 <= s.x && s.x <= ship.x+50
@ -131,7 +132,7 @@
var d = s.data;
var dt = (now - d.t) || 0;
if(dt > 30 * 1000){
Gun.obj.del(game.ships, d.id);
delete game.ships[d.id];
s.$.remove();
return true;
}
@ -164,7 +165,8 @@
if(!me || me.boom){ return }
var keys = game.keys;
if(shoot || keys.up || keys.right || keys.left || keys.down){
var data = Gun.obj.to(me.data);
var data = {};
Object.keys(me.data).forEach(function(k){ data[k] = me.data[k] }); // 1 layer clone.
data.x = data.x / game.area.x;
data.y = data.y / game.area.y;
me.gun.put(data);
@ -181,7 +183,7 @@
game.resize();
game.ship();
game.gun.get('players').map().on(function(data, id){
data = Gun.obj.copy(data);
data = JSON.parse(JSON.stringify(data)); // clone object, this is bad perf tho.
data.x = data.x * game.area.x;
data.y = data.y * game.area.y;
data.id = data.id || id;
@ -195,7 +197,8 @@
now = game.now = Gun.state();
diff = now - last;
last = now;
Gun.obj.map(ships, function(ship){
Object.keys(ships).forEach(function(key, ship){
ship = ships[key];
if(!ship.frame){ return }
ship.frame(diff, now);
});
@ -209,7 +212,9 @@
gun.on('hi', function(peer){
console.log("hi!", peer);
if(peer.url){ return }
Gun.obj.map(gun.back('opt.peers'), function(peer){
var peers = gun.back('opt.peers');
Object.keys(peers).forEach(function(id, peer){
peer = peers[id];
if(!peer.url || !peer.wire){ return }
peer.wire._send = peer.wire.send;
peer.wire.send = send;

52
gun.js
View File

@ -274,6 +274,7 @@
return gun;
}
function universe(msg){
// TODO: BUG! msg.out = null being set!
//if(!F){ var eve = this; setTimeout(function(){ universe.call(eve, msg,1) },Math.random() * 100);return; } // ADD F TO PARAMS!
if(!msg){ return }
if(msg.out === universe){ this.to.next(msg); return }
@ -1335,6 +1336,11 @@
;USE(function(module){
USE('./shim');
var noop = function(){}
var parse = JSON.parseAsync || function(t,cb,r){ var u, d = +new Date; try{ cb(u, JSON.parse(t,r), json.sucks(+new Date - d)) }catch(e){ cb(e) } }
var json = JSON.stringifyAsync || function(v,cb,r,s){ var u, d = +new Date; try{ cb(u, JSON.stringify(v,r,s), json.sucks(+new Date - d)) }catch(e){ cb(e) } }
json.sucks = function(d){ if(d > 99){ Gun.log("Warning: JSON blocking CPU detected. Add `gun/lib/yson.js` to fix."); json.sucks = noop } }
function Mesh(root){
var mesh = function(){};
var opt = root.opt || {};
@ -1344,8 +1350,6 @@
opt.pack = opt.pack || (opt.max * 0.01 * 0.01);
opt.puff = opt.puff || 9; // IDEA: do a start/end benchmark, divide ops/result.
var puff = setTimeout.turn || setTimeout;
var parse = JSON.parseAsync || function(t,cb,r){ var u; try{ cb(u, JSON.parse(t,r)) }catch(e){ cb(e) } }
var json = JSON.stringifyAsync || function(v,cb,r,s){ var u; try{ cb(u, JSON.stringify(v,r,s)) }catch(e){ cb(e) } }
var dup = root.dup, dup_check = dup.check, dup_track = dup.track;
@ -1424,7 +1428,6 @@
mesh.leap = mesh.last = null; // warning! mesh.leap could be buggy.
}
var tomap = function(k,i,m){m(k,true)};
var noop = function(){};
hear.c = hear.d = 0;
;(function(){
@ -1726,13 +1729,18 @@
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]}};
}
var parse = JSON.parseAsync || function(t,cb,r){ var u; try{ cb(u, JSON.parse(t,r)) }catch(e){ cb(e) } }
var json = JSON.stringifyAsync || function(v,cb,r,s){ var u; try{ cb(u, JSON.stringify(v,r,s)) }catch(e){ cb(e) } }
Gun.on('create', function lg(root){
this.to.next(root);
var opt = root.opt, graph = root.graph, acks = [], disk, to;
var opt = root.opt, graph = root.graph, acks = [], disk, to, size, stop;
if(false === opt.localStorage){ return }
opt.prefix = opt.file || 'gun/';
try{ disk = lg[opt.prefix] = lg[opt.prefix] || JSON.parse(store.getItem(opt.prefix)) || {}; // TODO: Perf! This will block, should we care, since limited to 5MB anyways?
try{ disk = lg[opt.prefix] = lg[opt.prefix] || JSON.parse(to = store.getItem(opt.prefix)) || {}; // TODO: Perf! This will block, should we care, since limited to 5MB anyways?
}catch(e){ disk = lg[opt.prefix] = {}; }
size = (to||'').length;
root.on('get', function(msg){
this.to.next(msg);
@ -1750,24 +1758,30 @@
root.on('put', function(msg){
this.to.next(msg); // remember to call next middleware adapter
var put = msg.put, soul = put['#'], key = put['.'], tmp; // pull data off wire envelope
var put = msg.put, soul = put['#'], key = put['.'], id = msg['#'], tmp; // pull data off wire envelope
disk[soul] = Gun.state.ify(disk[soul], key, put['>'], put[':'], soul); // merge into disk object
if(!msg['@']){ acks.push(msg['#']) } // then ack any non-ack write. // TODO: use batch id.
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(to){ return }
//flush();return;
to = setTimeout(flush, opt.wait || 1); // that gets saved as a whole to disk every 1ms
to = setTimeout(flush, 9+(size / 333)); // 0.1MB = 0.3s, 5MB = 15s
});
function flush(){
if(!acks.length && ((setTimeout.turn||'').s||'').length){ setTimeout(flush,99); return; } // defer if "busy" && no saves.
var err, ack = acks; clearTimeout(to); to = false; acks = [];
try{store.setItem(opt.prefix, JSON.stringify(disk));
}catch(e){
Gun.log((err = (e || "localStorage failure")) + " Consider using GUN's IndexedDB plugin for RAD for more storage space, https://gun.eco/docs/RAD#install");
root.on('localStorage:error', {err: err, get: opt.prefix, put: disk});
}
if(!err && !Object.empty(opt.peers)){ return } // only ack if there are no peers. // Switch this to probabilistic mode
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.
});
json(disk, function(err, tmp){
try{!err && store.setItem(opt.prefix, tmp);
}catch(e){ err = stop = e || "localStorage failure" }
if(err){
Gun.log(err + " Consider using GUN's IndexedDB plugin for RAD for more storage space, https://gun.eco/docs/RAD#install");
root.on('localStorage:error', {err: err, get: opt.prefix, put: disk});
}
size = tmp.length;
if(!err && !Object.empty(opt.peers)){ return } // only ack if there are no peers. // Switch this to probabilistic mode
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.
},0,99);
})
}
});
@ -2226,4 +2240,4 @@
var obj = Type.obj, obj_is = obj.is, obj_del = obj.del, obj_has = obj.has, obj_empty = obj.empty, obj_put = obj.put, obj_map = obj.map, obj_copy = obj.copy;
var u;
Type.graph = Type.graph || Graph;
}());
}());

View File

@ -3,7 +3,7 @@
// and then rest of AXE logic (here) will be moved back to gun/axe.js
// but for now... I gotta rush this out!
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.
function start(root){
if(root.axe){ return }
@ -21,6 +21,7 @@ function start(root){
if(msg.put){ return } // relaying handled by HAM aggregation, no message forwarding!
fall(msg);
}
function GET(msg){
if(!msg){ return }
var via = (msg._||'').via, soul, has, tmp, ref;
@ -57,6 +58,7 @@ function start(root){
}, 3);
}
function fall(msg){ mesh.say(msg, opt.peers) }
root.on('in', function(msg){ var tmp;
if((tmp = msg['@']) && (tmp = dup.s[tmp])){
tmp.ack = (tmp.ack || 0) + 1; // count remote ACKs to GET. // TODO: If mismatch, should trigger next asks.
@ -99,6 +101,53 @@ function start(root){
mesh.say(msg, peer);
}
var state_ify = Gun.state.ify, state_is = Gun.state.is;
;(function(){ // THIS IS THE UP MODULE;
return; // unfinished.
axe.up = {};
root.on('hi', function(peer){
this.to.next(peer);
if(!peer.url){ return }
axe.up[peer.id] = peer;
});
root.on('bye', function(peer){ this.to.next(peer);
// this needs to be modified. TODO!
return;
});
}());
;(function(){ // THIS IS THE MOB MODULE;
return; // unfinished
/*
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 || 8000; // default to 80% of lot of free cloud deploy's socket limit which is 10K.
// handle rebalancing a mob of peers:
root.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?
var peers = Object.keys(axe.up);
if(!peers.length){ return }
mesh.say({dam: 'mob', mob: count, peers: peers}, peer);
//setTimeout(function(){ mesh.bye(peer) }, 9); // something with better perf? // UNCOMMENT WHEN WE ACTIVATE THIS FEATURE
});
root.on('bye', function(peer){
this.to.next(peer);
});
}());
}
;(function(){

View File

@ -35,6 +35,7 @@ Gun.on('create', function(root){
}
socket.send(buf, 0, buf.length, udp.port, udp.address, noop);
}
//opt.mesh.hi(udp.peer);
Gun.log.once('Multicast on', udp.peer.id);
return; // below code only needed for when WebSocket connections desired!

View File

@ -1,34 +1,36 @@
var Gun = (typeof window !== "undefined")? window.Gun : require('../gun');
Gun.chain.open = function(cb, opt, at){
opt = opt || {};
window.list = {};
Gun.chain.open = function(cb, opt, at){ // this is a recursive function!
opt = opt || {}; // init top level options.
opt.doc = opt.doc || {};
opt.ids = opt.ids || {};
opt.any = opt.any || cb;
opt.meta = opt.meta || false;
opt.ev = opt.ev || {off: function(){
Gun.obj.map(opt.ev.s, function(e){
if(e){ e.off() }
opt.eve = opt.eve || {off: function(){ // collect all recursive events to unsubscribe to if needed.
Object.keys(opt.eve.s).forEach(function(i,e){ // switch to CPU scheduled setTimeout.each?
if(e = opt.eve.s[i]){ e.off() }
});
opt.ev.s = {};
opt.eve.s = {};
}, s:{}}
return this.on(function(data, key, ctx, ev){
return this.on(function(data, key, ctx, eve){ // subscribe to 1 deeper layer of data!
if(opt.meta !== true){
delete ((data = Gun.obj.copy(data))||{})._;
//delete data._; // This should be safe now?
delete ((data = JSON.parse(JSON.stringify(data||'')))||{})._; // BAD PERFORMANCE BUT TRY ANYWAYS!
}
clearTimeout(opt.to);
opt.to = setTimeout(function(){
clearTimeout(opt.to); // do not trigger callback if bunch of changes...
opt.to = setTimeout(function(){ // but schedule the callback to fire soon!
if(!opt.any){ return }
opt.any.call(opt.at.$, opt.doc, opt.key, opt, opt.ev);
if(opt.off){
opt.ev.off();
opt.any.call(opt.at.$, opt.doc, opt.key, opt, opt.eve); // call it.
if(opt.off){ // check for unsubscribing.
opt.eve.off();
opt.any = null;
}
}, opt.wait || 1);
opt.at = opt.at || ctx;
opt.at = opt.at || ctx; // opt.at will always be the first context it finds.
opt.key = opt.key || key;
opt.ev.s[this._.id] = ev;
if(Gun.val.is(data)){
opt.eve.s[this._.id] = eve; // collect all the events together.
if(true === Gun.valid(data)){ // if primitive value...
if(!at){
opt.doc = data;
} else {
@ -36,21 +38,25 @@ Gun.chain.open = function(cb, opt, at){
}
return;
}
var tmp = this, id;
Gun.obj.map(data, function(val, key){
var doc = at || opt.doc;
if (!doc) {
var tmp = this; // else if a sub-object, CPU schedule loop over properties to do recursion.
setTimeout.each(Object.keys(data), function(key, val){
val = data[key];
var doc = at || opt.doc, id; // first pass this becomes the root of open, then at is passed below, and will be the parent for each sub-document/object.
if(!doc){ // if no "parent"
return;
}
if(!(id = Gun.val.link.is(val))){
if('string' !== typeof (id = Gun.valid(val))){ // if primitive...
doc[key] = val;
return;
}
if(opt.ids[id]){
doc[key] = opt.ids[id];
if(opt.ids[id]){ // if we've already seen this sub-object/document
list[id] = (list[id] || 0) + 1;
doc[key] = opt.ids[id]; // link to itself, our already in-memory one, not a new copy.
return;
}
tmp.get(key).open(opt.any, opt, opt.ids[id] = doc[key] = {});
// now open up the recursion of sub-documents!
tmp.get(key).open(opt.any, opt, opt.ids[id] = doc[key] = {}); // 3rd param is now where we are "at".
});
})
}
GUN.C = 0;

View File

@ -15,6 +15,7 @@
require('./rfs');
require('./rs3');
require('./wire');
try{require('../sea');}catch(e){}
try{require('../axe');}catch(e){}
//require('./file');

View File

@ -23,23 +23,24 @@ yson.parseAsync = function(text, done, revive, M){
}
if(w){
i = s.indexOf('"', i-1); c = s[i];
tmp = '\\' == s[i-1];
tmp = ('\\' == s[i-1] && '\\' != s[i-2]);
b = b || tmp;
if('"' == c && !tmp){
w = u;
tmp = ctx.s;
if(ctx.a){
tmp = s.slice(ctx.sl, i);
if(b || (1+tmp.indexOf('\\u'))){ tmp = JSON.parse('"'+tmp+'"') } // unicode :( handling
if(b || (1+tmp.indexOf('\\'))){ tmp = JSON.parse('"'+tmp+'"') } // escape + unicode :( handling
if(ctx.at instanceof Array){
ctx.at.push(ctx.s = tmp);
} else {
if(!ctx.at){ ctx.end = j = M; tmp = u }
(ctx.at||{})[ctx.s] = ctx.s = tmp;
}
ctx.s = u;
} else {
ctx.s = s.slice(ctx.sl, i);
if(b || (1+ctx.s.indexOf('\\u'))){ ctx.s = JSON.parse('"'+ctx.s+'"'); } // unicode :( handling
if(b || (1+ctx.s.indexOf('\\'))){ ctx.s = JSON.parse('"'+ctx.s+'"'); } // escape + unicode :( handling
}
ctx.a = b = u;
}

View File

@ -61,6 +61,7 @@ Gun.chain.once = function(cb, opt){ opt = opt || {}; // avoid rewriting
if(eve.stun){ return } if('' === one[id]){ return }
if(true === (tmp = Gun.valid(data))){ once(); return }
if('string' == typeof tmp){ return } // TODO: BUG? Will this always load?
clearTimeout((cat.one||'')[id]); // clear "not found" since they only get set on cat.
clearTimeout(one[id]); one[id] = setTimeout(once, opt.wait||99); // TODO: Bug? This doesn't handle plural chains.
function once(){
if(!at.has && !at.soul){ at = {put: data, get: key} } // handles non-core messages.

View File

@ -112,7 +112,8 @@ Gun.ask = require('./ask');
++ni; kl = null; pop(o);
}());
} Gun.on.put = put;
console.log("BEWARE: BETA VERSION OF NEW GUN! NOT ALL FEATURES FINISHED!"); // clock below, reconnect sync, SEA certify wire merge, User.auth taking multiple times, // msg put, put, say ack, hear loop...
// TODO: MARK!!! clock below, reconnect sync, SEA certify wire merge, User.auth taking multiple times, // msg put, put, say ack, hear loop...
// WASIS BUG! first .once( undef 2nd good. .off othe rpeople: .open
function ham(val, key, soul, state, msg){
var ctx = msg._||'', root = ctx.root, graph = root.graph, lot, tmp;
var vertex = graph[soul] || empty, was = state_is(vertex, key, 1), known = vertex[key];

View File

@ -70,7 +70,7 @@ describe('Gun', function(){
} );
*/
describe('YSON', function(){
describe.only('YSON', function(){
it('parse', function(){
//var json = require('fs').readFileSync('./radix.json').toString();
//var json = require('fs').readFileSync('./data.json').toString();
@ -78,15 +78,38 @@ describe('Gun', function(){
//var json = require('fs').readFileSync('./stats.json').toString();
//var json = require('fs').readFileSync('./video.json').toString();
});
it('backslash', function(done){
var o = {z:"test\"wow\\"};
JSON.stringifyAsync(o, function(err,t){
JSON.parseAsync(t, function(err,data){
expect(data).to.be.eql(o);
next();
})
});
function next(){
JSON.parseAsync('{"webRTCsdp":"v=0\r\no=-"}', function(err,data){
var o = {webRTCsdp: 'v=0\r\no=-'};
expect(data).to.be.eql(o);
JSON.stringifyAsync(o, function(err,t){
expect(JSON.parse(t)).to.be.eql(o);
expect(t).to.be(JSON.stringify(o));
expect(t).to.be('{"webRTCsdp":"v=0\\r\\no=-"}');
JSON.parseAsync(t, function(err,d){
expect(d).to.be.eql(o);
done();
})
});
})
}
});
it('stringify', function(done){
function Foo(){}; Foo.prototype.toJSON = function(){};
//var obj = {"what\"lol": {"a": 1, "b": true, "c": false, "d": null, "wow": [{"z": 9}, true, "hi", 3.3]}};
var obj = {"what": {"a": 1, "b": true, "c": false, "d": null, "wow": [{"z": 9}, true, "hi", 3.3]}};
var obj = [{x:"test 😎\\😄🔥",z:"test\\","what\"lol": {"0": 1.01},a:true,b: new Foo,c:3,y:"yes","get":{"#":"chat"},wow:undefined,foo:[1,function(){}, function(){}, 'go'],blah:{a:5,toJSON:function(){ return 9 }}}];
var obj = [{x:"test 😎\\😄🔥",z:"test\\","what\"lol": {"0": 1.01},a:true,b: new Foo,c:3,y:"yes","get":{"#":"chat"},wow:undefined,foo:[1,function(){}, function(){}, 'go'],blah:{a:5,toJSON:function(){ return 9 }}}, {webRTCsdp: "v=0\r\no=-"}, [[]], 10e9];
JSON.stringifyAsync(obj, function(err, text){
JSON.parseAsync(text, function(err, data){
expect(data).to.be.eql([{x:"test 😎\\😄🔥",z:"test\\","what\"lol": {"0": 1.01},a:true,c:3,y:"yes","get":{"#":"chat"},foo:[1,null,null,'go'],blah:9}]);
expect(data).to.be.eql([{x:"test 😎\\😄🔥",z:"test\\","what\"lol": {"0": 1.01},a:true,c:3,y:"yes","get":{"#":"chat"},foo:[1,null,null,'go'],blah:9}, {webRTCsdp: "v=0\r\no=-"}, [[]], 10e9]);
var obj = {a: [], b: [""], c: ["", 1], d: [1, ""], e: {"":[]}, "a\"b": {0: 1}, wow: {'': {cool: 1}}};obj.lol = {0: {sweet: 9}};obj.wat = {"": 'cool'};obj.oh = {phew: {}, "": {}};
JSON.stringifyAsync(obj, function(err, text2){
JSON.parseAsync(text2, function(err, data){

240
test/panic/chat-user.js Normal file
View File

@ -0,0 +1,240 @@
var config = {
IP: require('ip').address(),
port: 8765,
servers: 1,
browsers: 2, //3,
each: 50000,//100000,
size: 1,
wait: 1,
route: {
'/': __dirname + '/index.html',
'/gun.js': __dirname + '/../../gun.js',
'/sea.js': __dirname + '/../../sea.js',
'/jquery.js': __dirname + '/../../examples/jquery.js'
}
}
/*
Assume we have 3 peers in a star topology,
..B..
./.\.
A...C
And they share a chat room with 10K messages.
A -> GET chat -> B (cache miss) -> C
C hosts the data and streams it back
C -> PUT chat -> B (relay) -> A got.
Using the WebRTC module, C <-> A directly, no need for a relay!
But we're wanting to test the performance of the whole network.
*/
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){ // Static server
config.route[req.url] && require('fs').createReadStream(config.route[req.url]).pipe(res);
}).listen(config.port); // Start panic server.
// In order to tell the clients what to do,
// We need a way to reference all of them.
var clients = panic.clients;
// Some of the clients may be NodeJS servers on different machines.
// PANIC manager is a nifty tool that lets us remotely spawn them.
var manager = require('panic-manager')();
manager.start({
clients: Array(config.servers).fill().map(function(u, i){ // Create a bunch of servers.
return {
type: 'node',
port: config.port + (i + 1) // They'll need unique ports to start their servers on, if we run the test on 1 machine.
}
}),
panic: 'http://' + config.IP + ':' + config.port // Auto-connect to our panic server.
});
// Now lets divide our clients into "servers" and "browsers".
var servers = clients.filter('Node.js');
var browsers = clients.excluding(servers);
var alice = browsers.pluck(1);
var carl = browsers.excluding(alice).pluck(1);
describe("Load test "+ config.browsers +" browser(s) across "+ config.servers +" server(s)!", function(){
this.timeout(50 * 60 * 1000);
console.log('start', config.pair);
// We'll have to manually launch the browsers,
// So lets up the timeout so we have time to do that.
it("Generate keypair", async function(){
return config.pair = await require('gun/sea').pair();
});
it("Servers have joined!", function(){
// Alright, lets wait until enough gun server peers are connected.
return servers.atLeast(config.servers);
});
it("GUN has spawned!", function(){
// Once they are, we need to actually spin up the gun server.
var tests = [], i = 0;
servers.each(function(client){
// for each server peer, tell it to run this code:
tests.push(client.run(function(test){
// NOTE: Despite the fact this LOOKS like we're in a closure...
// it is not! This code is actually getting run
// in a DIFFERENT machine or process!
var env = test.props;
// As a result, we have to manually pass it scope.
test.async();
// Clean up from previous test.
try{ require('fs').unlinkSync(env.i+'data.json') }catch(e){}
var server = require('http').createServer(function(req, res){
res.end("I am "+ env.i +"!");
});
// Launch the server and start gun!
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.") }
// Attach the server to gun.
var gun = Gun({file: env.i+'data', web: server, axe: false, localStorage: false, radisk: false});
server.listen(env.config.port + env.i, function(){
// This server peer is now done with the test!
// It has successfully launched.
test.done();
});
}, {i: i += 1, config: config}));
});
// NOW, this is very important:
// Do not proceed to the next test until
// every single server (in different machines/processes)
// have ALL successfully launched.
return Promise.all(tests);
});
it(config.browsers +" browser(s) have joined!", function(){
require('./util/open').web(config.browsers, "http://"+ ("localhost"||config.IP) +":"+ config.port); //console.log("PLEASE OPEN http://"+ config.IP +":"+ config.port +" IN "+ config.browsers +" BROWSER(S)!");
return browsers.atLeast(config.browsers);
});
it("Browsers load SEA!", function(){
//return carl.run(function(test){
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('sea.js', function(){
test.done();
});
}, {i: i += 1, config: config}));
});
return Promise.all(tests);
//}, config);
});
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');
var gun = Gun({localStorage: false, radisk: false, peers: 'http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun'});
window.gun = gun;
//window.ref = gun.user(env.config.pair.pub);
window.ref = gun.get('~'+env.config.pair.pub);
}, {i: i += 1, config: config}));
});
return Promise.all(tests);
});
it("Carl Create Chats", function(){
return carl.run(function(test){
console.log("I AM CARL");
$('body').append("<div>CPU turns stacked: <u></u> <button onclick='this.innerText = Math.random();'>Can you click me?</button><input id='msg' style='width:100%;'><b></b></div>");
test.async();
var env = test.props;
var dam = gun.back('opt.mesh');
dam.old = dam.say;
dam.say = function(){};
var rand = String.random || Gun.text.random;
var i = test.props.each, chat = {}, S = Gun.state();
var tmp = "generating " + i + " records..."; console.log(tmp); $('b').text(tmp);
var big = rand(test.props.size || 1); //1000 * 10);
function gen(){
var j = 99;
$('b').text(i + ' left to generate...');
var data = rand(100);
while(--j && i){ --i;
ref.get(i).put(rand(100) + data + big, function(ack){ console.log('err?', ack) });
//Gun.state.ify(chat, i/*+'-'+rand(9)*/, S, rand(100) + data + big, '~'+test.config.pair.pub);
}
if(i === 0){
ref.get('1').once(function(x){
//gun._.graph.chat = chat;
dam.say = dam.old;
test.done();
//console.log("Done!", x);
$('b').text('');
})
return;
}
setTimeout.turn(gen);
}
gun.on('auth', function(ack){ setTimeout(gen,9) });
window.ref = gun.user().auth(env.pair);
//window.chat = chat;
//console.log(JSON.stringify(chat,null,2));
setInterval(function(){ $('u').text(setTimeout.turn.s.length) },1000);
}, config);
});
it("Alice Asks for Chat", function(){
return alice.run(function(test){
console.log("I AM ALICE");
test.async();
var i = 0, t = test.props.each, tmp;
$('body').append("<div><i></i> / "+t+", seconds to first reply: <span></span>, CPU turns stacked: <u></u> <button onclick='this.innerText = Math.random();'>Can you click me?</button><input id='msg' style='width:100%;'><b></b></div>");
var $msg = $('#msg'), $i = $('i');
var V, I, S = +new Date, SS = S, tmp;
ref.map().once(function(v,k){
S && console.log('first:', $('span').text(tmp = (+new Date - S)/1000) && tmp) || (S = null);
if(!v){ no_data }
V = v;
I = ++i;
//console.log(i, "chat:",k,v);
if(i === t){
console.log(tmp = "seconds from start to end: " + (tmp = ((+new Date - SS)/1000)) + ", roughly " + (t/tmp).toFixed(2) + "ops/sec.");
$('b').text(tmp);
setTimeout(function(){ test.done() },100);
}
});
window.requestAnimationFrame = window.requestAnimationFrame || setTimeout;
window.requestAnimationFrame(function frame(){
window.requestAnimationFrame(frame, 16);
$msg.val(V);
$i.text(I);
}, 16);
setInterval(function(){ $('u').text(setTimeout.turn.s.length) },1000);
}, config);
});
after("Everything shut down.", function(){
// which is to shut down all the browsers.
require('./util/open').cleanup() || browsers.run(function(){
setTimeout(function(){
location.reload();
}, 15 * 1000);
});
// And shut down all the servers.
return servers.run(function(){
process.exit();
});
});
})