SEA unit tests passing!!! Needed quite a few fixes on async write queue stuff.

This commit is contained in:
Mark Nadal 2021-06-01 06:05:04 -07:00
parent 177eab019b
commit cb9322909b
5 changed files with 152 additions and 103 deletions

93
gun.js
View File

@ -96,14 +96,11 @@
// On event emitter generic javascript utility.
module.exports = function onto(tag, arg, as){
if(!tag){ return {to: onto} }
var u, tag = (this.tag || (this.tag = {}))[tag] ||
(this.tag[tag] = {tag: tag, to: onto._ = {
next: function(arg){ var tmp;
if((tmp = this.to)){
tmp.next(arg);
}}
}});
if('function' == typeof arg){
var u, f = 'function' == typeof arg, tag = (this.tag || (this.tag = {}))[tag] || f && (
this.tag[tag] = {tag: tag, to: onto._ = { next: function(arg){ var tmp;
if(tmp = this.to){ tmp.next(arg) }
}}});
if(f){
var be = {
off: onto.off ||
(onto.off = function(){
@ -301,7 +298,7 @@
root.on('out', msg);
return;
}
root.hatch = root.hatch || []; //ctx.latch = root.hatch = [];
ctx.latch = root.hatch; ctx.match = root.hatch = [];
var put = msg.put;
var DBG = ctx.DBG = msg.DBG, S = +new Date;
if(put['#'] && put['.']){ /*root && root.on('put', msg);*/ return } // TODO: BUG! This needs to call HAM instead.
@ -385,13 +382,15 @@
eve.to.next(msg);
fire(ctx);
}
function fire(ctx, msg){
function fire(ctx, msg){ var root;
if(ctx.stop){ return }
if(--ctx.stun !== 0 && !ctx.err){ return } // TODO: 'forget' feature in SEA tied to this, bad approach, but hacked in for now. Any changes here must update there.
ctx.stop = 1;
if(!(root = ctx.root)){ return }
var tmp = ctx.match; tmp.end = 1;
if(tmp === root.hatch){ if(!(tmp = ctx.latch) || tmp.end){ delete root.hatch } else { root.hatch = tmp } }
ctx.hatch && ctx.hatch(); // TODO: rename/rework how put & this interact.
if(!ctx.root){ return }
var hatch = ctx.root.hatch; ctx.root.hatch = 0; setTimeout.each(hatch, function(cb){cb && cb()}); //ctx.latch.end = 1; if(ctx.root.hatch.end){ ctx.root.hatch = 0 } setTimeout.each(ctx.latch, function(cb){cb && cb()});
setTimeout.each(ctx.match, function(cb){cb && cb()});
if(!(msg = ctx.msg) || ctx.err || msg.err){ return }
msg.out = universe;
ctx.root.on('out', msg);
@ -767,7 +766,6 @@
if(!msg.put || ('string' == typeof get['.'] && u === tmp[get['.']])){
if(u !== at.put){ return }
if(!at.soul && !at.has){ return } // TODO: BUG? For now, only core-chains will handle not-founds, because bugs creep in if non-core chains are used as $ but we can revisit this later for more powerful extensions.
//console.only; if('~sT1s6lOaUgia5Aiy_Qg_Z4ubCCVFDyGVJsi-i0VmKJI.UTmwQrcKxkHfw0lFK2bkVDaYbd4_2T1Gj-MONFMostM/zfdsa/y/x' == at.soul){ console.log("ACK:", msg, at, at.put, u !== at.put, 'da da da', at.root.graph[at.soul]); debugger; }
at.ack = (at.ack || 0) + 1;
at.on('in', {
get: at.get,
@ -804,23 +802,29 @@
opt.at = cat;
opt.ok = key;
var wait = {}; // can we assign this to the at instead, like in once?
function any(msg, eve){
function any(msg, eve, f){
if(any.stun){ return }
var at = msg.$._, data = at.put, tmp;
var at = msg.$._, data = at.put, aid, tmp;
if((tmp = root.pass) && !tmp[id]){ return }
if(!at.has && !at.soul){ data = (u !== (msg.put||'')['='])? msg.put['='] : msg.put } // handles non-core messages.
if('string' == typeof (tmp = Gun.valid(data))){ data = root.$.get(tmp)._.put } // TODO: Can we delete this line of code, because the line below (which was inspired by @rogowski) handles it anyways?
if(u === data && msg.$$){ data = msg.$$._.put }
if(opt.not !== u && u === data){ return }
if(opt.stun === u){
if(u !== opt.not && u === data){ return }
if(u === opt.stun){
//if(tmp = root.stun){ tmp = tmp[at.id] || at.$.back(function(back){ return tmp[back.id] || u }); if(tmp && !tmp.end && any.id > (tmp._||'').id){ // this is more thorough, but below seems to work too?
if((tmp = root.stun) && (tmp = tmp[at.id] || tmp[at.back.id]) && !tmp.end && any.id > (tmp._||'').id){ // if we are in the middle of a write, don't read until it is done, unless our callback was earlier than the write.
tmp[id] = function(){any(msg,eve)}; // add ourself to the stun callback list that is called at end of the write.
//if((tmp = root.stun) && (tmp = tmp[at.id] || tmp[at.back.id]) && !tmp.end && any.id > (tmp._||'').id){ // if we are in the middle of a write, don't read until it is done, unless our callback was earlier than the write.
if((tmp = root.stun) && (tmp = tmp[aid = cat.id] || tmp[aid = at.id] || (msg.$$ && tmp[aid = msg.$$._.id]) || tmp[aid = at.back.id]) && any.id > tmp.run){
if(tmp.stun && !tmp.stun.end){
tmp.stun[id] = function(){any(msg,eve,1)}; // add ourself to the stun callback list that is called at end of the write.
return;
}
root.stun[aid] = tmp.next;
any(msg,eve,f);
return;
} //}
if(tmp = root.hatch){ // quick hack! // What's going on here? Because data is streamed, we get things one by one, but a lot of developers would rather get a callback after each batch instead, so this does that by creating a wait list per chain id that is then called at the end of the batch by the hatch code in the root put listener.
}
if((tmp = root.hatch) && !tmp.end && u === opt.hatch && !f){ // quick hack! // What's going on here? Because data is streamed, we get things one by one, but a lot of developers would rather get a callback after each batch instead, so this does that by creating a wait list per chain id that is then called at the end of the batch by the hatch code in the root put listener.
if(wait[at.$._.id]){ return } wait[at.$._.id] = 1;
tmp.push(function(){any(msg,eve)});
tmp.push(function(){any(msg,eve,1)});
return;
}; wait = {}; // end quick hack.
}
@ -923,9 +927,10 @@
Gun.chain.put = function(data, cb, as){ // I rewrote it :)
var gun = this, at = gun._, root = at.root;
as = as || {};
(root.stun = root.stun || {})[at.id] = (as.stun = as.stun
|| ((root.stun._ = (root.stun._ || 0) + 1) && {})); // set a flag for reads to check if this chain is writing.
as.stun._ || ((as.stun._ = function(){}).id = as.run = root.once); // but alas, only if our write has an earlier id. // this is ugly but other options either use more memory or require an extra type check on each stun callback. So meh, this works for now, any better ideas?
as.root = at.root;
as.run || (as.run = root.once);
(as.stun || (as.stun = function(){ return as.run })).back = (root.stun || (root.stun = {}))._; (as.ta = root.stun)._ = as.stun;
stun(as, at.id); // set a flag for reads to check if this chain is writing.
as.ack = as.ack || cb;
as.via = as.via || gun;
as.data = as.data || data;
@ -937,15 +942,16 @@
as.todo = [{it: as.data, ref: as.$}];
as.turn = as.turn || turn;
as.ran = as.ran || ran;
// TODO: Perf! We only need to stun chains that are being modified, not necessarily written to.
(function walk(){
var to = as.todo, at = to.pop(), d = at.it, v, k, cat, tmp, g;
(tmp = at.ref) && ((root.stun || (root.stun = {}))[tmp._.id] = as.stun); // stun
var to = as.todo, at = to.pop(), d = at.it, cid = at.ref && at.ref._.id, v, k, cat, tmp, g;
stun(as, at.ref);
if(tmp = at.todo){
k = tmp.pop(); d = d[k];
if(tmp.length){ to.push(at) }
}
if(!(v = valid(d)) && !(g = Gun.is(d))){
if(!Object.plain(d)){ (as.ack||noop).call(as, as.out = {err: Gun.log("Invalid data, " + typeof d + " at " + (as.path||[]).join('.'))}); return } // TODO: BUG! Clear out stun!
if(!Object.plain(d)){ (as.ack||noop).call(as, as.out = {err: as.err = Gun.log("Invalid data, " + typeof d + " at " + (as.path||[]).join('.'))}); as.ran(as); return }
var seen = as.seen || (as.seen = []), i = seen.length;
while(i--){ if(d === (tmp = seen[i]).it){ v = d = tmp.link; break } }
}
@ -958,11 +964,12 @@
var id = as.seen.length;
(as.wait || (as.wait = {}))[id] = '';
tmp = (cat.ref = (g? d : k? at.ref.get(k) : at.ref))._;
(tmp = (d && (d._||'')['#']) || tmp.soul || tmp.link)? resolve({soul: tmp}) : cat.ref.get(resolve, {run: as.run, v2020:1}); // TODO: BUG! This should be resolve ONLY soul to prevent full data from being loaded.
(tmp = (d && (d._||'')['#']) || tmp.soul || tmp.link)? resolve({soul: tmp}) : cat.ref.get(resolve, {run: as.run, /*hatch: 0,*/ v2020:1}); // TODO: BUG! This should be resolve ONLY soul to prevent full data from being loaded.
function resolve(msg, eve){
if(eve){ eve.off(); eve.rid(msg) } // TODO: Too early! Check all peers ack not found.
// TODO: BUG maybe? Make sure this does not pick up a link change wipe, that it uses the changign link instead.
var soul = msg.soul || (tmp = (msg.$$||msg.$)._||'').soul || tmp.link || ((tmp = tmp.put||'')._||'')['#'] || tmp['#'] || (((tmp = msg.put||'') && msg.$$)? tmp['#'] : (tmp['=']||tmp[':']||'')['#']);
(tmp = msg.$) && ((root.stun || (root.stun = {}))[tmp._.id] = as.stun); // stun
stun(as, msg.$);
if(!soul){
soul = [];
msg.$.back(function(at){
@ -971,7 +978,6 @@
});
soul = soul.reverse().join('/');
}
//if(soul.indexOf('/zfdsa/y/x/c/foo') >= 1){ console.log('!!! *** ---', window.ZOW, cat, msg, as);debugger; /* id 5 ~ 8 should be stunned */ }
cat.link['#'] = soul;
!g && (((as.graph || (as.graph = {}))[soul] = (cat.node || (cat.node = {_:{}})))._['#'] = soul);
delete as.wait[id];
@ -985,22 +991,36 @@
return gun;
}
function stun(as, id){
if(!id){ return } id = (id._||'').id||id;
tmp = as.root.stun || (as.root.stun = as.ta);
var it = {run: as.run, stun: as.stun};
(tmp[id]? (tmp[id].last.next = it) : (tmp[id] = it)).last = it;
}
function ran(as){
if(as.err){ console.log("GUN in a buggy state, restart & report please."); return } // move log handle here. // TODO: BUG! Clear out stun!
if(as.todo.length || as.end || !Object.empty(as.wait)){ return } as.end = 1;
var cat = (as.$.back(-1)._), ask = cat.ask(function(ack){
cat.root.on('ack', ack);
var cat = (as.$.back(-1)._), root = cat.root, ask = cat.ask(function(ack){
root.on('ack', ack);
if(ack.err){ Gun.log(ack) }
if(++acks > (as.acks || 0)){ this.off() } // Adjustable ACKs! Only 1 by default.
if(!as.ack){ return }
as.ack(ack, this);
}, as.opt), acks = 0, stun = as.stun;
}, as.opt), acks = 0, stun = as.stun, tmp;
(tmp = function(){ // this is not official yet, but quick solution to hack in for now.
if(!stun){ return } stun.end = noop; // like with the earlier id, cheaper to make this flag a function so below callbacks do not have to do an extra type check.
if(root.stun){ delete root.stun['s'+as.run] }
if((tmp = root.stun) && stun === tmp._){
if(!(tmp = stun.back) || tmp.end){
delete root.stun; // ABC, ACB, BAC, BCA, CBA, CAB;
}
(root.stun||{})._ = tmp;
}
setTimeout.each(Object.keys(stun), function(cb){ if(cb = stun[cb]){cb()} }); // resume the stunned reads // Any perf reasons to CPU schedule this .keys( ?
}).hatch = tmp; // this is not official yet ^
//console.only(1, "PUT!", as.graph);
//console.log(1, "PUT!", as.run, as.graph);
(as.via._).on('out', {put: as.out = as.graph, opt: as.opt, '#': ask, _: tmp});
if((tmp = cat.root.stun) && --tmp._ === 0){ delete cat.root.stun } // decrease stun ids until done. // this used to be above the out call, but trying out new stun/run checks.
}
function get(as){
@ -1184,7 +1204,6 @@
function map(msg){ this.to.next(msg);
var cat = this.as, gun = msg.$, at = gun._, put = msg.put, tmp;
if(!at.soul && !msg.$$){ return } // this line took hundreds of tries to figure out. It only works if core checks to filter out above chains during link tho. This says "only bother to map on a node" for this layer of the chain. If something is not a node, map should not work.
//console.log("mapmapmapmap", cat.id, msg);
Gun.on.link(msg, cat);
}
var noop = function(){}, event = {stun: noop, off: noop}, u;

View File

@ -30,7 +30,7 @@ yson.parseAsync = function(text, done, revive, M){
tmp = ctx.s;
if(ctx.a){
tmp = s.slice(ctx.sl, i);
if(b){ tmp = JSON.parse('"'+tmp+'"') }
if(b || (1+tmp.indexOf('\\u'))){ tmp = JSON.parse('"'+tmp+'"') } // unicode :( handling
if(ctx.at instanceof Array){
ctx.at.push(ctx.s = tmp);
} else {
@ -38,7 +38,7 @@ yson.parseAsync = function(text, done, revive, M){
}
} else {
ctx.s = s.slice(ctx.sl, i);
if(b){ ctx.s = JSON.parse('"'+ctx.s+'"'); }
if(b || (1+ctx.s.indexOf('\\u'))){ ctx.s = JSON.parse('"'+ctx.s+'"'); } // unicode :( handling
}
ctx.a = b = u;
}
@ -169,13 +169,13 @@ yson.stringifyAsync = function(data, done, replacer, space, ctx){
function ify(){
var at = ctx.at, data = at.d, add = '', tmp;
if(at.i && (at.i - at.j) > 0){ add += ',' }
if(u !== (tmp = at.k)){ add += '"'+tmp+'":' }
if(u !== (tmp = at.k)){ add += JSON.stringify(tmp) + ':' } //'"'+tmp+'":' } // only if backslash
switch(typeof data){
case 'boolean':
add += ''+data;
break;
case 'string':
add += JSON.stringify(data); //ctx.text += '"'+data+'"';//JSON.stringify(data);
add += JSON.stringify(data); //ctx.text += '"'+data+'"';//JSON.stringify(data); // only if backslash
break;
case 'number':
add += data;
@ -205,6 +205,10 @@ yson.stringifyAsync = function(data, done, replacer, space, ctx){
}
// let this & below pass into default case...
case 'function':
if(at.as instanceof Array){
add += 'null';
break;
}
default: // handle wrongly added leading `,` if previous item not JSON-able.
add = '';
at.j++;

View File

@ -80,7 +80,7 @@ describe('Gun', function(){
obj = [{x:"test",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 }}}];
JSON.stringifyAsync(obj, function(err, text){
JSON.parseAsync(text, function(err, data){
expect(data).to.be.eql([{x:"test",a:true,c:3,y:"yes","get":{"#":"chat"},foo:[1,'go'],blah:9}]);
expect(data).to.be.eql([{x:"test",a:true,c:3,y:"yes","get":{"#":"chat"},foo:[1,null,null,'go'],blah:9}]);
done();
})
});
@ -3813,7 +3813,6 @@ describe('Gun', function(){
});
});
});*/
return;
it('Nested listener should be called', function(done){
var gun = Gun();
@ -3834,20 +3833,26 @@ describe('Gun', function(){
var app = gun.get('nl/app');
var node = app.get('watcher/1').put({"stats":{"num":3},"name":"trex"});
var C = 0;
app.get('watcher/1').get('stats').on(function (v, k) {
console.log('v:', k, v);
//console.log('v:', k, v);
if(++C === 1){
expect(v.num).to.be(3);
return;
}
expect(v.num).to.be(4);
done();
});
setTimeout(function(){
console.log("Huh?");
app.get('watcher/1').put({"stats":{"num":4},"name":"trexxx"});
},100);
});
return;
it.only('Memory management', function(done){
/*it.skip('Memory management', function(done){
this.timeout(9999999);
var gun = Gun(), c = 100000, big = "big";
while(--c){big += "big"}
@ -3865,8 +3870,7 @@ describe('Gun', function(){
},25);
});
return;
it.only('Custom extensions are chainable', function(done){
it('Custom extensions are chainable', function(done){
Gun.chain.filter = function(filter){
var chain = this.chain();
var context = this;
@ -3910,24 +3914,32 @@ describe('Gun', function(){
.filter(['a','b']) // Gun.chain.filter = function(tags){ .... }
.get(function(no){console.log("NO!", no)})
.once(function(yes){console.log("YES!", yes)})
});
}); */
it.only('Check that events are called with multiple instances', function(done){
it('Check that events are called with multiple instances', function(done){
var gunA = Gun( { file : "A.json" } );
var gunB = Gun( { file : "B.json" });
var gunC = Gun( { file : "C.json" });
gunA.get( "some path A" ).map(function(v,f){ console.log( "event on A: ", f, v ) } );
gunB.get( "some path B" ).map(function(v,f){ console.log( "event on B: ", f, v ) } );
gunC.get( "some path C" ).map(function(v,f){ console.log( "event on C: ", f, v ) } );
var check = {};
gunA.get( "some path A" ).map(function(v,f){ check.A = v; /*console.log( "event on A: ", f, v )*/ } );
gunB.get( "some path B" ).map(function(v,f){ check.B = v; /*console.log( "event on B: ", f, v )*/ } );
gunC.get( "some path C" ).map(function(v,f){ check.C = v; /*console.log( "event on C: ", f, v )*/ } );
gunA.get( "some path A" ).put( { simple:"message" } );
gunB.get( "some path B" ).put( { simple:"message" } );
gunC.get( "some path C" ).put( { simple:"message" } );
setTimeout(function(){
expect(check.A).to.be('message');
expect(check.B).to.be('message');
expect(check.C).to.be('message');
done();
}, 100);
});
it.only('Make sure circular contexts are not copied', function(done){
/* let's define an appropriate deep default database... */
/*it.only('Make sure circular contexts are not copied', function(done){
//let's define an appropriate deep default database...
var dfltSansUsers = { 1: { name : "org1", sites : { 1: {name : "site1"} } } };
var alice = {name: "alice" }
@ -3939,19 +3951,19 @@ describe('Gun', function(){
var alice = gun.get( "alice" ).put( { name: "alice" } );
console.log( "Failed after this" );
root.path( "1.sites.1.users" ).put( { 1: alice } );
root.get("1").get("sites").get("1").get("users" ).put( { 1: alice } );
console.log( "Failed before this" );
});
});*/
it.only('get any any none', function(done){
it('get any any none', function(done){
gun.get('full/none').get(function(at, ev){
var err = at.err, data = at.put, field = at.get;
console.log("*****", data);
//console.log("*****", data);
expect(data).to.be(undefined);
});
gun.get('full/none').get(function(at, ev){
var err = at.err, data = at.put, field = at.get;
console.log("*****2", data);
//console.log("*****2", data);
expect(data).to.be(undefined);
done();
});
@ -3971,23 +3983,24 @@ describe('Gun', function(){
done();
});
},400);
});return;
});
it('get get any parallel', function(done){
Gun.statedisk({ bob: { age: 29, name: "Bob!" } }, 'parallel/get/get', function(){
gun.get('parallel/get/get').path('bob').any(function(err, data, field, at, ev){
gun.get('parallel/get/get').get('bob').get(function(data){ data = data.put;
//console.log("***** 1", data);
expect(data.age).to.be(29);
expect(data.name).to.be('Bob!');
});
gun.get('parallel/get/get').path('bob').any(function(err, data, field, at, ev){
gun.get('parallel/get/get').get('bob').get(function(data){ data = data.put;
//console.log("***** 2", data);
expect(data.age).to.be(29);
expect(data.name).to.be('Bob!');
done();
if(done.c){ return }
done(); done.c = 1;
});
}, 1000);
});
});return;
it('get get any parallel later', function(done){
Gun.statedisk({ bob: { age: 29, name: "Bob!" } }, 'parallel/get/get/later', function(){
@ -7990,6 +8003,7 @@ describe('Gun', function(){
describe('localStorage', function(){
it("err", function(done){
this.timeout(9000);
var localStorage = localStorage || {clear:function(){}};
localStorage.clear();
var gun = Gun();
@ -8004,6 +8018,7 @@ describe('Gun', function(){
});
});
it("ack", function(done){
this.timeout(9000);
var localStorage = localStorage || {clear:function(){}};
localStorage.clear();
var gun = Gun();

View File

@ -25,8 +25,8 @@
<script src="../lib/rindexed.js"></script -->
<script src="../lib/yson.js"></script>
<!-- script src="./rad/rad.js"></script>
<script src="./sea/sea.js"></script -->
<!-- script src="./rad/rad.js"></script -->
<script src="./sea/sea.js"></script>
<script src="./common.js"></script>
<script>
@ -35,7 +35,7 @@
console.log('async?', Gun.debug);
}
var run = mocha.run(function(a,b,c){
document.body.prepend("MARK! REMEMBER TO REMOVE RETURN! &&&& ADD RADISK AGAIN! &&& YSON BACK IN (it breaks on SEA data)");return;
document.body.prepend("MARK! REMEMBER TO REMOVE RETURN! &&&& ADD RADISK AGAIN! &&& WHAT ABOUT localStorage gun/gap ???");return;
var yes = confirm("REFRESH BROWSER FOR ASYNC TESTS?");
if(yes){
if(location.search){

View File

@ -37,6 +37,9 @@ describe('SEA', function(){
var user;
var gun;
var pub;
var prep = async function(d,k, n,s){ return {'#':s,'.':k,':': await SEA.opt.parse(d),'>':Gun.state.is(n, k)} }; // shim for old - prep for signing.
var pack = function(d,cb,k, n,s){ return new Promise(function(res, rej){ SEA.opt.pack(d, function(r){ res(r) }, k,n,s) }) }; // make easier to upgrade test, cb to await
describe('Utility', function(){
/*it('generates aeskey from jwk', function(done) { // DEPRECATED!!!
console.log("WARNING: THIS DOES NOT WORK IN BROWSER!!!! NEEDS FIX");
@ -197,14 +200,14 @@ describe('SEA', function(){
expect(dec.priv).to.be(okey.priv);
expect(dec.epriv).to.be(okey.epriv);
var gun = Gun({super: true}), tmp = Gun.node.soul(old);
var gun = Gun({super: true}), tmp = old._['#'];
var graph = {};
graph[tmp] = old;
gun._.graph[tmp] = graph[tmp] = old;
var alias = await SEA.verify(old.alias, false);
expect(alias).to.be('bob');
alias = Gun.state.ify({}, tmp, 1, Gun.val.rel.ify(tmp), tmp = '~@'+alias);
alias = Gun.state.ify({}, tmp, 1, {'#': tmp}, tmp = '~@'+alias);
graph[tmp] = alias;
gun.on('test', {$: gun, put: graph});
gun._.graph[tmp] = alias;//gun.on('test', {$: gun, put: graph});
var use = gun.user();
use.auth('bob', 'test123', function(ack){
expect(ack.err).to.not.be.ok();
@ -220,12 +223,12 @@ describe('SEA', function(){
var gun = Gun({super: true}), tmp = old._['#'];//Gun.node.soul(old);
var graph = {};
graph[tmp] = old;
gun._.graph[tmp] = graph[tmp] = old;
var alias = SEA.opt.unpack(await SEA.verify(old.alias, false), 'alias', old);
expect(alias).to.be('alice');
alias = Gun.state.ify({}, tmp, 1, Gun.val.rel.ify(tmp), tmp = '~@'+alias);
graph[tmp] = alias;
gun.on('test', {$: gun, put: graph});
alias = Gun.state.ify({}, tmp, 1, {'#': tmp}, tmp = '~@'+alias);
gun._.graph[tmp] = graph[tmp] = alias;
//gun.on('test', {$: gun, put: graph});
var use = gun.user();
use.auth('alice', 'test123', function(ack){
expect(ack.err).to.not.be.ok();
@ -233,15 +236,15 @@ describe('SEA', function(){
});
}())})
it('JSON escape', function(done){
it('JSON escape', async function(done){
var plain = "hello world";
var json = JSON.stringify({hello:'world'});
var n1 = Gun.state.ify({}, 'key', 1, plain, 'soul');
var n2 = Gun.state.ify({}, 'key', 1, json, 'soul');
var tmp = SEA.opt.prep(plain, 'key', n1, 'soul');
var tmp = await prep(plain, 'key', n1, 'soul');
expect(tmp[':']).to.be("hello world");
tmp = SEA.opt.prep(json, 'key', n2, 'soul');
tmp = await prep(json, 'key', n2, 'soul');
expect(tmp[':'].hello).to.be("world");
tmp = SEA.opt.unpack(tmp);
expect(tmp.hello).to.be("world");
@ -256,15 +259,15 @@ describe('SEA', function(){
var json = JSON.stringify({hello:'world'});
var n1 = Gun.state.ify({}, 'key', 1, json, 'soul');
var sig = await SEA.sign(SEA.opt.prep(json, 'key', n1, 'soul'), pair, null, {raw:1 , check: SEA.opt.pack(json, 'key', n1, 'soul')});
var dup = await SEA.sign(SEA.opt.prep(sig, 'key', n1, 'soul'), pair, null, {raw:1 , check: SEA.opt.pack(sig, 'key', n1, 'soul')});
var sig = await SEA.sign(await prep(json, 'key', n1, 'soul'), pair, null, {raw:1 , check: await pack(json, 'key', n1, 'soul')});
var dup = await SEA.sign(await prep(sig, 'key', n1, 'soul'), pair, null, {raw:1 , check: await pack(sig, 'key', n1, 'soul')});
expect(dup).to.be.eql(sig);
var json = JSON.stringify({hello:'world'});
var n1 = Gun.state.ify({}, 'key', 1, json, 'soul');
var bob = await SEA.pair();
var sig = await SEA.sign(SEA.opt.prep(json, 'key', n1, 'soul'), bob, null, {raw:1 , check: SEA.opt.pack(json, 'key', n1, 'soul')});
var dup = await SEA.sign(SEA.opt.prep(sig, 'key', n1, 'soul'), pair, null, {raw:1 , check: SEA.opt.pack(sig, 'key', n1, 'soul')});
var sig = await SEA.sign(await prep(json, 'key', n1, 'soul'), bob, null, {raw:1 , check: await pack(json, 'key', n1, 'soul')});
var dup = await SEA.sign(await prep(sig, 'key', n1, 'soul'), pair, null, {raw:1 , check: await pack(sig, 'key', n1, 'soul')});
expect(dup).to.not.be.eql(sig);
var json = JSON.stringify({hello:'world'});
@ -286,8 +289,8 @@ describe('SEA', function(){
SEA.pair(function(p){
user.is = user._.sea = p;
gtmp = gid = 'test~'+p.pub;
g.get(gid).put({yo: 'hi'}, function(ack){
var data = SEA.opt.parse(g._.graph[gid].yo);
g.get(gid).put({yo: 'hi'}, async function(ack){
var data = await SEA.opt.parse(g._.graph[gid].yo);
expect(data[':']).to.be('hi');
expect(data['~']).to.be.ok();
g.get(gid).get('yo').once(function(r){
@ -326,7 +329,6 @@ describe('SEA', function(){
done();
});
})
it('read data', function(done){
user.get('a').get('b').once(function(data){
expect(data).to.be(0);
@ -416,10 +418,10 @@ describe('SEA', function(){
if(done.a){ return } done.a = 1;
var ref = user.get('who').get('all').set(msg);
var stub = user.get('stub').put({});
var tmp = ref._.dub || ref._.link;
setTimeout(function(){
user.get('who').put(stub);
setTimeout(function(){
var tmp = ref._.has;
user.get('who').get('all').get(tmp).put({boom: 'ah'});
setTimeout(function(){
user.get('who').get('all').map().once(function(data){
@ -443,7 +445,8 @@ describe('SEA', function(){
gun.on('auth', function(){
user.get("testauthed").get("arumf").set({"this": "is", "an": {"obj2": "again2"}}, function(ack) {
var notsigned = [];
Gun.obj.map(gun._.graph, function(v,k) {
//Gun.obj.map(gun._.graph, function(v,k) {
Object.keys(gun._.graph).forEach(function(k,v){ v = gun._.graph[k];
if (k[0]==='~' || k.indexOf('~', 1)!==-1) { return; } /// ignore '~pubkey' and '~@alias'
notsigned.push(k);
});
@ -467,7 +470,6 @@ describe('SEA', function(){
if(done.c){ return } done.c = 1;
var g = gun._.graph;
var p = '~'+alice.pub+'/';
console.log(1);
//console.log(p, g);
expect(g[p+'z']).to.be.ok();
expect(g[p+'z/y']).to.be.ok();
@ -482,21 +484,31 @@ describe('SEA', function(){
it('user mix', function(done){
var gun = Gun();
gun.on('auth', function(){
gun.on('auth', async function(){
if(done.a){ return } done.a = 1;
var ref = gun.user().get('zasdf').put({a: 9});
var at = gun.user().get('zfdsa').get('y').get('x').get('c').put(ref);
at.get('foo').get('bar').put('yay');
ref.get('foo').get('ah').put(1, function(){setTimeout(function(){
var c = 0, go = function(){ check(++c) }
var ref = gun.user().get('zasdf').put({a: 9}, go);
var at = gun.user().get('zfdsa').get('y').get('x').get('c').put(ref, go);
at.get('foo').get('bar').put('yay', go);
ref.get('foo').get('ah').put(1, go);
function check(){
if(c !== 4){ return }
setTimeout(function(){
if(done.c){ return } done.c = 1;
var g = gun._.graph;
var p = '~'+alice.pub+'/';
//console.log(p, g);
console.log(2);
expect(Object.keys(g[p+'zasdf']).sort()).to.be.eql(['_', 'a', 'foo'].sort());
expect(Object.keys(g[p+'zasdf/foo']).sort()).to.be.eql(['_', 'bar', 'ah'].sort());
var p = '~'+alice.pub;
//console.log(g);
expect(Object.keys(g[p]).sort()).to.be.eql(['_', 'zasdf', 'zfdsa'].sort());
expect(Object.keys(g[p+'/zasdf']).sort()).to.be.eql(['_', 'a', 'foo'].sort());
expect(Object.keys(g[p+'/zasdf/foo']).sort()).to.be.eql(['_', 'bar', 'ah'].sort());
expect(Object.keys(g[p+'/zfdsa']).sort()).to.be.eql(['_', 'y'].sort());
expect(Object.keys(g[p+'/zfdsa/y']).sort()).to.be.eql(['_', 'x'].sort());
expect(Object.keys(g[p+'/zfdsa/y/x']).sort()).to.be.eql(['_', 'c'].sort());
expect(g[p+'/zfdsa'].y.indexOf('/zfdsa/y"') > 0).to.be.ok();
expect(g[p+'/zfdsa/y'].x.indexOf('/zfdsa/y/x"') > 0).to.be.ok();
expect(g[p+'/zfdsa/y/x'].c.indexOf('/zasdf"') > 0).to.be.ok();
done();
},200)});
},500)};
});
gun.user().auth(alice);
});
@ -513,8 +525,7 @@ describe('SEA', function(){
if(done.c){ return } done.c = 1;
var g = gun._.graph;
var p = '~'+alice.pub+'/';
console.log(3);
console.log(p, Object.keys(g[p+'pchat/their.pub/2020']||{}).sort());
//console.log(p, Object.keys(g[p+'pchat/their.pub/2020']||{}).sort());
expect(Object.keys(g[p+'pchat/their.pub/2020']).sort()).to.be.eql(['_', 'msg'].sort());
expect(g[p+'2020']).to.not.be.ok();
done();