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');