diff --git a/gun.js b/gun.js index ece88877..fdced091 100644 --- a/gun.js +++ b/gun.js @@ -97,9 +97,9 @@ return !o? o : JSON.parse(JSON.stringify(o)); // is shockingly faster than anything else, and our data has to be a subset of JSON anyways! } ;(function(){ - function empty(v,i){ var n = this.n; + function empty(v,i){ var n = this.n, u; if(n && (i === n || (obj_is(n) && obj_has(n, i)))){ return } - if(i){ return true } + if(u !== i){ return true } } Type.obj.empty = function(o, n){ if(!o){ return true } @@ -115,20 +115,21 @@ } t.r = t.r || []; t.r.push(k); }; - var keys = Object.keys, map; + var keys = Object.keys, map, u; Object.keys = Object.keys || function(o){ return map(o, function(v,k,t){t(k)}) } Type.obj.map = map = function(l, c, _){ - var u, i = 0, x, r, ll, lle, f = fn_is(c); - t.r = null; + var u, i = 0, x, r, ll, lle, f = 'function' == typeof c; + t.r = u; if(keys && obj_is(l)){ ll = keys(l); lle = true; } + _ = _ || {}; if(list_is(l) || ll){ x = (ll || l).length; for(;i < x; i++){ var ii = (i + Type.list.index); if(f){ - r = lle? c.call(_ || this, l[ll[i]], ll[i], t) : c.call(_ || this, l[i], ii, t); + r = lle? c.call(_, l[ll[i]], ll[i], t) : c.call(_, l[i], ii, t); if(r !== u){ return r } } else { //if(Type.test.is(c,l[i])){ return ii } // should implement deep equality testing! @@ -171,7 +172,7 @@ tmp.next(arg); }} }}); - if(arg instanceof Function){ + if('function' == typeof arg){ var be = { off: onto.off || (onto.off = function(){ @@ -323,7 +324,7 @@ Node.ify = function(obj, o, as){ // returns a node from a shallow object. if(!o){ o = {} } else if(typeof o === 'string'){ o = {soul: o} } - else if(o instanceof Function){ o = {map: o} } + else if('function' == typeof o){ o = {map: o} } if(o.map){ o.node = o.map.call(as, obj, u, o.node || {}) } if(o.node = Node.soul.ify(o.node || {}, o)){ obj_map(obj, map, {o:o,as:as}); @@ -464,9 +465,13 @@ if(typeof env === 'string'){ env = {soul: env}; } else - if(env instanceof Function){ + if('function' == typeof env){ env.map = env; } + if(typeof as === 'string'){ + env.soul = env.soul || as; + as = u; + } if(env.soul){ at.link = Val.link.ify(env.soul); } @@ -681,7 +686,8 @@ at.on('in', root, at); at.on('in2', root2, at); at.on('put2', map, at); - at.on('out', root, {at: at, out: root}); + //at.on('out', root, {at: at, out: root}); + at.on('out', root2, at); Gun.on('create', at); at.on('create', at); } @@ -704,10 +710,10 @@ if(tmp = msg['@']){ dup.track(tmp) } // HNPERF: Bump original request's liveliness. if(!at.ask(tmp, msg)){ if(msg.get){ - Gun.on.get(msg, gun); //at.on('get', get(msg)); + Gun.on._get(msg, gun); //at.on('get', get(msg)); } if(msg.put){ - Gun.on.put(msg, gun); //at.on('put', put(msg)); + //Gun.on._put(msg, gun); //at.on('put', put(msg)); } } ev.to.next(msg); @@ -718,6 +724,7 @@ } function root2(msg){ if(!msg){ return } + if(msg.out === root2 || msg.out === root){ this.to.next(msg); return } var eve = this, as = eve.as, at = as.at || as, gun = at.$, dup = at.dup, tmp; if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) } if(dup.check(tmp)){ return } dup.track(tmp); @@ -741,15 +748,16 @@ root.on('in', {'@': id, ok: ok || 1}); id = u; }; + var set = root.set || (root.set = {'':1}); all.err = obj_map(put, valid, msg); ctx.node = ctx.state = u; mid = msg = ctx = u; - all(); - } + all(); // if synchronous + fire(root, ''); // if synchronous + } Gun.on.put = put; function valid(node, soul){ if(!node){ return ERR+cut(soul)+"no node." } var ctx = this._, tmp; - (ctx.root.opt||'').super && ctx.root.$.get(soul); // I think we need super for now, but since we are rewriting, should consider getting rid of it. if(!(tmp = node._)){ return ERR+cut(soul)+"no meta." } ctx.node = node; if(soul !== tmp[_soul]){ return ERR+cut(soul)+"soul not same." } @@ -769,6 +777,7 @@ var vertex = graph[soul] || empty, was = state_is(vertex, key, 1), known = vertex[key]; var machine = State(), is = HAM(machine, state, was, val, known), u; (alls = all.s || (all.s = {}))[id] = 1; + (root.set || (root.set = {}))[id] = 1; // tmp code; if(!is.incoming){ if(is.defer){ var to = is.defer - machine; @@ -789,29 +798,46 @@ function map(msg){ var eve = this, root = eve.as, graph = root.graph, put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>'], id = msg['#'], tmp; graph[soul] = state_ify(graph[soul], key, state, val, soul); - debounce(root, soul, key,val, state); // TODO: This should NOT be how the API works, this should be done at an extension layer, but hacky solution to migrate with old code for now. + chain(root, soul, key, (u !== (tmp = put['=']))? tmp : val, state); // TODO: This should NOT be how the API works, this should be done at an extension layer, but hacky solution to migrate with old code for now. + fire(root, soul+key); // ^ eve.to.next(msg); } - function debounce(root, soul, key,val, state){ var tmp; - if(!(tmp = root.next[soul]) || !tmp.$){ return } - tmp.change = state_ify(tmp.change, key, state, val, soul); + function chain(root, soul, key,val, state){ var tmp, put; + (root.opt||'').super && root.$.get(soul); // I think we need super for now, but since we are rewriting, should consider getting rid of it. + if(!root || !(tmp = root.next) || !(tmp = tmp[soul]) || !tmp.$){ return } + (put = root.put || (root.put = {}))[soul] = state_ify(put[soul], key, state, val, soul); tmp.put = state_ify(tmp.put, key, state, val, soul); + return; + tmp.change = state_ify(tmp.change, key, state, val, soul); if(tmp.wait){ return } + var stop = {}; tmp.wait = setTimeout(function(){ var change = tmp.change; tmp.change = tmp.wait = null; - root.stop = this.stop; // temporary fix till a better solution? + root.stop = stop; // temporary fix till a better solution? tmp.on('in', {$: tmp.$, get: soul, put: change}); root.stop = null; // temporary fix till a better solution? },0); } + function fire(root, id){ var set; + if(set = root.set){ delete set[id] } + if(!obj_empty(set)){ return } + var stop = {}; + var next = root.next||'', put = root.put; root.put = root.set = null; + Gun.graph.is(put, function(node,soul){ var tmp; + if(!(tmp = next[soul]) || !tmp.$){ return } + root.stop = stop; // temporary fix till a better solution? + tmp.on('in', {$: tmp.$, get: soul, put: node}); + root.stop = null; // temporary fix till a better solution? + }) + } var ERR = "Error: Invalid graph!"; var cut = function(s){ return " '"+(''+s).slice(0,9)+"...' " } var HAM = Gun.HAM, MD = 2147483647, State = Gun.state; }()); ;(function(){ - Gun.on.put = function(msg, gun){ + Gun.on._put = function(msg, gun){ var at = gun._, ctx = {$: gun, graph: at.graph, put: {}, map: {}, souls: {}, machine: Gun.state(), ack: msg['@'], cat: at, stop: {}}; if(!Gun.obj.map(msg.put, perf, ctx)){ return } // HNPERF: performance test, not core code, do not port. if(!Gun.graph.is(msg.put, null, verify, ctx)){ ctx.err = "Error: Invalid graph!" } @@ -821,7 +847,7 @@ if(u !== ctx.defer){ var to = ctx.defer - ctx.machine; setTimeout(function(){ - Gun.on.put(msg, gun); + Gun.on._put(msg, gun); }, to > MD? MD : to ); // setTimeout Max Defer 32bit :( } if(!ctx.diff){ return } @@ -894,7 +920,7 @@ } function perf(node, soul){ if(node !== this.graph[soul]){ return true } } // HNPERF: do not port! - Gun.on.get = function(msg, gun){ + Gun.on._get = function(msg, gun){ var root = gun._, get = msg.get, soul = get[_soul], node = root.graph[soul], has = get[_has], tmp; var next = root.next || (root.next = {}), at = next[soul]; // queue concurrent GETs? @@ -1008,7 +1034,7 @@ } return; } - if(n instanceof Function){ + if('function' == typeof n){ var yes, tmp = {back: at}; while((tmp = tmp.back) && u === (yes = n(tmp, opt))){} @@ -1081,6 +1107,12 @@ put._ = meta; back.on('in', {$: back.$, put: put, get: back.get}) } + if(tmp = at.lex){ + tmp = (tmp._) || (tmp._ = function(){}); + if(back.ack < tmp.ask){ tmp.ask = back.ack } + if(tmp.ask){ return } + tmp.ask = 1; + } } root.ask(ack, msg); return root.on('in', msg); @@ -1311,7 +1343,7 @@ at.on('in', {get: at.get, put: Gun.val.link.ify(get['#']), $: at.$, '@': msg['@']}); return; } - Gun.on.put(msg, at.root.$); + Gun.on._put(msg, at.root.$); } var empty = {}, u; var obj = Gun.obj, obj_has = obj.has, obj_put = obj.put, obj_del = obj.del, obj_to = obj.to, obj_map = obj.map; @@ -1331,7 +1363,7 @@ } gun = gun.$; } else - if(key instanceof Function){ + if('function' == typeof key){ if(true === cb){ return soul(this, key, cb, as), this } gun = this; var at = gun._, root = at.root, tmp = root.now, ev; @@ -1367,7 +1399,7 @@ if(tmp = this._.stun){ // TODO: Refactor? gun._.stun = gun._.stun || tmp; } - if(cb && cb instanceof Function){ + if(cb && 'function' == typeof cb){ gun.get(cb, as); } return gun; diff --git a/lib/radisk.js b/lib/radisk.js index 2a1fa2a6..712b5b7c 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -40,159 +40,57 @@ 1. Because writing to disk takes time, we should batch data to disk. This improves performance, and reduces potential disk corruption. 2. If a batch exceeds a certain number of writes, we should immediately write to disk when physically possible. This caps total performance, but reduces potential loss. */ - var r = function(key, val, cb){ - key = ''+key; - if(val instanceof Function){ + var r = function(key, data, cb){ + if('function' === typeof data){ var o = cb || {}; - cb = val; - var S; LOG && (S = +new Date); - val = r.batch(key); - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'rad mem'); - if(u !== val){ - cb(u, r.range(val, o), o); - if(atomic(val)){ return } - // if a node is requested and some of it is cached... the other parts might not be. - } - if(r.thrash.at){ - val = r.thrash.at(key); - if(u !== val){ - cb(u, r.range(val, o), o); - if(atomic(val)){ cb(u, val, o); return } - // if a node is requested and some of it is cached... the other parts might not be. - } - } - return r.read(key, cb, o); - } - r.batch(key, val); - if(cb){ r.batch.acks.push(cb) } - if(++r.batch.ed >= opt.batch){ return r.thrash() } // (2) - if(r.batch.to){ return } - //clearTimeout(r.batch.to); // (1) // THIS LINE IS EVIL! NEVER USE IT! ALSO NEVER DELETE THIS SO WE NEVER MAKE THE SAME MISTAKE AGAIN! - r.batch.to = setTimeout(r.thrash, opt.until || 1); - } - - r.batch = Radix(); - r.batch.acks = []; - r.batch.ed = 0; - - r.thrash = function(){ - var thrash = r.thrash; - if(thrash.ing){ return thrash.more = true } - LOG = console.LOG; // dirty place to cheaply update LOG settings over time. - thrash.more = false; - thrash.ing = true; - var batch = thrash.at = r.batch, i = 0; - clearTimeout(r.batch.to); - r.batch = null; - r.batch = Radix(); - r.batch.acks = []; - r.batch.ed = 0; - //console.debug(99); var ID = Gun.text.random(2), S = (+new Date); console.log("[[[[[[[[", ID, batch.acks.length); - r.save(batch, function(err, ok){ - if(++i > 1){ opt.log('RAD ERR: Radisk has callbacked multiple times, please report this as a BUG at github.com/amark/gun/issues ! ' + i); return } - if(err){ opt.log('err', err) } - //console.debug(99); var TMP; console.log("]]]]]]]]", ID, batch.acks.length, (TMP = +new Date) - S, 'more?', thrash.more); - map(batch.acks, function(cb){ cb(err, ok) }); - //console.log("][", +new Date - TMP, thrash.more); - thrash.at = null; - thrash.ing = false; - if(thrash.more){ thrash() } - }); - } - - /* - 1. Find the first radix item in memory. - 2. Use that as the starting index in the directory of files. - 3. Find the first file that is lexically larger than it, - 4. Read the previous file to that into memory - 5. Scan through the in memory radix for all values lexically less than the limit. - 6. Merge and write all of those to the in-memory file and back to disk. - 7. If file too large, split. More details needed here. - */ - /* NEW APPROACH: - 1. For each item in radix memory - 2. Add it to a radix bucket corresponding to directory of files - 3. Iterate over each bucket - 4. Resume old approach. - */ - r.save = function(rad, cb){ - if(r.save.ing){ - r.save.ing.push({rad: rad, ack: cb}); + cb = data; + r.read(key, cb, o); return; } - //console.only(99); var ID = Gun.text.random(2), S = (+new Date); console.log("[[[[[[[[", ID); - r.save.ing = []; - var ack = cb; - var s = function Span(err, ok){ - var tmp = r.save.ing; - //console.only(99); var TMP; console.log("]]]]]]]]", ID, (TMP = +new Date) - S, 'more?', !!tmp); - r.save.ing = null; - map(tmp, function(q){ // if many, not the most efficient to requeue, but works for now. - if(!q || !q.rad || !q.ack){ return } - r.save(q.rad, q.ack); - }) - ack(err, ok); - }; - cb = s; - s.files = {}; - s.i = 0; // TODO: revise? Using counter for critical path not my favorite. - s.place = function(tree, key){ - var go = function(file, last){ - file = decodeURIComponent(file || last || opt.code.from); - (s.files[file] || (s.files[file] = Radix()))(key, tree); - if(!(--s.i)){ s.go() } // TODO: See above, revise? - return true; - } - go.reverse = 1; - go.end = key; - r.list(go); - ++s.i; // TODO: See above, revise? - } - s.go = function(){ - if(s.gone){ return } s.gone = true; - s.seq = []; - map(s.files, function(mem, file){ s.seq.push({file: file, mem: mem}) }); - LOG && opt.log(+new Date, s.seq.length, "rad files #"); - s.files = null; - s.c = 0; - s.merge(s.c); - } - s.merge = function(i){ - i = i || 0; - //var at = s.seq[i]; - var at = s.seq.shift(); - if(!at){ - if(s.ok){ return cb(null, s.ok) } - return cb("No file to save data to."); - } - var file = at.file, mem = at.mem; - r.parse(file, function(err, disk){ - if(err){ return cb(err) } - if(!disk && file !== opt.code.from){ // corrupt file? - r.list.bad(file); // remove from dir list - r.save(rad, cb); // try again - return; - } - disk = disk || Radix(); - var S, C = 0; LOG && (S = +new Date); - Radix.map(mem, function(val, key){ - C++; - // PLUGIN: consider adding HAM as an extra layer of protection - disk(key, val); // merge batch[key] -> disk[key] - }); - LOG && opt.log(S, +new Date - S, "rad merge"); - LOG && opt.log(S, C, "rad merge #"); - r.write(file, disk, s.pop); - }) - } - s.pop = function(err, ok){ - if(s.err = err || s.err){ return cb(err) } - s.ok = ok || s.ok || 1; - s.merge(++s.c); - } - Radix.map(rad, s.place); - if(!s.i){ s.go() }; // TODO: See above, revise? + //var tmp = (tmp = r.batch = r.batch || {})[key] = tmp[key] || {}; + //var tmp = (tmp = r.batch = r.batch || {})[key] = data; + r.save(key, data, cb); } + r.save = function(key, data, cb){ + var s = {key: key}; + s.find = function(file){ var tmp; + s.file = file || (file = opt.code.from); + if(tmp = r.disk[file]){ s.mix(u, tmp); return } + r.parse(file, s.mix); + } + s.mix = function(err, disk){ + if(s.err = err || s.err){ cb(err); return } + var file = s.file = (disk||'').file || s.file; + if(!disk && file !== opt.code.from){ // corrupt file? + r.find.bad(file); // remove from dir list + r.save(key, data, cb); // try again + return; + } + (disk = r.disk[file] || (r.disk[file] = disk || Radix())).file || (disk.file = file); + if(opt.compare){ + data = opt.compare(disk(key), data, key, file); + if(u === data){ cb(err, -1); return } + } + (s.disk = disk)(key, data); + if(disk.Q){ disk.Q.push(cb); return } disk.Q = [cb]; + disk.to = setTimeout(s.write, opt.until); + } + s.write = function(){ + var file = s.file, disk = s.disk; + s.q = disk.Q; + delete disk.Q; + delete r.disk[file]; + r.write(file, disk, s.ack); + } + s.ack = function(err, ok){ + var q = s.q || [], i = 0, ack; + //var S = +new Date; + while(ack = q[i++]){ ack(err, ok) } + //console.log('acks:', +new Date - S, s.file, q.length); + } + r.find(key, s.find); + } + r.disk = {}; /* Any storage engine at some point will have to do a read in order to write. @@ -200,70 +98,77 @@ Therefore it is unavoidable that a read will have to happen, the question is just how long you delay it. */ + var RWC = 0; r.write = function(file, rad, cb, o){ + if(!rad){ cb('No radix!'); return } o = ('object' == typeof o)? o : {force: o}; - var f = function Fractal(){}; + var f = function Fractal(){}, a, b; f.text = ''; - f.count = 0; - f.file = file; - f.each = function(val, key, k, pre){ - //console.log("RAD:::", JSON.stringify([val, key, k, pre])); - if(u !== val){ f.count++ } - if(opt.pack <= (val||'').length){ return cb("Record too big!"), true } - var enc = Radisk.encode(pre.length) +'#'+ Radisk.encode(k) + (u === val? '' : ':'+ Radisk.encode(val)) +'\n'; - if((opt.chunk < f.text.length + enc.length) && (1 < f.count) && !o.force){ - f.text = ''; - f.limit = Math.ceil(f.count/2); - f.count = 0; - f.sub = Radix(); - // IMPORTANT: DO THIS IN REVERSE, SO LAST HALF OF DATA MOVED TO NEW FILE BEFORE DROPPING FROM CURRENT FILE. - Radix.map(rad, f.slice, {reverse: true}); - return true; - } - f.text += enc; - } + f.file = file = rad.file || (rad.file = file); + if(!file){ cb('What file?'); return } f.write = function(){ - var tmp = ename(file); + var text = rad.raw = f.text; + r.disk[file = rad.file || f.file || file] = rad; var S; LOG && (S = +new Date); - r.list.add(tmp, function(err){ - if(err){ return cb(err) } - //opt.store.put(tmp, f.text, cb); // revert to this after stats done below: - opt.store.put(tmp, f.text, function(err,ok){ - LOG && opt.log(S, ST = +new Date - S, "wrote disk", tmp); - cb(err,ok); + r.find.add(file, function add(err){ + if(err){ cb(err); return } + opt.store.put(ename(file), text, function safe(err, ok){ + LOG && opt.log(S, ST = +new Date - S, "wrote disk", JSON.stringify(file), ++RWC, 'total all writes.'); + cb(err, ok || 1); + if(!rad.Q){ delete r.disk[file] } // VERY IMPORTANT! Clean up memory, but not if there is already queued writes on it! }); }); } + f.split = function(){ + f.text = ''; + if(!f.count){ f.count = 0; + Radix.map(rad, function count(){ f.count++ }); // TODO: Perf? Any faster way to get total length? + } + f.limit = Math.ceil(f.count/2); + f.count = 0; + f.sub = Radix(); + Radix.map(rad, f.slice, {reverse: 1}); // IMPORTANT: DO THIS IN REVERSE, SO LAST HALF OF DATA MOVED TO NEW FILE BEFORE DROPPING FROM CURRENT FILE. + r.write(f.end, f.sub, f.both, o); + f.hub = Radix(); + Radix.map(rad, f.stop); + r.write(rad.file, f.hub, f.both, o); + return true; + } f.slice = function(val, key){ f.sub(f.end = key, val); - if(f.limit <= (++f.count)){ - r.write(key, f.sub, f.swap, o); - return true; - } - } - f.swap = function(err){ - if(err){ return cb(err) } - f.sub = Radix(); - Radix.map(rad, f.stop); - r.write(f.file, f.sub, cb, o); + if(f.limit <= (++f.count)){ return true } } f.stop = function(val, key){ if(key >= f.end){ return true } - f.sub(key, val); + f.hub(key, val); } - if(opt.jsonify){ return r.write.jsonify(f, file, rad, cb, o) } // temporary testing idea + f.both = function(err, ok){ + if(b){ cb(err || b); return } + if(a){ cb(err, ok); return } + a = true; + b = err; + } + f.each = function(val, key, k, pre){ + //console.log("RAD:::", JSON.stringify([val, key, k, pre])); + if(u !== val){ f.count++ } + if(opt.pack <= (val||'').length){ return cb("Data too big!"), true } + var enc = Radisk.encode(pre.length) +'#'+ Radisk.encode(k) + (u === val? '' : ':'+ Radisk.encode(val)) +'\n'; + if((opt.chunk < f.text.length + enc.length) && (1 < f.count) && !o.force){ + return f.split(); + } + f.text += enc; + } + if(opt.jsonify){ r.write.jsonify(f, rad, cb, o); return } // temporary testing idea if(!Radix.map(rad, f.each, true)){ f.write() } } - r.write.jsonify = function(f, file, rad, cb, o){ + r.write.jsonify = function(f, rad, cb, o){ var raw; var S; LOG && (S = +new Date); try{raw = JSON.stringify(rad.$); - }catch(e){ return cb("Record too big!") } + }catch(e){ cb("Cannot radisk!"); return } LOG && opt.log(S, +new Date - S, "rad stringified JSON"); - if(opt.chunk < raw.length && !o.force){ - if(Radix.map(rad, f.each, true)){ return } - } + if(opt.chunk < raw.length && !o.force){ return f.split() } f.text = raw; f.write(); } @@ -273,129 +178,68 @@ if(u === o.start && u === o.end){ return tree } if(atomic(tree)){ return tree } var sub = Radix(); - Radix.map(tree, function(v,k){ // ONLY PLACE THAT TAKES TREE, maybe reduce API for better perf? - sub(k,v); - }, o); + Radix.map(tree, function(v,k){ sub(k,v) }, o); // ONLY PLACE THAT TAKES TREE, maybe reduce API for better perf? return sub(''); } ;(function(){ - var Q = {}; r.read = function(key, cb, o){ o = o || {}; - if(RAD && !o.next){ // cache - var S; LOG && (S = +new Date); - var val = RAD(key); - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'rad cached'); - //if(u !== val){ - //cb(u, val, o); - if(atomic(val)){ cb(u, val, o); return } - // if a node is requested and some of it is cached... the other parts might not be. - //} + var g = {key: key}; + g.find = function(file){ var tmp; + g.file = file || (file = opt.code.from); + if(tmp = r.disk[g.file = file]){ g.check(u, tmp); return } + r.parse(file, g.check); } - o.span = (u !== o.start) || (u !== o.end); // is there a start or end? - var g = function Get(){}; - g.lex = function(file){ var tmp; // // TODO: this had a out-of-memory crash! - file = (u === file)? u : decodeURIComponent(file); - tmp = o.next || key || (o.reverse? o.end || '\uffff' : o.start || ''); - if(!file || (o.reverse? file < tmp : file > tmp)){ - LOG && opt.log(S, +new Date - S, 'rad read lex'); S = +new Date; - if(o.next || o.reverse){ g.file = file } - if(tmp = Q[g.file]){ - tmp.push({key: key, ack: cb, file: g.file, opt: o}); - return true; - } - Q[g.file] = [{key: key, ack: cb, file: g.file, opt: o}]; - if(!g.file){ - g.it(null, u, {}); - return true; - } - r.parse(g.file, g.check); - return true; - } - g.file = file; - } - g.it = function(err, disk, info){ - if(g.err = err){ opt.log('err', err) } - if(!disk && g.file){ // corrupt file? - r.list.bad(g.file); // remove from dir list - r.read(key, cb, o); // look again + g.get = function(err, disk, info){ + if(g.err = err || g.err){ cb(err); return } + var file = g.file = (disk||'').file || g.file; + if(!disk && file !== opt.code.from){ // corrupt file? + r.find.bad(file); // remove from dir list + r.read(key, cb, o); // try again return; } - g.info = info; - if(disk){ RAD = g.disk = disk } - disk = Q[g.file]; delete Q[g.file]; - map(disk, g.ack); - } - g.ack = function(as){ - if(!as.ack){ return } - var S; LOG && (S = +new Date); - var key = as.key, o = as.opt, info = g.info, rad = g.disk || noop, data = r.range(rad(key), o), last = rad.last || Radix.map(rad, rev, revo); - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, "rad range loaded"); - o.parsed = (o.parsed || 0) + (info.parsed||0); + disk = r.disk[file] || (r.disk[file] = disk); + if(!disk){ cb("No file!"); return } + disk.file || (disk.file = file); + var data = r.range(disk(key), o); + o.unit = disk.unit; o.chunks = (o.chunks || 0) + 1; - o.more = true; - if((!as.file) // if no more places to look - || (!o.span && last === key) // if our key exactly matches the very last atomic record - || (!o.span && last && last > key && 0 != last.indexOf(key)) // 'zach' may be lexically larger than 'za', but there still might be more, like 'zane' in the 'za' prefix bucket so do not end here. - ){ - o.more = u; - as.ack(g.err, data, o); - return + o.parsed = (o.parsed || 0) + ((info||'').parsed||(o.chunks*opt.chunk)); + o.more = 1; + o.next = u; + Radix.map(r.list, function next(v,f){ + if(!v || file === f){ return } + o.next = f; + return 1; + }, o.reverse? {reverse: 1, end: file} : {start: file}); + if(!o.next){ o.more = 0 } + if(o.next){ + if(!o.reverse && (key < o.next && 0 != o.next.indexOf(key)) || (u !== o.end && (o.end || '\uffff') < o.next)){ o.more = 0 } + if(o.reverse && (key > o.next && 0 != key.indexOf(o.next)) || (u !== o.start && (o.start || '') > o.next)){ o.more = 0 } } - if(u !== data){ - as.ack(g.err, data, o); // more might be coming! - if(o.parsed >= o.limit){ return } // even if more, we've hit our limit, asking peer will need to make a new ask with a new starting point. - } - o.next = as.file; - r.read(key, as.ack, o); + if(!o.more){ cb(g.err, data, o); return } + if(data){ cb(g.err, data, o) } + if(o.parsed >= o.limit){ return } + r.parse(o.next, g.check); } g.check = function(err, disk, info){ - g.it(err, disk, info); - var good = true; + g.get(err, disk, info); + (info || (info = {})).file || (info.file = g.file); Radix.map(disk, function(val, key){ - // assume in memory for now, since both write/read already call r.list which will init it. - var go = function(file){ - if(info.file !== file){ - good = false - } - return true; - } - go.reverse = 1; - go.end = key; - r.list(go); - }); - if(good){ return } - var id = Gun.text.random(3); - r.save(disk, function ack(err, ok){ - if(err){ return r.save(disk, ack) } // ad infinitum??? - console.log("MISLOCATED DATA CORRECTED", id); + // assume in memory for now, since both write/read already call r.find which will init it. + r.find(key, function(file){ + if((file || (file = opt.code.from)) === info.file){ return } + var id = Gun.text.random(3); + console.log("MISLOCATED DATA", id, key, info.file, file); + r.save(key, val, function ack(err, ok){ + if(err){ r.save(key, val, ack); return } // ad infinitum??? + console.log("MISLOCATED DATA CORRECTED", id); + }); + }) }); } - /*g.check2 = function(err, disk, info){ - if(err || !disk){ return g.it(err, disk, info) } - var good = true; - Radix.map(disk, function(val, key){ - // assume in memory for now, since both write/read already call r.list which will init it. - var go = function(file){ - if(info.file !== file){ good = false } - return true; - } - go.reverse = 1; - go.end = key; - r.list(go); - }); - if(good){ return g.it(err, disk, info) } - var id = Gun.text.random(3); console.log("MISLOCATED DATA", id); - r.save(disk, function ack(err, ok){ - if(err){ return r.save(disk, ack) } // ad infinitum??? - console.log("MISLOCATED CORRECTED", id); - r.read(key, cb, o); - }); - }*/ - if(o.reverse){ g.lex.reverse = true } - LOG && (S = +new Date); - r.list(g.lex); + r.find(key, g.find); } function rev(a,b){ return b } var revo = {reverse: true}; @@ -409,18 +253,18 @@ with how much performance and scale we can get out of only one. Then we can work on the harder problem of being multi-process. */ + var RPC = 0; var Q = {}, s = String.fromCharCode(31); r.parse = function(file, cb, raw){ var q; - if(q = Q[file]){ return q.push(cb) } q = Q[file] = [cb]; - var p = function Parse(){}, info = {file: ename(file)}; - p.disk = Radix(); + if(!file){ return cb(); } + if(q = Q[file]){ q.push(cb); return } q = Q[file] = [cb]; + var p = function Parse(){}, info = {file: file}; + (p.disk = Radix()).file = file; p.read = function(err, data){ var tmp; - LOG && opt.log(S, +new Date - S, 'read disk', ename(file)); + LOG && opt.log(S, +new Date - S, 'read disk', JSON.stringify(file), ++RPC, 'total all parses.'); delete Q[file]; - if((p.err = err) || (p.not = !data)){ - return map(q, p.ack); - } - if(typeof data !== 'string'){ + if((p.err = err) || (p.not = !data)){ map(q, p.ack); return } + if('string' !== typeof data){ try{ if(opt.pack <= data.length){ p.err = "Chunk too big!"; @@ -428,12 +272,11 @@ data = data.toString(); // If it crashes, it crashes here. How!?? We check size first! } }catch(e){ p.err = e } - if(p.err){ return map(q, p.ack) } + if(p.err){ map(q, p.ack); return } } info.parsed = data.length; - LOG && (S = +new Date); - if(opt.jsonify || '{' === data[0]){ // temporary testing idea + if(opt.jsonify || '{' === data[0]){ try{ var json = JSON.parse(data); // TODO: this caused a out-of-memory crash! p.disk.$ = json; @@ -443,14 +286,27 @@ }catch(e){ tmp = e } if('{' === data[0]){ p.err = tmp || "JSON error!"; - return map(q, p.ack); + map(q, p.ack); + return; } } + p.radec(err, data); + } + p.ack = function(cb){ + if(!cb){ return } + if(p.err || p.not){ + cb(p.err, u, info); + return; + } + cb(u, p.disk, info); + } + p.radec = function(err, data){ LOG && (S = +new Date); var tmp = p.split(data), pre = [], i, k, v; if(!tmp || 0 !== tmp[1]){ p.err = "File '"+file+"' does not have root radix! "; - return map(q, p.ack); + map(q, p.ack); + return; } while(tmp){ k = v = u; @@ -470,7 +326,6 @@ tmp = p.split(tmp[2]); } LOG && opt.log(S, +new Date - S, 'parsed RAD'); - //cb(err, p.disk); map(q, p.ack); }; p.split = function(t){ @@ -484,75 +339,63 @@ l[2] = t.slice(i + o.i); return l; } - p.ack = function(cb){ - if(!cb){ return } - if(p.err || p.not){ return cb(p.err, u, info) } - cb(u, p.disk, info); - } var S; LOG && (S = +new Date); - if(raw){ return p.read(null, raw) } + if(r.disk){ raw || (raw = (r.disk[file]||'').raw) } + if(raw){ return p.read(u, raw) } opt.store.get(ename(file), p.read); } }()); ;(function(){ - var dir, q, f = String.fromCharCode(28), ef = ename(f); - r.list = function(cb){ - if(dir){ - var last, tmp = {reverse: (cb.reverse)? 1 : 0, start: cb.start, end: cb.end}; - Radix.map(dir, function(val, key){ - if(!val){ return } - return cb(last = key); - }, tmp) || cb(u, last); + var dir, f = String.fromCharCode(28), Q; + r.find = function(key, cb){ + if(!dir){ + if(Q){ Q.push([key, cb]); return } Q = [[key, cb]]; + r.parse(f, init); return; } - if(q){ return q.push(cb) } q = [cb]; - r.parse(f, r.list.init); + Radix.map(r.list = dir, function(val, key){ + if(!val){ return } + return cb(key) || true; + }, {reverse: 1, end: key}) || cb(opt.code.from); } - r.list.add = function(file, cb){ + r.find.add = function(file, cb){ var has = dir(file); - if(has || file === ef){ - return cb(u, 1); - } + if(has || file === f){ cb(u, 1); return } dir(file, 1); - cb.listed = (cb.listed || 0) + 1; + cb.found = (cb.found || 0) + 1; r.write(f, dir, function(err, ok){ - if(err){ return cb(err) } - cb.listed = (cb.listed || 0) - 1; - if(cb.listed !== 0){ return } + if(err){ cb(err); return } + cb.found = (cb.found || 0) - 1; + if(0 !== cb.found){ return } cb(u, 1); }, true); } - r.list.bad = function(file, cb){ - dir(ename(file), 0); + r.find.bad = function(file, cb){ + dir(file, 0); r.write(f, dir, cb||noop); } - r.list.init = function(err, disk){ + function init(err, disk){ if(err){ opt.log('list', err); - setTimeout(function(){ r.parse(f, r.list.init) }, 1000); - return; - } - if(disk){ - r.list.drain(disk); - return; - } - if(!opt.store.list){ - r.list.drain(Radix()); + setTimeout(function(){ r.parse(f, init) }, 1000); return; } + if(disk){ drain(disk); return } + dir = dir || disk || Radix(); + if(!opt.store.list){ drain(dir); return } // import directory. opt.store.list(function(file){ - dir = dir || Radix(); - if(!file){ return r.list.drain(dir) } - r.list.add(file, noop); + if(!file){ drain(dir); return } + r.find.add(file, noop); }); } - r.list.drain = function(rad, tmp){ - r.list.dir = dir = rad; - tmp = q; q = null; - Gun.list.map(tmp, function(cb){ - r.list(cb); + function drain(rad, tmp){ + dir = dir || rad; + dir.file = f; + tmp = Q; Q = null; + Gun.list.map(tmp, function(arg){ + r.find(arg[0], arg[1]); }); } }()); @@ -562,8 +405,6 @@ return r; } - - ;(function(){ var _ = String.fromCharCode(31), u; Radisk.encode = function(d, o, s){ s = s || _; diff --git a/lib/radiskip.js b/lib/radiskip.js deleted file mode 100644 index 325bbf3c..00000000 --- a/lib/radiskip.js +++ /dev/null @@ -1,600 +0,0 @@ -;(function(){ - - function Radisk(opt){ - - opt = opt || {}; - opt.log = opt.log || console.log; - opt.file = String(opt.file || 'radata'); - var has = (Radisk.has || (Radisk.has = {}))[opt.file]; - if(has){ return has } - - opt.pack = opt.pack || (opt.memory? (opt.memory * 1000 * 1000) : 1399000000) * 0.3; // max_old_space_size defaults to 1400 MB. - opt.until = opt.until || opt.wait || 250; - opt.batch = opt.batch || (10 * 1000); - opt.chunk = opt.chunk || (1024 * 1024 * 1); // 1MB - opt.code = opt.code || {}; - opt.code.from = opt.code.from || '!'; - opt.jsonify = true; - - function ename(t){ return encodeURIComponent(t).replace(/\*/g, '%2A') } - function atomic(v){ return u !== v && (!v || 'object' != typeof v) } - var map = Gun.obj.map; - var LOG = console.LOG; - var ST = 0; - - if(!opt.store){ - return opt.log("ERROR: Radisk needs `opt.store` interface with `{get: fn, put: fn (, list: fn)}`!"); - } - if(!opt.store.put){ - return opt.log("ERROR: Radisk needs `store.put` interface with `(file, data, cb)`!"); - } - if(!opt.store.get){ - return opt.log("ERROR: Radisk needs `store.get` interface with `(file, cb)`!"); - } - if(!opt.store.list){ - //opt.log("WARNING: `store.list` interface might be needed!"); - } - - /* - Any and all storage adapters should... - 1. Because writing to disk takes time, we should batch data to disk. This improves performance, and reduces potential disk corruption. - 2. If a batch exceeds a certain number of writes, we should immediately write to disk when physically possible. This caps total performance, but reduces potential loss. - */ - var r = function(key, data, cb){ - if('function' === typeof data){ - var o = cb || {}; - cb = data; - r.read(key, cb); - return; - } - //var tmp = (tmp = r.batch = r.batch || {})[key] = tmp[key] || {}; - //var tmp = (tmp = r.batch = r.batch || {})[key] = data; - r.save(key, data, cb); - } - r.save = function(key, data, cb){ - var s = {key: key}; - s.find = function(file){ var tmp; - s.file = file || (file = opt.code.from); - if(tmp = r.disk[file]){ s.mix(u, tmp); return } - r.parse(file, s.mix); - } - s.mix = function(err, disk){ - if(err){ cb(err); return } - var file = s.file = (disk||'').file || s.file; - if(!disk && file !== opt.code.from){ // corrupt file? - r.find.bad(file); // remove from dir list - r.save(key, data, cb); // try again - return; - } - (disk = r.disk[file] || (r.disk[file] = disk || Radix())).file || (disk.file = file); - if(opt.compare){ - data = opt.compare(disk(key), data, key, file); - if(u === data){ cb(err, -1); return } - } - (s.disk = disk)(key, data); - if(disk.Q){ disk.Q.push(cb); return } disk.Q = [cb]; - disk.to = setTimeout(s.write, opt.until); - } - s.write = function(){ - var file = s.file, disk = s.disk; - s.q = disk.Q; - delete disk.Q; - delete r.disk[file]; - r.write(file, disk, s.ack); - } - s.ack = function(err, ok){ - var q = s.q || [], i = 0, ack; - //var S = +new Date; - while(ack = q[i++]){ ack(err, ok) } - //console.log('acks:', +new Date - S, s.file, q.length); - } - r.find(key, s.find); - } - r.disk = {}; - - /* - Any storage engine at some point will have to do a read in order to write. - This is true of even systems that use an append only log, if they support updates. - Therefore it is unavoidable that a read will have to happen, - the question is just how long you delay it. - */ - var RWC = 0; - r.write = function(file, rad, cb, o){ - if(!rad){ cb('No radix!'); return } - o = ('object' == typeof o)? o : {force: o}; - var f = function Fractal(){}, a, b; - f.text = ''; - f.file = file = rad.file || (rad.file = file); - if(!file){ cb('What file?'); return } - f.write = function(){ - var text = rad.raw = f.text; - r.disk[file = rad.file || f.file || file] = rad; - var S; LOG && (S = +new Date); - r.find.add(file, function add(err){ - if(err){ cb(err); return } - opt.store.put(ename(file), text, function safe(err, ok){ - LOG && opt.log(S, ST = +new Date - S, "wrote disk", JSON.stringify(file), ++RWC, 'total all writes.'); - cb(err, ok || 1); - if(!rad.Q){ delete r.disk[file] } // VERY IMPORTANT! Clean up memory, but not if there is already queued writes on it! - }); - }); - } - f.split = function(){ - f.text = ''; - if(!f.count){ f.count = 0; - Radix.map(rad, function count(){ f.count++ }); // TODO: Perf? Any faster way to get total length? - } - f.limit = Math.ceil(f.count/2); - f.count = 0; - f.sub = Radix(); - Radix.map(rad, f.slice, {reverse: 1}); // IMPORTANT: DO THIS IN REVERSE, SO LAST HALF OF DATA MOVED TO NEW FILE BEFORE DROPPING FROM CURRENT FILE. - r.write(f.end, f.sub, f.both, o); - f.hub = Radix(); - Radix.map(rad, f.stop); - r.write(rad.file, f.hub, f.both, o); - return true; - } - f.slice = function(val, key){ - f.sub(f.end = key, val); - if(f.limit <= (++f.count)){ return true } - } - f.stop = function(val, key){ - if(key >= f.end){ return true } - f.hub(key, val); - } - f.both = function(err, ok){ - if(b){ cb(err || b); return } - if(a){ cb(err, ok); return } - a = true; - b = err; - } - f.each = function(val, key, k, pre){ - //console.log("RAD:::", JSON.stringify([val, key, k, pre])); - if(u !== val){ f.count++ } - if(opt.pack <= (val||'').length){ return cb("Record too big!"), true } - var enc = Radisk.encode(pre.length) +'#'+ Radisk.encode(k) + (u === val? '' : ':'+ Radisk.encode(val)) +'\n'; - if((opt.chunk < f.text.length + enc.length) && (1 < f.count) && !o.force){ - return f.split(); - } - f.text += enc; - } - if(opt.jsonify){ r.write.jsonify(f, rad, cb, o); return } // temporary testing idea - if(!Radix.map(rad, f.each, true)){ f.write() } - } - - r.write.jsonify = function(f, rad, cb, o){ - var raw; - var S; LOG && (S = +new Date); - try{raw = JSON.stringify(rad.$); - }catch(e){ cb("Cannot radisk!"); return } - LOG && opt.log(S, +new Date - S, "rad stringified JSON"); - if(opt.chunk < raw.length && !o.force){ return f.split() } - f.text = raw; - f.write(); - } - - r.range = function(tree, o){ - if(!tree || !o){ return } - if(u === o.start && u === o.end){ return tree } - if(atomic(tree)){ return tree } - var sub = Radix(); - Radix.map(tree, function(v,k){ sub(k,v) }, o); // ONLY PLACE THAT TAKES TREE, maybe reduce API for better perf? - return sub(''); - } - - ;(function(){ - var Q = {}; - r.read = function(key, cb, o){ - o = o || {}; - if(RAD && !o.next){ // cache - var S; LOG && (S = +new Date); - var val = RAD(key); - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'rad cached'); - //if(u !== val){ - //cb(u, val, o); - if(atomic(val)){ cb(u, val, o); return } - // if a node is requested and some of it is cached... the other parts might not be. - //} - } - o.span = (u !== o.start) || (u !== o.end); // is there a start or end? - var g = function Get(){}; - g.lex = function(file){ var tmp; // // TODO: this had a out-of-memory crash! - file = (u === file)? u : decodeURIComponent(file); - tmp = o.next || key || (o.reverse? o.end || '\uffff' : o.start || ''); - if(!file || (o.reverse? file < tmp : file > tmp)){ - LOG && opt.log(S, +new Date - S, 'rad read lex'); S = +new Date; - if(o.next || o.reverse){ g.file = file } - if(tmp = Q[g.file]){ - tmp.push({key: key, ack: cb, file: g.file, opt: o}); - return true; - } - Q[g.file] = [{key: key, ack: cb, file: g.file, opt: o}]; - if(!g.file){ - g.it(u, u, {}); - return true; - } - r.parse(g.file, g.check); - return true; - } - g.file = file; - } - g.it = function(err, disk, info){ - if(g.err = err){ opt.log('err', err) } - if(!disk && g.file){ // corrupt file? - r.find.bad(g.file); // remove from dir list - r.read(key, cb, o); // look again - return; - } - g.info = info; - if(disk){ RAD = g.disk = disk } - disk = Q[g.file]; delete Q[g.file]; - map(disk, g.ack); - } - g.ack = function(as){ - if(!as.ack){ return } - var S; LOG && (S = +new Date); - var key = as.key, o = as.opt, info = g.info, rad = g.disk || noop, data = r.range(rad(key), o), last = rad.last || Radix.map(rad, rev, revo); - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, "rad range loaded"); - o.parsed = (o.parsed || 0) + (info.parsed||0); - o.chunks = (o.chunks || 0) + 1; - o.more = true; - if((!as.file) // if no more places to look - || (!o.span && last === key) // if our key exactly matches the very last atomic record - || (!o.span && last && last > key && 0 != last.indexOf(key)) // 'zach' may be lexically larger than 'za', but there still might be more, like 'zane' in the 'za' prefix bucket so do not end here. - ){ - o.more = u; - as.ack(g.err, data, o); - return; - } - if(u !== data){ - as.ack(g.err, data, o); // more might be coming! - if(o.parsed >= o.limit){ return } // even if more, we've hit our limit, asking peer will need to make a new ask with a new starting point. - } - o.next = as.file; - r.read(key, as.ack, o); - } - g.check = function(err, disk, info){ - g.it(err, disk, info); - var good = true; - Radix.map(disk, function(val, key){ - // assume in memory for now, since both write/read already call r.find which will init it. - var go = function(file){ - if(info.file !== file){ - good = false - } - return true; - } - go.reverse = 1; - go.end = key; - r.list(go); - }); - if(good){ return } - var id = Gun.text.random(3); - r.save(disk, function ack(err, ok){ - if(err){ r.save(disk, ack); return } // ad infinitum??? - console.log("MISLOCATED DATA CORRECTED", id); - }); - } - /*g.check2 = function(err, disk, info){ - if(err || !disk){ g.it(err, disk, info); return } - var good = true; - Radix.map(disk, function(val, key){ - // assume in memory for now, since both write/read already call r.find which will init it. - var go = function(file){ - if(info.file !== file){ good = false } - return true; - } - go.reverse = 1; - go.end = key; - r.list(go); - }); - if(good){ g.it(err, disk, info); return } - var id = Gun.text.random(3); console.log("MISLOCATED DATA", id); - r.save(disk, function ack(err, ok){ - if(err){ r.save(disk, ack); return } // ad infinitum??? - console.log("MISLOCATED CORRECTED", id); - r.read(key, cb, o); - }); - }*/ - if(o.reverse){ g.lex.reverse = true } - LOG && (S = +new Date); - r.find(key, g.lex); - } - - r.read = function(key, cb, o){ - var g = {key: key}; - g.find = function(file){ var tmp; - g.file = file || (file = opt.code.from); // this may not be true for reads? Hit "end of dir"? - if(tmp = r.disk[file]){ g.check(u, tmp); return } - r.parse(file, g.check); - } - g.get = function(err, disk, info){ - if(err){ cb(err); return } - var file = g.file = (disk||'').file || g.file; - if(!disk && file !== opt.code.from){ // corrupt file? - r.find.bad(file); // remove from dir list - r.save(key, cb); // try again - return; - } - disk = r.disk[file] || (r.disk[file] = disk); - if(!disk){ cb(); return } - disk.file || (disk.file = file); - // ---------------------------- - info = info || {}; - var data = disk(key); - info.atom = disk.atom; - if(u !== data){ cb(u, data, info); return } - // ---------------------------- - return; - var S; LOG && (S = +new Date); - var rad = disk || noop, data = r.range(rad(key), o), last = rad.last || Radix.map(rad, rev, revo); - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, "rad range loaded"); - o.parsed = (o.parsed || 0) + (info.parsed||0); - o.chunks = (o.chunks || 0) + 1; - o.more = true; - if((!as.file) // if no more places to look - || (!o.span && last === key) // if our key exactly matches the very last atomic record - || (!o.span && last && last > key && 0 != last.indexOf(key)) // 'zach' may be lexically larger than 'za', but there still might be more, like 'zane' in the 'za' prefix bucket so do not end here. - ){ - o.more = u; - as.ack(g.err, data, o); - return; - } - if(u !== data){ - as.ack(g.err, data, o); // more might be coming! - if(o.parsed >= o.limit){ return } // even if more, we've hit our limit, asking peer will need to make a new ask with a new starting point. - } - o.next = as.file; - r.read(key, as.ack, o); - } - g.check = function(err, disk, info){ - g.get(err, disk, info); - (info || (info = {})).file || (info.file = g.file); - Radix.map(disk, function(val, key){ - // assume in memory for now, since both write/read already call r.find which will init it. - r.find(key, function(file){ - if(file === info.file){ return } - var id = Gun.text.random(3); - console.log("MISLOCATED DATA", id, key, info.file, file); - r.save(key, val, function ack(err, ok){ - if(err){ r.save(key, val, ack); return } // ad infinitum??? - console.log("MISLOCATED DATA CORRECTED", id); - }); - }) - }); - } - r.find(key, g.find); - } - function rev(a,b){ return b } - var revo = {reverse: true}; - }()); - - ;(function(){ - /* - Let us start by assuming we are the only process that is - changing the directory or bucket. Not because we do not want - to be multi-process/machine, but because we want to experiment - with how much performance and scale we can get out of only one. - Then we can work on the harder problem of being multi-process. - */ - var RPC = 0; - var Q = {}, s = String.fromCharCode(31); - r.parse = function(file, cb, raw){ var q; - if(q = Q[file]){ q.push(cb); return } q = Q[file] = [cb]; - var p = function Parse(){}, info = {file: file}; - (p.disk = Radix()).file = file; - p.read = function(err, data){ var tmp; - LOG && opt.log(S, +new Date - S, 'read disk', JSON.stringify(file), ++RPC, 'total all parses.'); - delete Q[file]; - if((p.err = err) || (p.not = !data)){ map(q, p.ack); return } - if('string' !== typeof data){ - try{ - if(opt.pack <= data.length){ - p.err = "Chunk too big!"; - } else { - data = data.toString(); // If it crashes, it crashes here. How!?? We check size first! - } - }catch(e){ p.err = e } - if(p.err){ map(q, p.ack); return } - } - info.parsed = data.length; - LOG && (S = +new Date); - if(opt.jsonify || '{' === data[0]){ - try{ - var json = JSON.parse(data); // TODO: this caused a out-of-memory crash! - p.disk.$ = json; - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'rad parsed JSON'); - map(q, p.ack); - return; - }catch(e){ tmp = e } - if('{' === data[0]){ - p.err = tmp || "JSON error!"; - map(q, p.ack); - return; - } - } - p.radec(err, data); - } - p.ack = function(cb){ - if(!cb){ return } - if(p.err || p.not){ - cb(p.err, u, info); - return; - } - cb(u, p.disk, info); - } - p.radec = function(err, data){ - LOG && (S = +new Date); - var tmp = p.split(data), pre = [], i, k, v; - if(!tmp || 0 !== tmp[1]){ - p.err = "File '"+file+"' does not have root radix! "; - map(q, p.ack); - return; - } - while(tmp){ - k = v = u; - i = tmp[1]; - tmp = p.split(tmp[2])||''; - if('#' == tmp[0]){ - k = tmp[1]; - pre = pre.slice(0,i); - if(i <= pre.length){ - pre.push(k); - } - } - tmp = p.split(tmp[2])||''; - if('\n' == tmp[0]){ continue } - if('=' == tmp[0] || ':' == tmp[0]){ v = tmp[1] } - if(u !== k && u !== v){ p.disk(pre.join(''), v) } - tmp = p.split(tmp[2]); - } - LOG && opt.log(S, +new Date - S, 'parsed RAD'); - map(q, p.ack); - }; - p.split = function(t){ - if(!t){ return } - var l = [], o = {}, i = -1, a = '', b, c; - i = t.indexOf(s); - if(!t[i]){ return } - a = t.slice(0, i); - l[0] = a; - l[1] = b = Radisk.decode(t.slice(i), o); - l[2] = t.slice(i + o.i); - return l; - } - var S; LOG && (S = +new Date); - if(r.disk){ raw || (raw = (r.disk[file]||'').raw) } - if(raw){ return p.read(u, raw) } - opt.store.get(ename(file), p.read); - } - }()); - - ;(function(){ - var dir, f = String.fromCharCode(28), Q; - r.find = function(key, cb){ - if(!dir){ - if(Q){ Q.push([key, cb]); return } Q = [[key, cb]]; - r.parse(f, init); - return; - } - Radix.map(dir, function(val, key){ - if(!val){ return } - return cb(key) || true; - }, {reverse: 1, end: key}) || cb(); - } - r.find.add = function(file, cb){ - var has = dir(file); - if(has || file === f){ cb(u, 1); return } - dir(file, 1); - cb.found = (cb.found || 0) + 1; - r.write(f, dir, function(err, ok){ - if(err){ cb(err); return } - cb.found = (cb.found || 0) - 1; - if(0 !== cb.found){ return } - cb(u, 1); - }, true); - } - r.find.bad = function(file, cb){ - dir(file, 0); - r.write(f, dir, cb||noop); - } - function init(err, disk){ - if(err){ - opt.log('list', err); - setTimeout(function(){ r.parse(f, init) }, 1000); - return; - } - if(disk){ drain(disk); return } - dir = dir || disk || Radix(); - if(!opt.store.list){ drain(dir); return } - // import directory. - opt.store.list(function(file){ - if(!file){ drain(dir); return } - r.find.add(file, noop); - }); - } - function drain(rad, tmp){ - dir = dir || rad; - dir.file = f; - tmp = Q; Q = null; - Gun.list.map(tmp, function(arg){ - r.find(arg[0], arg[1]); - }); - } - }()); - - var noop = function(){}, RAD, u; - Radisk.has[opt.file] = r; - return r; - } - - ;(function(){ - var _ = String.fromCharCode(31), u; - Radisk.encode = function(d, o, s){ s = s || _; - var t = s, tmp; - if(typeof d == 'string'){ - var i = d.indexOf(s); - while(i != -1){ t += s; i = d.indexOf(s, i+1) } - return t + '"' + d + s; - } else - if(d && d['#'] && (tmp = Gun.val.link.is(d))){ - return t + '#' + tmp + t; - } else - if(Gun.num.is(d)){ - return t + '+' + (d||0) + t; - } else - if(null === d){ - return t + ' ' + t; - } else - if(true === d){ - return t + '+' + t; - } else - if(false === d){ - return t + '-' + t; - }// else - //if(binary){} - } - Radisk.decode = function(t, o, s){ s = s || _; - var d = '', i = -1, n = 0, c, p; - if(s !== t[0]){ return } - while(s === t[++i]){ ++n } - p = t[c = n] || true; - while(--n >= 0){ i = t.indexOf(s, i+1) } - if(i == -1){ i = t.length } - d = t.slice(c+1, i); - if(o){ o.i = i+1 } - if('"' === p){ - return d; - } else - if('#' === p){ - return Gun.val.link.ify(d); - } else - if('+' === p){ - if(0 === d.length){ - return true; - } - return parseFloat(d); - } else - if(' ' === p){ - return null; - } else - if('-' === p){ - return false; - } - } - }()); - - if(typeof window !== "undefined"){ - var Gun = window.Gun; - var Radix = window.Radix; - window.Radisk = Radisk; - } else { - var Gun = require('../gun'); - var Radix = require('./radix'); - //var Radix = require('./radix2'); Radisk = require('./radisk2'); - try{ module.exports = Radisk }catch(e){} - } - - Radisk.Radix = Radix; - -}()); \ No newline at end of file diff --git a/lib/radix.js b/lib/radix.js index f33bc4b3..1d28b46a 100644 --- a/lib/radix.js +++ b/lib/radix.js @@ -2,13 +2,13 @@ function Radix(){ var radix = function(key, val, t){ - radix.atom = 0; + radix.unit = 0; if(!t && u !== val){ radix.last = (''+key < radix.last)? radix.last : ''+key; delete (radix.$||{})[_]; } t = t || radix.$ || (radix.$ = {}); - if(!key && Object.keys(t).length){ console.log('wat?', t, key); return t } + if(!key && Object.keys(t).length){ return t } key = ''+key; var i = 0, l = key.length-1, k = key[i], at, tmp; while(!(at = t[k]) && i < l){ @@ -48,7 +48,7 @@ } else if(i == l){ //if(u === val){ return (u === (tmp = at['']))? at : tmp } // THIS CODE IS CORRECT, below is - if(u === val){ return (u === (tmp = at['']))? at : ((radix.atom = 1) && tmp) } // temporary help?? + if(u === val){ return (u === (tmp = at['']))? at : ((radix.unit = 1) && tmp) } // temporary help?? at[''] = val; //(at[_] = function $(){ $.sort = Object.keys(at).sort(); return $ }()); } else { diff --git a/lib/rfs.js b/lib/rfs.js index 705ae88a..f66ddb4c 100644 --- a/lib/rfs.js +++ b/lib/rfs.js @@ -12,6 +12,7 @@ function Store(opt){ Store[opt.file] = store; var puts = {}; + // TODO!!! ADD ZLIB INFLATE / DEFLATE COMPRESSION! store.put = function(file, data, cb){ puts[file] = data; var random = Math.random().toString(36).slice(-3); @@ -29,7 +30,7 @@ function Store(opt){ if('ENOENT' === (err.code||'').toUpperCase()){ return cb(); } - opt.log("ERROR:", err) + opt.log("ERROR:", err); } cb(err, data); }); diff --git a/lib/store.js b/lib/store.js index 1ca48d89..4e17c809 100644 --- a/lib/store.js +++ b/lib/store.js @@ -6,13 +6,11 @@ Gun.on('create', function(root){ var opt = root.opt, empty = {}, u; if(false === opt.radisk){ return } var Radisk = (Gun.window && Gun.window.Radisk) || require('./radisk'); - var Radiskip = (Gun.window && Gun.window.Radisk) || require('./radiskip'); var Radix = Radisk.Radix; var LOG = console.LOG, ST = 0; opt.store = opt.store || (!Gun.window && require('./rfs')(opt)); - var rad = Radisk(opt), esc = String.fromCharCode(27); - var dare = Radiskip(opt); + var dare = Radisk(opt), esc = String.fromCharCode(27); root.on('put2', function(msg){ this.to.next(msg); @@ -31,8 +29,7 @@ Gun.on('create', function(root){ var _ = (msg._||''), got = _.rad; if(got){ return } // RAD's own ACKs to GETs do not need to be written to disk again. if(_.ram){ return } // in-memory ACKs to GETs do not need to be written to disk again. - root.on('in', {'@': msg['#'], err: 'Migration not done, please report this to & complain at Mark in http://chat.gun.eco !'}); - return; + if(true || !Gun.TESTING){ root.on('in', {'@': msg['#'], err: console.log('Migration not done, please report this to & complain at Mark in http://chat.gun.eco !')}); return } var S = (+new Date), C = 0; // STATS! var now = Gun.state(); Gun.graph.is(msg.put, null, function(val, key, node, soul){ @@ -45,9 +42,9 @@ Gun.on('create', function(root){ return; } if(track){ ++acks } - //console.log('put:', soul, key, val); - val = Radisk.encode(val, null, esc)+'>'+Radisk.encode(Gun.state.is(node, key), null, esc); - rad(soul+esc+key, val, (track? ack : u)); + dare(soul+esc+key, {':': val, '>': Gun.state.is(node, key)}, (track? ack : u)); + //val = Radisk.encode(val, null, esc)+'>'+Radisk.encode(Gun.state.is(node, key), null, esc); + //rad(soul+esc+key, val, (track? ack : u)); C++; }); if(LOG && (ST = +new Date - S) > 9){ Gun.log(S, ST, 'put loop'); Gun.log(S, C, 'put loop #') } @@ -107,16 +104,18 @@ Gun.on('create', function(root){ var now = Gun.state(); var S = (+new Date), C = 0; // STATS! //rad(key||'', function(err, data, o){ + //console.log("STORE GET:", JSON.stringify(key||''), o); dare(key||'', function(err, data, info){ + //console.log("STORE GOT:", data); try{opt.store.stats.get.time[statg % 50] = (+new Date) - S; ++statg; opt.store.stats.get.count++; if(err){ opt.store.stats.get.err = err } }catch(e){} // STATS! //if(u === data && info.chunks > 1){ return } // if we already sent a chunk, ignore ending empty responses. // this causes tests to fail. LOG && Gun.log(S, +new Date - S, 'got', JSON.stringify(key)); S = +new Date; - info = info || {}; + info = info || ''; var va, ve; - if(info.atom && data && u !== (va = data[':']) && u !== (ve = data['>'])){ // new format + if(info.unit && data && u !== (va = data[':']) && u !== (ve = data['>'])){ // new format var tmp = key.split(esc), so = tmp[0], ha = tmp[1]; (graph = graph || {})[so] = Gun.state.ify(graph[so], ha, ve, va, so); root.$.get(so).get(ha)._.rad = now; @@ -134,7 +133,6 @@ Gun.on('create', function(root){ } console.STAT && (console.STAT.radgetcount = C); if(LOG && (ST = +new Date - S) > 9){ Gun.log(S, ST, 'got prep time'); Gun.log(S, C, 'got prep #') } C = 0; S = +new Date; - //console.log("STORE GOT:", graph); var faith = function(){}; faith.faith = true; faith.rad = get; // HNPERF: We're testing performance improvement by skipping going through security again, but this should be audited. root.on('in', {'@': id, put: graph, '%': info.more? 1 : u, err: err? err : u, _: faith}); LOG && (ST = +new Date - S) > 9 && Gun.log(S, ST, 'got emit', Object.keys(graph||{}).length); @@ -150,8 +148,11 @@ Gun.on('create', function(root){ has = has.slice(-1)[0]; if(o.limit && o.limit <= o.count){ return true } var va, ve, so = soul, ha = has; - if((va = val[':']) && (ve = val['>'])){ // THIS HANDLES NEW CODE! + //if(u !== (va = val[':']) && u !== (ve = val['>'])){ // THIS HANDLES NEW CODE! + if('string' != typeof val){ // THIS HANDLES NEW CODE! + va = val[':']; ve = val['>']; (graph = graph || {})[so] = Gun.state.ify(graph[so], ha, ve, va, so); + //root.$.get(so).get(ha)._.rad = now; o.count = (o.count || 0) + ((va||'').length || 9); return; } diff --git a/sea.js b/sea.js index 3730fc21..7c062d12 100644 --- a/sea.js +++ b/sea.js @@ -439,7 +439,7 @@ opt = opt || {}; // SEA.I // verify is free! Requires no user permission. var pub = pair.pub || pair; - var key = SEA.opt.slow_leak? await SEA.opt.slow_leak(pub) : await (shim.ossl || shim.subtle).importKey('jwk', jwk, {name: 'ECDSA', namedCurve: 'P-256'}, false, ['verify']); + var key = SEA.opt.slow_leak? await SEA.opt.slow_leak(pub) : await (shim.ossl || shim.subtle).importKey('jwk', S.jwk(pub), {name: 'ECDSA', namedCurve: 'P-256'}, false, ['verify']); var hash = await sha(json.m); var buf, sig, check, tmp; try{ buf = shim.Buffer.from(json.s, opt.encode || 'base64'); // NEW DEFAULT! @@ -474,9 +474,11 @@ return knownKeys[pair]; }; - + var O = SEA.opt; SEA.opt.fall_verify = async function(data, pair, cb, opt, f){ if(f === SEA.opt.fallback){ throw "Signature did not match" } f = f || 1; + var tmp = data||''; + data = SEA.opt.unpack(data) || data; var json = S.parse(data), pub = pair.pub || pair, key = await SEA.opt.slow_leak(pub); var hash = (f <= SEA.opt.fallback)? shim.Buffer.from(await shim.subtle.digest({name: 'SHA-256'}, new shim.TextEncoder().encode(S.parse(json.m)))) : await sha(json.m); // this line is old bad buggy code but necessary for old compatibility. var buf; var sig; var check; try{ @@ -491,6 +493,7 @@ if(!check){ throw "Signature did not match." } } var r = check? S.parse(json.m) : u; + O.fall_soul = tmp['#']; O.fall_key = tmp['.']; O.fall_val = data; O.fall_state = tmp['>']; if(cb){ try{ cb(r) }catch(e){console.log(e)} } return r; } @@ -1099,7 +1102,7 @@ if(!at.sea){ // only add SEA once per instance, on the "at" context. at.sea = {own: {}}; at.on('in', security, at); // now listen to all input data, acting as a firewall. - at.on('out', signature, at); // and output listeners, to encrypt outgoing data. + //at.on('out', signature, at); // and output listeners, to encrypt outgoing data. at.on('node', each, at); at.on('put2', check, at); } @@ -1165,10 +1168,11 @@ if('~@' === soul.slice(0,2)){ // special case for shared system data, the list of public keys for an alias. check.pubs(eve, msg, val, key, soul, at, no); return; } - if('~' === soul.slice(0,1) && 2 === (tmp = soul.slice(1)).split('.').length){ // special case, account data for a public key. - check.pub(eve, msg, val, key, soul, at, no, (msg._||'').user, tmp); return; + //if('~' === soul.slice(0,1) && 2 === (tmp = soul.slice(1)).split('.').length){ // special case, account data for a public key. + if(tmp = SEA.opt.pub(soul)){ // special case, account data for a public key. + check.pub(eve, msg, val, key, soul, at, no, at.user||'', tmp); return; } - check.any(eve, msg, val, key, soul, at, no, (msg._||'noop').user); return; + check.any(eve, msg, val, key, soul, at, no, at.user||''); return; eve.to.next(msg); // not handled } check.hash = function(eve, msg, val, key, soul, at, no){ @@ -1192,59 +1196,34 @@ if(val === pub){ return eve.to.next(msg) } // the account MUST match `pub` property that equals the ID of the public key. return no("Account not same!"); } - if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){ - SEA.sign(msg.put, (user._).sea, function(data){ var rel; + if((tmp = user.is) && pub === tmp.pub){ + SEA.sign(SEA.opt.pack(msg.put), (user._).sea, function(data){ if(u === data){ return no(SEA.err || 'Signature fail.') } - if(rel = link_is(val)){ (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = 1 } - console.log("WHAT HAPPENS HERE?", data.m, SEA.opt.unpack(data.m), key, soul); - msg.put[':'] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); - //node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); + if(tmp = link_is(val)){ (at.sea.own[tmp] = at.sea.own[tmp] || {})[pub] = 1 } + msg.put[':'] = JSON.stringify({':': tmp = SEA.opt.unpack(data.m), '~': data.s}); + msg.put['='] = tmp; eve.to.next(msg); - }, {check: msg.put, raw: 1}); + }, {raw: 1}); return; } - SEA.verify(msg.put, pub, function(data){ var rel, tmp; - console.log("WHAT VERIFIES HERE?", data, SEA.opt.unpack(data, key), key, soul); - data = SEA.opt.unpack(data, key); + SEA.verify(SEA.opt.pack(msg.put), pub, function(data){ var tmp; + data = SEA.opt.unpack(data); if(u === data){ return no("Unverified data.") } // make sure the signature matches the account it claims to be on. // reject any updates that are signed with a mismatched account. - if((rel = link_is(data)) && pub === SEA.opt.pub(rel)){ - (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = 1; - } + if((tmp = link_is(data)) && pub === SEA.opt.pub(tmp)){ (at.sea.own[tmp] = at.sea.own[tmp] || {})[pub] = 1 } + msg.put['='] = data; eve.to.next(msg); }); }; check.any = function(eve, msg, val, key, soul, at, no, user){ var tmp, pub; - if(!(pub = SEA.opt.pub(soul))){ - if(at.opt.secure){ return no("Soul missing public key at '" + key + "'.") } - // TODO: Ask community if should auto-sign non user-graph data. - at.on('secure', function(msg){ this.off(); - if(!at.opt.secure){ return eve.to.next(msg) } - no("Data cannot be changed."); - }).on.on('secure', msg); - return; - } - // TODO: DEDUP WITH check.pub ??? - if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){ - SEA.sign(mgs.put, (user._).sea, function(data){ - if(u === data){ return no('User signature fail.') } - console.log("WHAT HAPPENS HERE??", data.m, SEA.opt.unpack(data.m), key, soul); - msg.put[':'] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); - //node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); - eve.to.next(msg); - }, {check: msg.put, raw: 1}); - return; - } - SEA.verify(msg.put, pub, function(data){ var rel; - console.log("WHAT VERIFIES HERE?", data, SEA.opt.unpack(data, key), key, soul); - data = SEA.opt.unpack(data, key); - if(u === data){ return no("Not owner on '" + key + "'.") } // thanks @rogowski ! - if((rel = link_is(data)) && pub === SEA.opt.pub(rel)){ - (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = 1; - } - eve.to.next(msg); - }); + if(at.opt.secure){ return no("Soul missing public key at '" + key + "'.") } + // TODO: Ask community if should auto-sign non user-graph data. + at.on('secure', function(msg){ this.off(); + if(!at.opt.secure){ return eve.to.next(msg) } + no("Data cannot be changed."); + }).on.on('secure', msg); + return; } - var link_is = Gun.val.link.is; + var link_is = Gun.val.link.is, state_ify = Gun.state.ify; // okay! The security function handles all the heavy lifting. // It needs to deal read and write of input and output of system data, account/public key data, and regular data. @@ -1408,6 +1387,7 @@ if(!s || !(s = s[1])){ return } s = s.split('.'); if(!s || 2 > s.length){ return } + if('@' === (s[0]||'')[0]){ return } // TODO: Should check ~X.Y. are alphanumeric, not just not @. s = s.slice(0,2).join('.'); return s; } @@ -1416,16 +1396,18 @@ } SEA.opt.pack = function(d,k, n,s){ // pack for verifying if(SEA.opt.check(d)){ return d } - var meta = (Gun.obj.ify(d)||noop), sig = meta['~']; - return sig? {m: {'#':s,'.':k,':':meta[':'],'>':Gun.state.is(n, k)}, s: sig} : d; + var meta = (Gun.obj.ify(d)||''), sig = meta['~']; + return sig? {m: {'#':s||d['#'],'.':k||d['.'],':':meta[':'],'>':d['>']||Gun.state.is(n, k)}, s: sig} : d; } + var O = SEA.opt; SEA.opt.unpack = function(d, k, n){ var tmp; if(u === d){ return } if(d && (u !== (tmp = d[':']))){ return tmp } + k = k || O.fall_key; if(!n && O.fall_val){ n = {}; n[k] = O.fall_val } if(!k || !n){ return } if(d === n[k]){ return d } if(!SEA.opt.check(n[k])){ return d } - var soul = Gun.node.soul(n), s = Gun.state.is(n, k); + var soul = Gun.node.soul(n) || O.fall_soul, s = Gun.state.is(n, k) || O.fall_state; if(d && 4 === d.length && soul === d[0] && k === d[1] && fl(s) === fl(d[3])){ return d[2]; } @@ -1437,6 +1419,7 @@ var noop = function(){}, u; var fl = Math.floor; // TODO: Still need to fix inconsistent state issue. var rel_is = Gun.val.rel.is; + var obj_ify = Gun.obj.ify; // TODO: Potential bug? If pub/priv key starts with `-`? IDK how possible. })(USE, './index'); diff --git a/test/common.js b/test/common.js index 91f6615b..1cf70726 100644 --- a/test/common.js +++ b/test/common.js @@ -1279,6 +1279,14 @@ describe('Gun', function(){ this.to.next(root); });*/ } + Gun.on('create', function(root){ + root.on('test', function(msg){ + var put = msg.put; + this.to.next(msg); + root.on('out', msg); + Gun.graph.is(put, function(n,s){ root.$.get(s).off() }); + }) + }) var gun = Gun(); it.skip('gun chain separation', function(done){ // TODO: UNDO! @@ -1397,8 +1405,7 @@ describe('Gun', function(){ - Performant read lock on write contexts. - Proxying event across maps. */ - var s = Gun.state.map();s.soul = 'u/m'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "Alice", @@ -1409,7 +1416,7 @@ describe('Gun', function(){ name: "Bob!", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m')}); var check = {}, count = {}; gun.get('u/m').map().on(function(v,f){ check[f] = v; @@ -1433,8 +1440,7 @@ describe('Gun', function(){ }); it('uncached synchronous map get on', function(done){ - var s = Gun.state.map();s.soul = 'u/m/p'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "alice", @@ -1445,7 +1451,7 @@ describe('Gun', function(){ name: "bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/p')}); var check = {}, count = {}; gun.get('u/m/p').map().get('name').on(function(v,f){ //console.log("*****************", f, v); @@ -1465,8 +1471,7 @@ describe('Gun', function(){ }); it('uncached synchronous map get on node', function(done){ - var s = Gun.state.map();s.soul = 'u/m/p/n'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "alice", @@ -1477,7 +1482,7 @@ describe('Gun', function(){ name: "bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/p/n')}); var check = {}, count = {}; gun.get('u/m/p/n').map().get('pet').on(function(v,f){ //console.log("********************", f,v); @@ -1500,8 +1505,7 @@ describe('Gun', function(){ it('uncached synchronous map get on node get', function(done){ var gun = Gun(); - var s = Gun.state.map();s.soul = 'u/m/p/n/p'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "alice", @@ -1512,7 +1516,7 @@ describe('Gun', function(){ name: "bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/p/n/p')}); var check = {}, count = {}; //console.debug.i=1;console.log('-------------------'); gun.get('u/m/p/n/p').map().get('pet').get('name').on(function(v,f){ @@ -1539,8 +1543,7 @@ describe('Gun', function(){ }); it('uncached synchronous map on mutate', function(done){ - var s = Gun.state.map();s.soul = 'u/m/mutate'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "Alice", @@ -1551,7 +1554,7 @@ describe('Gun', function(){ name: "Bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/mutate')}); var check = {}, count = {}; gun.get('u/m/mutate').map().get('name').get(function(at,ev){ var e = at.err, v = at.put, f = at.get; @@ -1575,8 +1578,7 @@ describe('Gun', function(){ }); it('uncached synchronous map on mutate node', function(done){ - var s = Gun.state.map();s.soul = 'u/m/mutate/n'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: {_:{'#':'umaliceo'}, age: 26, name: "Alice", @@ -1587,7 +1589,7 @@ describe('Gun', function(){ name: "Bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/mutate/n')}); var check = {}, count = {}; gun.get('u/m/mutate/n').map().get('name').get(function(at,ev){ var e = at.err, v = at.put, f = at.get; @@ -1622,8 +1624,7 @@ describe('Gun', function(){ }); it('uncached synchronous map on mutate node uncached', function(done){ - var s = Gun.state.map();s.soul = 'u/m/mutate/n/u'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: {_:{'#':'umaliceo1'}, age: 26, name: "Alice", @@ -1634,7 +1635,7 @@ describe('Gun', function(){ name: "Bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/mutate/n/u')}); var check = {}, count = {}; gun.get('u/m/mutate/n/u').map().on(function(v,f){ check[v.name] = f; @@ -1654,10 +1655,9 @@ describe('Gun', function(){ } }); setTimeout(function(){ - var s = Gun.state.map();s.soul = 'u/m/m/n/u/soul'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ name: 'Alice Zzxyz' - }, s)}); + }, Gun.state.map(), 'u/m/m/n/u/soul')}); //console.debug.i=1;console.log("---------------"); gun.get('u/m/mutate/n/u').put({ alice: {'#':'u/m/m/n/u/soul'}, @@ -1679,8 +1679,7 @@ describe('Gun', function(){ }); it('uncached synchronous map on get mutate node uncached', function(done){ - var s = Gun.state.map();s.soul = 'u/m/p/mutate/n/u'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: {_:{'#':'umaliceo2'}, age: 26, name: "Alice", @@ -1691,7 +1690,7 @@ describe('Gun', function(){ name: "Bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/p/mutate/n/u')}); var check = {}, count = {}; gun.get('u/m/p/mutate/n/u').map().get('name').on(function(v,f){ check[v] = f; @@ -1712,10 +1711,9 @@ describe('Gun', function(){ } }); setTimeout(function(){ - var s = Gun.state.map();s.soul = 'u/m/p/m/n/u/soul'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ name: 'Alice Zzxyz', age: 34 - }, s)}); + }, Gun.state.map(), 'u/m/p/m/n/u/soul')}); gun.get('u/m/p/mutate/n/u').put({ alice: {'#':'u/m/p/m/n/u/soul'}, }); @@ -1729,8 +1727,7 @@ describe('Gun', function(){ }); it('uncached synchronous map on get node mutate node uncached', function(done){ - var s = Gun.state.map();s.soul = 'u/m/p/n/mutate/n/u'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: {_:{'#':'umaliceo3'}, age: 26, name: "Alice", @@ -1741,7 +1738,7 @@ describe('Gun', function(){ name: "Bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/p/n/mutate/n/u')}); var check = {}, count = {}; gun.get('u/m/p/n/mutate/n/u').map().get('pet').on(function(v,f){ check[v.name] = f; @@ -1760,11 +1757,10 @@ describe('Gun', function(){ } }); setTimeout(function(){ - var s = Gun.state.map();s.soul = 'alice/fuzz/soul'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ name: 'Alice Zzxyz', age: 34, pet: {c:3, name: "Fuzzball"} - }, s)}); + }, Gun.state.map(), 'alice/fuzz/soul')}); gun.get('u/m/p/n/mutate/n/u').put({ alice: {'#':'alice/fuzz/soul'}, }); @@ -2844,15 +2840,13 @@ describe('Gun', function(){ }); it('get node after recursive field', function(done){ - var s = Gun.state.map();s.soul = 'node/circle'; var bob = {age: 29, name: "Bob!"}; var cat = {name: "Fluffy", species: "kitty"}; var user = {bob: bob}; bob.pet = cat; cat.slave = bob; - gun.on('put', {$: gun, put: Gun.graph.ify(user, s)}); - //console.debug.i=1;console.log("-------------"); - gun.get(s.soul).get('bob').get('pet').get('slave').once(function(data){ + gun.on('test', {$: gun, put: Gun.graph.ify(user, Gun.state.map(), 'node/circle')}); + gun.get('node/circle').get('bob').get('pet').get('slave').once(function(data){ //clearTimeout(done.to); //setTimeout(function(){ //console.log("*****************", data);return; @@ -2945,7 +2939,9 @@ describe('Gun', function(){ list.set(gun.get('dave').put({name: "Dave", group: "awesome", married: true})); var check = {}, count = {}; - list.map().once(function(data, id){ + //console.log("==============================="); + //console.only.i=1; + list.map().on(function(data, id){ //console.log("***************", id, data); check[id] = data; count[id] = (count[id] || 0) + 1; @@ -3090,13 +3086,12 @@ describe('Gun', function(){ }); it('get get get any parallel', function(done){ - var s = Gun.state.map();s.soul = 'parallel'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!" } - }, s)}); + }, Gun.state.map(), 'parallel')}); gun.get('parallel').get('bob').get('age').get(function(at, ev){ var err = at.err, data = at.put, field = at.get; //console.log("***** age", data, at.$._.ack);//return; @@ -3117,13 +3112,12 @@ describe('Gun', function(){ }); it('get get get any later', function(done){ - var s = Gun.state.map();s.soul = 'parallel/later'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ bob: {_:{'#':'ddfsa'}, age: 29, name: "Bob!" } - }, s)}); + }, Gun.state.map(), 'parallel/later')}); gun.get('parallel/later').get('bob').get('age').get(function(at, ev){ var err = at.err, data = at.put, field = at.get; //console.log("***** age", data); @@ -3189,11 +3183,10 @@ describe('Gun', function(){ }); it('get any any', function(done){ - var s = Gun.state.map();s.soul = 'full'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ hello: 'world', goodbye: 'mars' - }, s)}); + }, Gun.state.map(), 'full')}); gun.get('full').get(function(at, ev){ var err = at.err, data = at.$._.put || at.put, field = at.get; //console.log("*****1", data); @@ -3211,11 +3204,10 @@ describe('Gun', function(){ }); it('get any any later', function(done){ - var s = Gun.state.map();s.soul = 'full/later'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ hello: 'world', goodbye: 'mars' - }, s)}); + }, Gun.state.map(), 'full/later')}); gun.get('full/later').get(function(at, ev){ var err = at.err, data = at.$._.put || at.put, field = at.get; //console.log("*****", data); @@ -3303,8 +3295,7 @@ describe('Gun', function(){ it('multiple times partial', function(done){ var gun = Gun(); - var s = Gun.state.map();s.soul = 'mult/times/part'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alias: { mark: { pub: {_:{'#':'PUB'}, @@ -3314,9 +3305,9 @@ describe('Gun', function(){ } } } - }, s)}); + }, Gun.state.map(), 'mult/times/part')}); - var app = gun.get(s.soul); + var app = gun.get('mult/times/part'); //console.debug.i=1;console.log("==================="); app.get('alias').get('mark').map().once(function(alias){ @@ -3457,6 +3448,7 @@ describe('Gun', function(){ list.get('message').put('hello world'); // outputs "message: hello world" list.get('message').put(null); // throws Uncaught TypeError: Cannot read property '#' of null }); + return; it('Check multi instance message passing', function(done){ try{ require('fs').unlinkSync('bdata') }catch(e){} @@ -3541,10 +3533,10 @@ describe('Gun', function(){ it('If chain cannot be called, ack', function(done){ var gun = Gun(), u; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ wat: 1, a: true - }, 'nl/app')}); + }, Gun.state.map(), 'nl/app')}); // prev had no state_map? var app = gun.get('nl/app'); @@ -3565,11 +3557,11 @@ describe('Gun', function(){ it('Chain on known nested object should ack', function(done){ var gun = Gun(), u; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ bar: { wat: 1 } - }, 'nl/app')}); + }, Gun.state.map(), 'nl/app')}); var app = gun.get('nl/app').get('bar'); @@ -3953,13 +3945,12 @@ describe('Gun', function(){ });return; it('get get any parallel', function(done){ - var s = Gun.state.map();s.soul = 'parallel/get/get'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!" } - }, s)}); + }, Gun.state.map(), 'parallel/get/get')}); gun.get('parallel/get/get').path('bob').any(function(err, data, field, at, ev){ //console.log("***** 1", data); expect(data.age).to.be(29); @@ -3974,13 +3965,12 @@ describe('Gun', function(){ }); it('get get any parallel later', function(done){ - var s = Gun.state.map();s.soul = 'parallel/get/get/later'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!" } - }, s)}); + }, Gun.state.map(), 'parallel/get/get/later')}); gun.get('parallel/get/get/later').path('bob').any(function(err, data, field, at, ev){ //console.log("***** 1", data); expect(data.age).to.be(29); @@ -3997,13 +3987,12 @@ describe('Gun', function(){ }); it('get get any none', function(done){ - var s = Gun.state.map();s.soul = 'get/get/none'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ alice: { age: 31, name: "alice" } - }, s)}); + }, Gun.state.map(), 'get/get/none')}); var c = 0, s = 0; gun.get('get/get/none').path('bob').any(function(err, data, field, at, ev){ //console.log("***** 1", data); @@ -4025,13 +4014,12 @@ describe('Gun', function(){ }); it('get get any none later', function(done){ - var s = Gun.state.map();s.soul = 'get/get/none/later'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ alice: { age: 31, name: "alice" } - }, s)}); + }, Gun.state.map(), 'get/get/none/later')}); var c = 0; gun.get('get/get/none/later').path('bob').any(function(err, data, field, at, ev){ //console.log("***** 1", data); @@ -4051,10 +4039,9 @@ describe('Gun', function(){ }); it('get get primitive get any', function(done){ - var s = Gun.state.map();s.soul = 'get/get/prim'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: "is awesome" - }, s)}); + }, Gun.state.map(), 'get/get/prim')}); gun.get('get/get/prim').path('bob').path('age').any(function(err, data, field, at, ev){ //console.log("***** 1", data); expect(data).to.be(undefined); @@ -4067,10 +4054,9 @@ describe('Gun', function(){ }); it('get put any', function(done){ - var s = Gun.state.map();s.soul = 'get/put/any'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ here: "we go" - }, s)}); + }, Gun.state.map(), 'get/put/any')}); //console.debug.i=1;console.log("---------------"); gun.get('get/put/any') .put({}) @@ -4081,10 +4067,9 @@ describe('Gun', function(){ }); return; it('get any, get put any', function(done){ - var s = Gun.state.map();s.soul = 'get/any/get/put/any'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ here: "we go" - }, s)}); + }, Gun.state.map(), 'get/any/get/put/any')}); gun.get('get/any/get/put/any') .any(function(err, data, field, at, ev){ if(done.first){ return } // it is okay for `any` to get called multiple times. @@ -4110,8 +4095,7 @@ describe('Gun', function(){ }); it('mutate pointer to primitive deep on', function(done){ - var s = Gun.state.map();s.soul = 'change/pointer'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4120,7 +4104,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'change/pointer')}); gun.get('change/pointer').path('bob').path('pet').any(function(err, data, f, at, ev){ //console.log("***", data);return setTimeout(function(){asdf},500); if(done.c){ @@ -4159,8 +4143,7 @@ describe('Gun', function(){ }); it('get only soul', function(done){ - var s = Gun.state.map();s.soul = 'only/soul'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4169,7 +4152,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'only/soul')}); gun.get('only/soul')/*.path('bob')*/.any(function(err, data){ expect(Gun.obj.empty(data, '_')).to.be.ok(); done(); @@ -4177,8 +4160,7 @@ describe('Gun', function(){ }); it('get path only soul', function(done){ - var s = Gun.state.map();s.soul = 'only/p/soul'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4187,7 +4169,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'only/p/soul')}); gun.get('only/p/soul').path('bob').any(function(err, data){ //console.log("*********", err, data); expect(Gun.val.link.is(data)).to.be.ok(); @@ -4197,8 +4179,7 @@ describe('Gun', function(){ }); it('mutate pointer to self', function(done){ - var s = Gun.state.map();s.soul = 'change/pointer/point'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4207,7 +4188,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'change/pointer/point')}); gun.get('change/pointer/point').path('bob').any(function(err, data){ if(done.c){ expect(data.age).to.be(30); @@ -4228,8 +4209,7 @@ describe('Gun', function(){ },400); }); it('mutate pointer to self deep', function(done){ - var s = Gun.state.map();s.soul = 'change/pointer/point/deep'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4238,7 +4218,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'change/pointer/point/deep')}); gun.get('change/pointer/point/deep').path('bob').any(function(err, data){ //console.log("***", data); if(done.c){ @@ -4259,8 +4239,7 @@ describe('Gun', function(){ }); it('mutate pointer to primitive after any', function(done){ - var s = Gun.state.map();s.soul = 'change/pointer/to/prime'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: {_: {'#': 'asdffdsa'}, age: 29, name: "Bob!", @@ -4269,7 +4248,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'change/pointer/to/prime')}); var bob = gun.get('asdffdsa').any(function(err, data){ //console.log("***", data); }); @@ -4294,8 +4273,7 @@ describe('Gun', function(){ }); it('mutate pointer to primitive after any deep', function(done){ - var s = Gun.state.map();s.soul = 'change/pointer/to/prime/deep'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4304,7 +4282,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'change/pointer/to/prime/deep')}); var cat = gun.get('sadffads').any(function(err, data){ //console.log("***", data); }); @@ -4328,8 +4306,7 @@ describe('Gun', function(){ }); return; it.only('mutate pointer to another pointer after any', function(done){ - var s = Gun.state.map();s.soul = 'change/pointer/to/pointer'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: {_: {'#': 'dafssfad'}, age: 29, name: "Bob!", @@ -4338,7 +4315,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'change/pointer/to/pointer')}); var bob = gun.get('dafssfad').any(function(err, data){ console.log("***", data); }); @@ -4929,9 +4906,7 @@ describe('Gun', function(){ }); it('get get not', function(done){ - var s = Gun.state.map(); - s.soul = 'a'; - Gun.on('put', {$: gun, put: Gun.graph.ify({b: 1, c: 2}, s)}); + Gun.on('test', {$: gun, put: Gun.graph.ify({b: 1, c: 2}, Gun.state.map(), 'a')}); function cb(e,d,f,a){ if('b' === f && 1 === d){ done.b = true; diff --git a/test/mocha.html b/test/mocha.html index 13bcf7a4..e5af40c4 100644 --- a/test/mocha.html +++ b/test/mocha.html @@ -17,12 +17,7 @@ - - + diff --git a/test/rad/bench.js b/test/rad/bench.js index d9c00b6e..c03a6a80 100644 --- a/test/rad/bench.js +++ b/test/rad/bench.js @@ -1,6 +1,6 @@ var Gun = (typeof window !== "undefined")? window.Gun : require('../../../gun/gun'); -var Radisk = (Gun.window && window.Radisk) || require('../../../gun/lib/radiskip'); +var Radisk = (Gun.window && window.Radisk) || require('../../../gun/lib/radisk'); Gun.TESTING = true; try{localStorage.clear()}catch(e){} try{indexedDB.deleteDatabase('radatatest');}catch(e){} diff --git a/test/rad/browser.html b/test/rad/browser.html index 087c3cfd..3821b567 100644 --- a/test/rad/browser.html +++ b/test/rad/browser.html @@ -4,8 +4,7 @@ - - + diff --git a/test/rad/rad.js b/test/rad/rad.js index eef442aa..28c91dba 100644 --- a/test/rad/rad.js +++ b/test/rad/rad.js @@ -43,7 +43,7 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam //console.log("HYPER TEST");var z = 10000; while(--z){ names.push(Gun.text.random(7)) }this.timeout(9000); - describe.only('Radix', function(){ + describe('Radix', function(){ var radix = Radix(); it('unit', function(){ @@ -264,6 +264,7 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam if(v.indexOf(find) == 0){ all[v] = true } }); rad(find, function(err, data, info){ + expect(data).to.be.ok(); Radix.map(data, function(v,k){ delete all[find+k]; }); @@ -312,12 +313,22 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam }) }); + it('read one', function(done){ + //gun.get('names').get({'.': {'*': find}, '%': 1000 * 100}).once().map().once(function(data, key){ + gun.get('names').get('stu').once(function(data, key){ + expect(data.name).to.be.ok(); + expect(data.age).to.be.ok(); + done(); + }); + }); + it('read contacts', function(done){ var all = {}, find = 'm', to; names.forEach(function(v){ v = v.toLowerCase(); if(v.indexOf(find) == 0){ all[v] = true } }); + //console.log("<<<<<<<<<"); gun.get('names').get({'.': {'*': find}, '%': 1000 * 100}).once().map().once(function(data, key){ expect(data.name).to.be.ok(); expect(data.age).to.be.ok(); @@ -328,6 +339,7 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam done(); },100); }); + //console.log(">>>>>>>>>"); }); it('read contacts again', function(done){ diff --git a/test/sea/sea.js b/test/sea/sea.js index 1a166804..dca8f6fd 100644 --- a/test/sea/sea.js +++ b/test/sea/sea.js @@ -197,20 +197,20 @@ describe('SEA', function(){ expect(dec.priv).to.be(okey.priv); expect(dec.epriv).to.be(okey.epriv); - var gun = Gun(), tmp = Gun.node.soul(old); + var gun = Gun({super: true}), tmp = Gun.node.soul(old); var graph = {}; 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); graph[tmp] = alias; - gun.on('put', {$: gun, put: graph}); + gun.on('test', {$: gun, put: graph}); var use = gun.user(); use.auth('bob', 'test123', function(ack){ expect(ack.err).to.not.be.ok(); done(); }); - }())}) + }())}); it('legacy []', function(done){ (async function(){ var pw = 'test123'; @@ -218,14 +218,14 @@ describe('SEA', function(){ var old = JSON.parse(atob("eyJfIjp7IiMiOiJ+VThkS0dySFJhX01sMFZ1YlR5OUZBYTlQS1ZlYlh0eTFjS05zWWxnYjduNC5QeVd5cUVVb0ZpYVduUElOV0Nad0xBbzFobjN1MldPWTU3SzZHZnpsNjhVIiwiPiI6eyJwdWIiOjE1NDY5MDI1MDQ5NzksImFsaWFzIjoxNTQ2OTAyNTA0OTc5LCJlcHViIjoxNTQ2OTAyNTA0OTc5LCJhdXRoIjoxNTQ2OTAyNTA0OTc5fX0sInB1YiI6IlU4ZEtHckhSYV9NbDBWdWJUeTlGQWE5UEtWZWJYdHkxY0tOc1lsZ2I3bjQuUHlXeXFFVW9GaWFXblBJTldDWndMQW8xaG4zdTJXT1k1N0s2R2Z6bDY4VSIsImFsaWFzIjoiU0VBe1wibVwiOltcIn5VOGRLR3JIUmFfTWwwVnViVHk5RkFhOVBLVmViWHR5MWNLTnNZbGdiN240LlB5V3lxRVVvRmlhV25QSU5XQ1p3TEFvMWhuM3UyV09ZNTdLNkdmemw2OFVcIixcImFsaWFzXCIsXCJhbGljZVwiLDE1NDY5MDI1MDQ5NzldLFwic1wiOlwienpuaGtIZjhZdFpZM2lGd3FVd0lJUldMTjhZMmlHbmNkcnVTaStGNDNmU1BLYWpSZlI0VzhXVHM4bElSMDBndGJmTWJxS0NjQkpGN3VNSkdGRC9WV2c9PVwifSIsImVwdWIiOiJTRUF7XCJtXCI6W1wiflU4ZEtHckhSYV9NbDBWdWJUeTlGQWE5UEtWZWJYdHkxY0tOc1lsZ2I3bjQuUHlXeXFFVW9GaWFXblBJTldDWndMQW8xaG4zdTJXT1k1N0s2R2Z6bDY4VVwiLFwiZXB1YlwiLFwiRkRzM1VvNTNFZEp6eFNocEpDaVctRGZPQ3lUS0M2U3cxeS1PZVJxam5ZRS5xVGdyYTlFQk1maEpNdVlMVmNaejRZYklLRm85enNBMHpMcV82dEVPMHI0XCIsMTU0NjkwMjUwNDk3OV0sXCJzXCI6XCJPZzRVVjY4OTluSjE4dC9ybWVnV0lkdnNqN01KaEpFc29ranZYQmdteVVRUXVNVjFTdnh4cXJqOFoyV1o2Q25XSkZnTlVDbEVYYWxuMURjUFE3M1R6UT09XCJ9IiwiYXV0aCI6IlNFQXtcIm1cIjpbXCJ+VThkS0dySFJhX01sMFZ1YlR5OUZBYTlQS1ZlYlh0eTFjS05zWWxnYjduNC5QeVd5cUVVb0ZpYVduUElOV0Nad0xBbzFobjN1MldPWTU3SzZHZnpsNjhVXCIsXCJhdXRoXCIsXCJ7XFxcImVrXFxcIjpcXFwiU0VBe1xcXFxcXFwiY3RcXFxcXFxcIjpcXFxcXFxcIi94ZnNPdVNkQUtrNkJiR00zbUV6MnVlSjI3Y0tJNThYMEtUL1FsaExSZXpWcjRkNzVZb2M5QlZNRjkzejl4QXI4N080S2FDNjJUWGVoeERQN0FFa2V4N1paaEpYL2hsVm9kK1FIcVFaaUZMK2lVQzFvL2hpUEJGWElBZmtINGRrcklGOFdqcEVaU3NIVmRSOVRhY2ZzbTB3aHN5NGJXN1ZLSEUySGc9PVxcXFxcXFwiLFxcXFxcXFwiaXZcXFxcXFxcIjpcXFxcXFxcIjhWekduTStEc1lTUktIU3Z4cSszTGc9PVxcXFxcXFwiLFxcXFxcXFwic1xcXFxcXFwiOlxcXFxcXFwibVVSSlJ4TzUvdXM9XFxcXFxcXCJ9XFxcIixcXFwic1xcXCI6XFxcImE1SlA3VFpuVE9jYjEwMGJOejlscEU4dnpqcUE3TWl0NHcwN3pjQTdIOFV0bml1WnVHSmdpZnNNQlFNSGdRdE5cXFwifVwiLDE1NDY5MDI1MDQ5NzldLFwic1wiOlwiSGFzMytJaHFEZTYyN016cElXZVE1cVFrZ2NOMlk3WHRpNGw0TFU3T2JyaktxSlBnSllrVWE2bk9YdlRmQkFzV1BPVzVnemh4Q2RPVGNFQm5icWlpWXc9PVwifSJ9")); var okey = {"pub":"U8dKGrHRa_Ml0VubTy9FAa9PKVebXty1cKNsYlgb7n4.PyWyqEUoFiaWnPINWCZwLAo1hn3u2WOY57K6Gfzl68U","epub":"FDs3Uo53EdJzxShpJCiW-DfOCyTKC6Sw1y-OeRqjnYE.qTgra9EBMfhJMuYLVcZz4YbIKFo9zsA0zLq_6tEO0r4","priv":"jMy7WfcldJ4esZEijAj4LTb99smtY_H0yKJLemJl2HI","epriv":"1DszMh-85pGTPLYtRunG-Q-xB78AE4k07PPkbedYYwk"} - var gun = Gun(), tmp = Gun.node.soul(old); + var gun = Gun({super: true}), tmp = Gun.node.soul(old); var graph = {}; 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('put', {$: gun, put: graph}); + gun.on('test', {$: gun, put: graph}); var use = gun.user(); use.auth('alice', 'test123', function(ack){ expect(ack.err).to.not.be.ok(); @@ -277,8 +277,30 @@ describe('SEA', function(){ }); describe('User', function(){ + var gun = Gun(), gtmp; + + it('test', function(done){ + var g = Gun(); + user = g.user(); + var gid; + 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); + expect(data[':']).to.be('hi'); + expect(data['~']).to.be.ok(); + g.get(gid).get('yo').once(function(r){ + expect(r).to.be('hi'); + user.leave(); + done(); + }) + }) + }) + }); + it('is instantiable', function(done){ - gun = Gun(); + user.leave(); user = gun.user(); done(); }) @@ -289,7 +311,7 @@ describe('SEA', function(){ expect(ack.err).to.not.be.ok(); done(); }) - }) + }); it('login users', function(done){ user.auth('carl', 'test123', function(ack){ @@ -347,6 +369,7 @@ describe('SEA', function(){ var ref = user.get('who').get('all').set(msg); user.get('who').get('said').set(ref); user.get('who').get('said').map().once(function(data){ + //console.log("*****", data); expect(data.what).to.be.ok(); done(); }) @@ -356,6 +379,7 @@ describe('SEA', function(){ it('set user ref null override', function(done){ this.timeout(9000); var gun = Gun(); + //user.leave(); var user = gun.user(); var msg = {what: 'hello world'}; user.create('xavier', 'password');