mirror of
https://github.com/amark/gun.git
synced 2025-06-03 20:56:43 +00:00
prep for stash
This commit is contained in:
parent
ba7c3e8bda
commit
2bbbe36e13
@ -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
52
gun.js
@ -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;
|
||||
}());
|
||||
}());
|
51
lib/axe.js
51
lib/axe.js
@ -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(){
|
||||
|
@ -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!
|
||||
|
54
lib/open.js
54
lib/open.js
@ -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;
|
@ -15,6 +15,7 @@
|
||||
require('./rfs');
|
||||
require('./rs3');
|
||||
require('./wire');
|
||||
|
||||
try{require('../sea');}catch(e){}
|
||||
try{require('../axe');}catch(e){}
|
||||
//require('./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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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];
|
||||
|
@ -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
240
test/panic/chat-user.js
Normal 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();
|
||||
});
|
||||
});
|
||||
})
|
Loading…
x
Reference in New Issue
Block a user