Before adding queue to on

This commit is contained in:
Mark Nadal 2016-06-08 15:07:04 -07:00
parent ac761bf674
commit 752fe41a19
10 changed files with 343 additions and 79 deletions

159
gun.js
View File

@ -176,7 +176,8 @@
function noop(){}; function noop(){};
function Event(tag, arg, at, as, skip){ function Event(tag, arg, at, as, skip){
var ctx = this, ons = ctx.ons || (ctx.ons = {}), on = ons[tag] || (ons[tag] = {s: []}), act, mem; var ctx = this, ons = ctx.ons || (ctx.ons = {}), on = ons[tag] || (ons[tag] = {s: []}), act, mem;
/*if(!arg && 1 === arguments.length){ //typeof console !== 'undefined' && console.debug(102, 'on', tag, arg, 'ons', ctx, ons);
/*if(!arg && 1 === arguments.length){ // Performance drops significantly even though `arguments.length` should be okay to use.
return on.s; return on.s;
}*/ }*/
if(arg instanceof Function){ if(arg instanceof Function){
@ -188,7 +189,7 @@
return; return;
}*/ }*/
} }
return; return act;
} }
if(emit){ emit(tag, arg, on, ctx) } if(emit){ emit(tag, arg, on, ctx) }
on.arg = arg; on.arg = arg;
@ -226,9 +227,9 @@
} }
} }
on.s = still; on.s = still;
if(0 === still.length){ //if(0 === still.length){ // TODO: BUG! If we clean up the events themselves when no longer needed by deleting this code, it causes some tests to fail.
delete ons[tag]; // delete ons[tag];
} //}
} }
if(!gap && at && at instanceof Function){ if(!gap && at && at instanceof Function){
at.call(as, arg); at.call(as, arg);
@ -237,7 +238,9 @@
} }
exports.on = Event; exports.on = Event;
}(Util, function add(tag, act, on, ctx){ // Gun specific extensions }(Util, function add(tag, act, on, ctx){ // Gun specific extensions
var mem = on.mem, at; var mem = on.mem;
typeof console !== 'undefined' && console.debug(9, 'ON', tag, mem);
typeof console !== 'undefined' && console.debug(10, 'SO! The problem is that subsequent event listeners trigger lazy again, but the should queue for the results of the one already trying to finish or else you will get wrong results.');
if(mem){ if(mem){
if(mem instanceof Array){ if(mem instanceof Array){
act.fn.apply(act.at, mem.concat(act)); act.fn.apply(act.at, mem.concat(act));
@ -246,11 +249,10 @@
} }
return; return;
} }
at = act.at? act.at.gun? act.at : ctx : ctx; if(!ctx.lazy){ return }
if(!at.lex || !at.lex.soul){ return } // TODO: What about lex cursors? var at = act.at? act.at.gun? act.at : ctx : ctx;
console.debug(16, 'on', tag, mem); if(!at.gun){ return }
console.debug(3, 'on', tag, mem); ctx.lazy(at, tag);
Gun.get(at);
//if(on.mem){ add(tag, act, on, ctx) } // for synchronous async actions. //if(on.mem){ add(tag, act, on, ctx) } // for synchronous async actions.
}, function(tag, arg, on, at){ }, function(tag, arg, on, at){
on.mem = arg; on.mem = arg;
@ -606,8 +608,7 @@
is_graph(at.graph, map, null, at); is_graph(at.graph, map, null, at);
}); });
function map(node, soul){ function map(node, soul){
console.debug(12, 'put to get', soul); //Gun.get.got.call(this, null, node);
console.debug(9, 'put to get', soul);
Gun.get.got.call(this.gun.__.gun.get(soul)._, null, node); Gun.get.got.call(this.gun.__.gun.get(soul)._, null, node);
} }
}()); }());
@ -626,20 +627,21 @@
stream: cb stream: cb
} }
} }
console.debug(4, 'GET', at); console.debug(5, 'GET', at.lex);
Gun.on('get', at); // TODO: What is the cleanest way to reply if there is no responses, without assuming drivers do reply or not? Gun.on('get', at); // TODO: What is the cleanest way to reply if there is no responses, without assuming drivers do reply or not?
return at.gun; return at.gun;
} }
Gun.get.got = got; Gun.get.got = got;
function got(err, node){ function got(err, node){ var at = this;
if(err){ Gun.log(err) } if(err){ Gun.log(err) }
console.debug(105, 'GOT', err, node); if(!at.stream){ var soul;
console.debug(5, 'GOT', err, node); if(!node && !at.lex.soul){ return }
Gun.on('stream', Gun.obj.to(this, {err: err, change: node}), stream); at = at.gun.__.gun.get(is_node_soul(node) || at.lex.soul)._;
}
Gun.on('stream', Gun.obj.to(at, {err: err, change: node}), stream);
} }
function stream(at){ function stream(at){
if(!at.stream){ console.log("WARNING! No at.get", at); } if(!at.stream){ console.log("WARNING! No at.stream", at); }
console.debug(6, 'STREAM', at);
at.stream(at.err, at.change); at.stream(at.err, at.change);
} }
}()); }());
@ -649,6 +651,7 @@
if(opt.force){ return } if(opt.force){ return }
var lex = at.lex, gun = at.gun, graph = gun.__.graph, node = graph[lex.soul]; var lex = at.lex, gun = at.gun, graph = gun.__.graph, node = graph[lex.soul];
if(opt.memory || node){ return at.cb(null, node), ev.stun() } if(opt.memory || node){ return at.cb(null, node), ev.stun() }
console.debug(6, 'not in memory');
}); });
Gun.on('stream', function(at, ev){ var node; Gun.on('stream', function(at, ev){ var node;
@ -667,8 +670,8 @@
if(get && get[soul] && !get[soul]._.node){ if(get && get[soul] && !get[soul]._.node){
get[soul]._.node = __.graph[soul]; get[soul]._.node = __.graph[soul];
} }
}); });*/
*/
Gun.on('stream', function(at){ Gun.on('stream', function(at){
var lex = at.lex, soul = lex.soul, field = lex.field; var lex = at.lex, soul = lex.soul, field = lex.field;
var gun = at.gun, graph = gun.__.graph, node = graph[soul], u; var gun = at.gun, graph = gun.__.graph, node = graph[soul], u;
@ -840,12 +843,13 @@
put.any = cb; put.any = cb;
put.data = data; put.data = data;
put.state = (opt.state || opts.state)(); put.state = (opt.state || opts.state)();
console.debug(3, 'put put', data);
at.on('chain', link, at); // TODO: ONE? at.on('chain', link, at); // TODO: ONE?
return gun; return gun;
}; };
function link(cat, ev){ ev.off(); // TODO: BUG! function link(cat, ev){ ev.off(); // TODO: BUG!
console.log(8, 'putting', cat);
var at = this, put = at.put, data, cb; var at = this, put = at.put, data, cb;
console.debug(7, 'putting', at, cat.gun === at.gun, cat);
if(cat.err){ return } if(cat.err){ return }
if(!cat.node && (put.opt.init || cat.gun.__.opt.init)){ return } if(!cat.node && (put.opt.init || cat.gun.__.opt.init)){ return }
// TODO: BUG! `at` doesn't have correct backwards data! // TODO: BUG! `at` doesn't have correct backwards data!
@ -858,9 +862,9 @@
ev.stun(); ev.stun();
//put.resume = ev.stun(put.resume); //put.resume = ev.stun(put.resume);
Gun.ify(data, end, { Gun.ify(data, end, {
node: function(env, cb){ var eat = env.at; node: function(env, cb){ var eat = env.at, tmp;
if(1 === eat.path.length && cat.node){ if(1 === eat.path.length && cat.node){
eat.soul = is_rel(cat.node[eat.path[0]]); // TODO: BUG! Need to handle paths that aren't loaded yet. eat.soul = (tmp = is_rel(at.value))? tmp : is_rel(cat.node[eat.path[0]]); // TODO: BUG! Need to handle paths that aren't loaded yet.
} }
cb(env, eat); cb(env, eat);
}, value: function(env){ var eat = env.at; }, value: function(env){ var eat = env.at;
@ -892,11 +896,9 @@
Gun.on('normalize', Gun.obj.to(at, {err: err, graph: env.graph, env: env}), wire); Gun.on('normalize', Gun.obj.to(at, {err: err, graph: env.graph, env: env}), wire);
} }
function wire(at){ function wire(at){
console.debug(8, 'pat', at);
Gun.put(Gun.obj.to(at, {cb: ack})); Gun.put(Gun.obj.to(at, {cb: ack}));
} }
function ack(err, ok){ var at = this, cb; function ack(err, ok){ var at = this, cb;
console.debug(14, 'ack', err, ok);
if((cb = at.put.any) && cb instanceof Function){ if((cb = at.put.any) && cb instanceof Function){
cb.call(at.gun, err, ok); cb.call(at.gun, err, ok);
} }
@ -925,16 +927,23 @@
} }
Gun.on('chain', function(cat, e){ Gun.on('chain', function(cat, e){
if(!is_node_soul(cat.node, 'key')){ return } if(!is_node_soul(cat.node, 'key')){ return }
var resume = e.stun(1), node = cat.node, pseudo = cat.gun._.pseudo || (cat.gun._.pseudo = cat.gun._.node = is_node_ify({}, is_node_soul(node))); var resume = e.stun(1), node = cat.change, field = cat.lex.field, pseudo = cat.gun._.pseudo || (cat.gun._.pseudo = cat.gun._.node = is_node_ify({}, is_node_soul(cat.node)));
pseudo._.key = 'pseudo'; pseudo._.key = 'pseudo';
cat.seen = cat.seen || {}; // TODO: There is a better way. cat.seen = cat.seen || {}; // TODO: There is a better way.
'hello/world' === is_node_soul(node) && console.log("scan", node);
is_node(node, function(n, f){ // TODO: PERF! BAD! Filter out items we've already seen. is_node(node, function(n, f){ // TODO: PERF! BAD! Filter out items we've already seen.
if(cat.seen[f]){ return } cat.seen[f] = true; // TODO: There is a better way. if(cat.seen[f]){ return } cat.seen[f] = true; // TODO: There is a better way.
cat.gun.get(Gun.obj.to(cat.lex, {soul: f}), on); //cat.gun.__.gun.get(Gun.obj.to(cat.lex, {soul: f}), on);
function on(err, node){ if(field){
cat.gun.__.gun.get(f).path(field, on);
} else {
cat.gun.__.gun.get(f, on);
}
function on(err, node, field, at){
if(!node){ return } if(!node){ return }
HAM_node(pseudo, node); HAM_node(pseudo, node);
cat.node = pseudo; cat.node = pseudo;
cat.change = at.change;
resume(); resume();
} }
}); });
@ -966,17 +975,10 @@
if(!opt || !opt.path){ var back = this.__.gun; } // TODO: CHANGING API! Remove this line! if(!opt || !opt.path){ var back = this.__.gun; } // TODO: CHANGING API! Remove this line!
var gun, back = back || this; var gun, back = back || this;
var get = back._.get || (back._.get = {}), tmp; var get = back._.get || (back._.get = {}), tmp;
console.debug(2, 'get', lex);
if(typeof lex === 'string'){ if(typeof lex === 'string'){
if(!(gun = get[lex])){ if(!(gun = get[lex])){
gun = cache(get, lex, back); gun = cache(get, lex, back);
console.debug(15, 'get', lex, get, 'and the', gun);
console.debug(2, 'get', lex);
if((tmp = gun._.lex).field){
/*if(!back._.ons.chain || !back._.ons.chain.s.length){ // TODO: CLEAN UP! // TODO: ONE?
back._.on('chain', link, gun._);
}*/
back._.on('field:' + tmp.field, field, gun._); // TODO: ONE?
}
} }
} else } else
if(!lex && 0 != lex){ // TODO: BUG!? if(!lex && 0 != lex){ // TODO: BUG!?
@ -990,7 +992,7 @@
if(tmp = lex.soul){ if(tmp = lex.soul){
if(lex.field){ if(lex.field){
gun = back.chain(); gun = back.chain();
gun._.stream = cb; //gun._.stream = cb;
gun._.lex = lex; gun._.lex = lex;
Gun.get(gun._); Gun.get(gun._);
return gun; return gun;
@ -1000,59 +1002,82 @@
} }
} else } else
if(tmp = lex[_soul]){ if(tmp = lex[_soul]){
if(lex[_field]){
return back.get({soul: tmp, field: lex[_field]}, cb, opt);
}
if(!(gun = get[tmp])){ if(!(gun = get[tmp])){
gun = cache(get, tmp, back); gun = cache(get, tmp, back);
} }
if(tmp = lex[_field]){
return gun.path(tmp, cb, opt);
}
} }
console.debug(7, 'get', lex);
if(cb && cb instanceof Function){ if(cb && cb instanceof Function){
gun._.on('any', pop(cb), gun); // TODO: Perf! Batch! // TODO: API CHANGE? Having to use pop is annoying. Should we support NodeJS style callbacks anymore? //gun._.on('any', pop(cb), gun); // TODO: Perf! Batch! // TODO: API CHANGE? Having to use pop is annoying. Should we support NodeJS style callbacks anymore?
console.debug(8, 'getting');
gun._.on('any', cb, gun); // TODO: Perf! Batch! // TODO: API CHANGE? Having to use pop is annoying. Should we support NodeJS style callbacks anymore?
} }
return gun; return gun;
} }
function cache(get, key, back){ function cache(get, key, back){
var gun = get[key] = back.chain(), at = gun._; var gun = get[key] = back.chain(), at = gun._;
at.stream = stream; at.lazy = lazy;
if(!back.back){ if(!back.back){
at.stream = stream;
at.lex.soul = key; at.lex.soul = key;
} else { } else {
var lex = at.lex, flex = back._.lex; var lex = at.lex, cat = back._, flex = cat.lex;
lex.field = key; lex.field = key;
if(!flex.field && flex.soul){ if(!flex.field && flex.soul){
lex.soul = flex.soul; lex.soul = flex.soul;
} }
back._.on('field:' + key, field, at);
} }
return gun; return gun;
} }
function stream(err, node){ function lazy(at){ var cat = this;
console.debug(10, 'stream', err, node); if(at.path && at.path.wait){ return } // means we're being lazy again.
Gun.on('chain', this); console.debug(4, 'lazy', at);
//Gun.on('chain', this, link, this); var lex = at.lex;
} if(!lex.soul){
Gun.on('chain', link); if(!(lex.soul = is_rel(cat.value))){
function link(cat, ev){ var at = cat.gun._, u; return; // TODO: BUG! Handle async case.
var err = cat.err, node = cat.node, cex = cat.lex, lex = at.lex, field = lex.field, rel, val;
console.debug(13, 'link', at, cat);
console.debug(11, 'link', at, cat);
if(lex !== cex && lex.field && cex.field){
if(obj_has(node, cex.field) && (rel = is_rel(val = node[cex.field]))){
return Gun.get(Gun.obj.to(at, {lex: {soul: rel, field: lex.field}}));
} }
} }
console.debug(17, 'link', at, cat); Gun.get(at);
at.on('any', [err, (field && node)? node[field] : node, field, cat]); // TODO: Revisit! };
function stream(err, node){
//Gun.on('chain', this);
Gun.on('chain', this, link, this);
}
//Gun.on('chain', link);
function link(cat, ev){ var at = this, u;
//at.value = cat.value = cat.node;
var err = cat.err, node = cat.node, cex = cat.lex, lex = at.lex, field = lex.field, rel, val;
if(at.path && is_node_soul(node) === at.path.rel){ field = u }
at.on('any', [err, (field && node)? node[field] : node, lex.field, cat]) // TODO: Revisit!
if(err){ at.on('err', err) } if(err){ at.on('err', err) }
if(node){ at.on('ok', [(field && node)? node[field] : node, field, cat]) } // TODO: Revisit! if(node){ at.on('ok', [(field && node)? node[field] : node, lex.field, cat]) } // TODO: Revisit!
is_node(at.change, map, {cat: cat, at: at});
at.on('chain', cat); at.on('chain', cat);
if(at.path && field){ return }
is_node(cat.change, map, {cat: cat, at: at}) || obj_map(at.get, map, {cat: cat, at: at}); // TODO: Cleaner way? Necessary to pass error/nots down the chain for implicit puts.
} }
function map(val, field){ function map(val, field){
this.cat.on('field:' + field, this.cat); this.at.on('field:' + field, this.cat);
} }
function field(cat, ev){ var at = this; function field(cat, ev){ var at = this;
at.on('chain', Gun.obj.to(at, {err: cat.err, change: cat.change})); var node = cat.node, lex, field, rel;
if(!at.path){ at.path = {} }
if(!node){ return link.call(at, cat, ev) } // TODO: Errors and nots?
(lex = at.lex).soul = is_node_soul(node);
if(at.value === node[field = lex.field] && obj_has(at, 'value')){ return }
if(at.path.ev){ at.path.ev.off() }
at.value = node[field];
if(rel = at.path.rel = is_rel(at.value)){
at.path.wait = true;
at.path.ev = at.gun.__.gun.get(rel)._.on('chain', link, at);
at.path.wait = false;
return;
}
link.call(at, cat, ev);
} }
}()); }());
Gun.chain.path = function(field, cb, opt){ Gun.chain.path = function(field, cb, opt){
@ -1160,10 +1185,12 @@
;(function(){ ;(function(){
function get(err, data, at){ function get(err, data, at){
if(!data && !Gun.obj.empty(at.opt.peers)){ return } // let the peers handle no data. if(!data && !Gun.obj.empty(at.opt.peers)){ return } // let the peers handle no data.
console.log("ouch");
at.cb(err, data); // node at.cb(err, data); // node
} }
Gun.on('get', function(at){ Gun.on('get', function(at){
var opt = at.opt, lex = at.lex; var opt = at.opt, lex = at.lex;
console.debug(7, 'get ASYNC');
Tab.store.get((opt.prefix || '') + lex.soul, get, at); Tab.store.get((opt.prefix || '') + lex.soul, get, at);
}); });
}()); }());
@ -1303,10 +1330,10 @@
;(function(exports){ var u; ;(function(exports){ var u;
function s(){} function s(){}
s.put = function(key, val, cb){ try{ store.setItem(key, Gun.text.ify(val));if(cb)cb(null) }catch(e){if(cb)cb(e)} } s.put = function(key, val, cb){ try{ store.setItem(key, Gun.text.ify(val));if(cb)cb(null) }catch(e){if(cb)cb(e)} }
s.get = function(key, cb, t){ //setTimeout(function(){ s.get = function(key, cb, t){ setTimeout(function(){
try{ cb(null, Gun.obj.ify(store.getItem(key) || null), t); try{ cb(null, Gun.obj.ify(store.getItem(key) || null), t);
}catch(e){ cb(e,u,t)} }catch(e){ cb(e,u,t)}
}//,1) } },1) }
s.del = function(key){ return store.removeItem(key) } s.del = function(key){ return store.removeItem(key) }
var store = window.localStorage || {setItem: function(){}, removeItem: function(){}, getItem: function(){}}; var store = window.localStorage || {setItem: function(){}, removeItem: function(){}, getItem: function(){}};
exports.store = s; exports.store = s;

View File

@ -49,7 +49,7 @@
}, },
"devDependencies": { "devDependencies": {
"mocha": "~>1.9.0", "mocha": "~>1.9.0",
"panic-server": "~>0.2.4", "panic-server": "~>0.3.0",
"selenium-webdriver": "~>2.53.2" "selenium-webdriver": "~>2.53.2"
} }
} }

View File

@ -1352,9 +1352,11 @@ describe('Gun', function(){
}); });
}); });
it('put node with soul get soul', function(done){ it.only('put node with soul get soul', function(done){
Gun.log.debug=1;console.log("--------------------------");
gun.put({_: {'#': 'foo'}, hello: 'world'}) gun.put({_: {'#': 'foo'}, hello: 'world'})
.get({'#': 'foo'}, function(err, node){ .get({'#': 'foo'}, function(err, node){
console.log("huh?", err, node);
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
expect(Gun.is.node.soul(node)).to.be('foo'); expect(Gun.is.node.soul(node)).to.be('foo');
expect(node.hello).to.be('world'); expect(node.hello).to.be('world');
@ -1583,15 +1585,14 @@ describe('Gun', function(){
it('put node path path', function(done){ it('put node path path', function(done){
var gun = Gun(); var gun = Gun();
Gun.log.debug=1;console.log("----------------------------------"); var g = gun.put({hello: {little: 'world'}}).path('hello').path('little', function(err, val, field){
gun.put({hello: {little: 'world'}}).path('hello').path('little', function(err, val, field){
if(done.end){ return } // it is okay for path's callback to be called multiple times. if(done.end){ return } // it is okay for path's callback to be called multiple times.
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
expect(field).to.be('little'); expect(field).to.be('little');
expect(val).to.be('world'); expect(val).to.be('world');
done(); done.end = true; done(); done.end = true;
}); });
});return; });
it('put node path rel', function(done){ it('put node path rel', function(done){
gun.put({foo: {bar: 'lol'}}).path('foo', function(err, val, field){ gun.put({foo: {bar: 'lol'}}).path('foo', function(err, val, field){
@ -1617,8 +1618,9 @@ describe('Gun', function(){
var gun = Gun(); var gun = Gun();
gun.put({_:{'#': 'soul/field'}, hi: 'lol', foo: 'bar'});//.key('key/field'); gun.put({_:{'#': 'soul/field'}, hi: 'lol', foo: 'bar'});//.key('key/field');
gun.get({'#': 'soul/field', '.': 'hi'}, function(err, val){ gun.get({'#': 'soul/field', '.': 'hi'}, function(err, val){
expect(val.hi).to.be('lol'); //expect(val.hi).to.be('lol'); // TODO: REVISE API?
expect(Gun.obj.has(val,'foo')).to.not.be.ok(); expect(val).to.be('lol');
//expect(Gun.obj.has(val,'foo')).to.not.be.ok();
done(); done();
}) })
}); });
@ -1767,7 +1769,7 @@ describe('Gun', function(){
expect(val).to.be('are'); expect(val).to.be('are');
expect(field).to.be('you'); expect(field).to.be('you');
done(); done();
}) });
}); });
it('get node path put object merge isolated', function(done){ it('get node path put object merge isolated', function(done){
@ -1778,6 +1780,8 @@ describe('Gun', function(){
var puthi = get.put({hi: 'you'}); var puthi = get.put({hi: 'you'});
puthi.on(function(node){ puthi.on(function(node){
if(done.hi){ return } if(done.hi){ return }
//console.log(1, node);
expect(node.hello).to.be('key');
expect(node.hi).to.be('you'); expect(node.hi).to.be('you');
done.hi = 1; done.hi = 1;
}); });
@ -1787,8 +1791,11 @@ describe('Gun', function(){
path2._.id = 'path2'; path2._.id = 'path2';
var putyay = path2.put({yay: "value"}); var putyay = path2.put({yay: "value"});
putyay.on(function(node, field){ putyay.on(function(node, field){
if(done.yay){ return }
//console.log(2, field, node);
expect(field).to.be('hi'); expect(field).to.be('hi');
expect(node.yay).to.be('value'); expect(node.yay).to.be('value');
done.yay = true;
}); });
setTimeout(function(){ setTimeout(function(){
var get3 = gun.get('hello/key/iso'); var get3 = gun.get('hello/key/iso');
@ -1796,9 +1803,10 @@ describe('Gun', function(){
path3._.id = 'path3'; path3._.id = 'path3';
var puthappy = path3.put({happy: "faces"}); var puthappy = path3.put({happy: "faces"});
puthappy.on(function(node, field){ puthappy.on(function(node, field){
//console.log(3, field, node);
expect(field).to.be('hi'); expect(field).to.be('hi');
expect(node.yay).to.be('value');
expect(node.happy).to.be('faces'); expect(node.happy).to.be('faces');
expect(node.yay).to.be('value');
setTimeout(function(){ setTimeout(function(){
done(); done();
},200); },200);
@ -1931,6 +1939,7 @@ describe('Gun', function(){
}); });
it('get put path', function(done){ it('get put path', function(done){
Gun.log.debug=1;console.log("-------------------------");
gun.get('hello/world').put({hello: 'Mark'}).path('hello').val(function(val, field){ gun.get('hello/world').put({hello: 'Mark'}).path('hello').val(function(val, field){
console.log("WAT?", field, val); console.log("WAT?", field, val);
expect(val).to.be('Mark'); expect(val).to.be('Mark');

View File

@ -1,3 +1,5 @@
require('./holy/grail');
describe('PANIC!', function(){ describe('PANIC!', function(){
this.timeout(1000 * 100); this.timeout(1000 * 100);
@ -35,7 +37,7 @@ describe('PANIC!', function(){
function min(n, done, list){ function min(n, done, list){
list = list || clients; list = list || clients;
function ready() { function ready() {
if (list.len() >= n) { if (list.length >= n) {
done(); done();
list.removeListener('add', ready); list.removeListener('add', ready);
return true; return true;
@ -46,7 +48,7 @@ describe('PANIC!', function(){
} }
} }
function gunify(ctx, done){ function gunify(done, ctx){
var s = document.createElement('script'); var s = document.createElement('script');
s.src = 'gun.js'; s.src = 'gun.js';
s.onload = done; s.onload = done;
@ -69,7 +71,7 @@ describe('PANIC!', function(){
var sync = gun.get('sync'); var sync = gun.get('sync');
sync.put({hello: 'world'}) sync.put({hello: 'world'})
}).then(function(){ }).then(function(){
return bob.run(function(ctx, done){ return bob.run(function(done, ctx){
var sync = gun.get('sync'); var sync = gun.get('sync');
sync.on(function(val){ sync.on(function(val){
if(val.hello === 'world'){ if(val.hello === 'world'){

177
test/holy/grail.js Normal file
View File

@ -0,0 +1,177 @@
/*
This file should be one
folder deeper than every
other file. It requires
mocha to run.
*/
var panic = require('panic-server');
var spawn = require('child_process').spawn;
var path = require('path');
var http = require('http');
var fs = require('fs');
var ports = require('./ports');
var wd = require('selenium-webdriver');
function open(url) {
var driver = new wd.Builder()
.forBrowser('firefox')
.build();
driver.get(url);
return driver;
}
open('http://localhost:' + ports.panic + '/index.html');
open('http://localhost:' + ports.panic + '/index.html');
var staticServer = new http.Server(function (req, res) {
if (req.url === '/') {
req.url = '/index.html';
}
var file = path.join(__dirname, req.url);
try {
var page = fs.readFileSync(file, 'utf8');
res.end(page);
} catch (e) {
// don't care
}
});
var server = panic.clients.filter('Node.js').pluck(1);
var browsers = panic.clients.excluding(server);
var alice = browsers.pluck(1);
var bob = browsers.excluding(alice).pluck(1);
var serverPath = path.join(__dirname, 'gun-server.js');
// start the server on :8080
spawn('node', [serverPath]);
function waitFor (num, list) {
return new Promise(function (res) {
function ready() {
if (list.length < num) {
return;
}
res();
list.removeListener('add', ready);
return true;
}
if (!ready()) {
list.on('add', ready);
}
});
}
before(function () {
this.timeout(1500000);
// start the panic server
panic.server(staticServer).listen(ports.panic);
return waitFor(2, browsers)
.then(function () {
return waitFor(1, server);
});
});
var scope = {
uniqueKey: Math.random().toString(16).slice(2),
file: path.join(process.cwd(), 'delete-me.json'),
'@scope': true
}
describe('The holy grail', function () {
it('should allow full recovery', function () {
this.timeout(1500000);
return browsers.run(function () {
localStorage.clear();
})
.then(function () {
return browsers.run(function () {
window.ref = gun.get(uniqueKey).put({
text: 'ignore'
});
}, scope)
})
.then(function () {
return alice.run(function (done) {
// alice saves some data
//ref.path('text').put('Initial text', done); // TODO: USE THIS LINE INSTEAD!
ref.path('text').put('Initial text');
setTimeout(done, 50);
});
})
.then(function () {
return bob.run(function (done) {
var ctx = this;
ref.path('text').on(function (data) {
if (data === 'ignore') {
return;
}
// bob sees alice's data
if (data !== 'Initial text') {
ctx.fail('Wrong data showed up: ' + JSON.stringify(data));
}
done();
});
});
})
.then(function () {
return server.run(function () {
var fs = require('fs');
// destroy the data
fs.unlinkSync(file);
// crash the server
process.exit(0);
}, scope);
})
.then(function () {
return alice.run(function (done) {
ref.path('text').put('A conflicting update');
setTimeout(done, 50);
});
})
.then(function () {
return bob.run(function () {
ref.path('text').put('B conflicting update');
});
})
.then(function () {
spawn('node', [serverPath]);
return waitFor(1, server);
})
.then(function () {
return browsers.run(function (done) {
var ctx = this;
ref.path('text').on(function (value) {
if (value === 'B conflicting update') {
done();
}
});
});
});
});
});
after(function () {
if (server.length) {
return server.run(function () {
process.exit(0);
});
}
});

16
test/holy/gun-server.js Normal file
View File

@ -0,0 +1,16 @@
var panic = require('panic-client');
var ports = require('./ports');
var Gun = require('gun');
var gun = new Gun({
file: 'delete-me.json'
});
var http = require('http');
var server = new http.Server(gun.wsp.server);
gun.wsp(server);
server.listen(ports.gun);
panic.server('http://localhost:' + ports.panic);

27
test/holy/index.html Normal file
View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Holy grail demo</title>
</head>
<body>
<script src='panic.js'></script>
<script src='http://localhost:8080/gun.js'></script>
<script>
(function () {
var req = new XMLHttpRequest();
req.overrideMimeType('application/json');
req.open('GET', 'ports.json');
req.addEventListener('load', function () {
var ports = JSON.parse(req.responseText);
var server = 'http://localhost:' + ports.gun + '/gun';
window.gun = new Gun(server);
panic.server('http://localhost:' + ports.panic);
});
req.send();
}());
</script>
</body>
</html>

4
test/holy/ports.json Normal file
View File

@ -0,0 +1,4 @@
{
"panic": 3000,
"gun": 8080
}

View File

@ -1978,11 +1978,13 @@
var hewo = {hello: "world"}; var hewo = {hello: "world"};
window.puti = window.puti || 0; window.puti = window.puti || 0;
window.geti = window.geti || 0; window.geti = window.geti || 0;
/*
localStorage.clear(); localStorage.clear();
gun.get('users').put({1: {where: {lat: Math.random(), lng: Math.random(), i: 1}}}); gun.get('users').put({1: {where: {lat: Math.random(), lng: Math.random(), i: 1}}});
//var ok = function(a,b){ console.log('wat', a,b) } //var ok = function(a,b){ console.log('wat', a,b) }
//Gun.log.debug=1;console.log("------------------"); //Gun.log.debug=1;console.log("------------------");
var val = gun.get('users').path(1).path('where').val(ok); var val = gun.get('users').path(1).path('where').val(ok);
*/
}); });
//localStorage.clear(); //localStorage.clear();
/* /*

View File

@ -27,7 +27,7 @@
<button id="abort">Abort</button> <button id="abort">Abort</button>
<button id="share">Share</button> <button id="share">Share</button>
<a id="share-result"></a> <a id="share-result"></a>
<script src="./mocha/json2.js"></script> <script src="../json2.js"></script>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script> <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="benchmark.js"></script> <script src="benchmark.js"></script>
<script src="ptsd.js"></script> <script src="ptsd.js"></script>