This commit is contained in:
Mark Nadal 2018-02-03 18:01:35 -08:00
parent 4ec64ade36
commit 48c7a442a9
4 changed files with 153 additions and 150 deletions

205
gun.js
View File

@ -63,7 +63,7 @@
} }
Type.list = {is: function(l){ return (l instanceof Array) }} Type.list = {is: function(l){ return (l instanceof Array) }}
Type.list.slit = Array.prototype.slice; Type.list.slit = Array.prototype.slice;
Type.list.sort = function(k){ // creates a new sort function based off some field Type.list.sort = function(k){ // creates a new sort function based off some key
return function(A,B){ return function(A,B){
if(!A || !B){ return 0 } A = A[k]; B = B[k]; if(!A || !B){ return 0 } A = A[k]; B = B[k];
if(A < B){ return -1 }else if(A > B){ return 1 } if(A < B){ return -1 }else if(A > B){ return 1 }
@ -73,15 +73,15 @@
Type.list.map = function(l, c, _){ return obj_map(l, c, _) } Type.list.map = function(l, c, _){ return obj_map(l, c, _) }
Type.list.index = 1; // change this to 0 if you want non-logical, non-mathematical, non-matrix, non-convenient array notation Type.list.index = 1; // change this to 0 if you want non-logical, non-mathematical, non-matrix, non-convenient array notation
Type.obj = {is: function(o){ return o? (o instanceof Object && o.constructor === Object) || Object.prototype.toString.call(o).match(/^\[object (\w+)\]$/)[1] === 'Object' : false }} Type.obj = {is: function(o){ return o? (o instanceof Object && o.constructor === Object) || Object.prototype.toString.call(o).match(/^\[object (\w+)\]$/)[1] === 'Object' : false }}
Type.obj.put = function(o, f, v){ return (o||{})[f] = v, o } Type.obj.put = function(o, k, v){ return (o||{})[k] = v, o }
Type.obj.has = function(o, f){ return o && Object.prototype.hasOwnProperty.call(o, f) } Type.obj.has = function(o, k){ return o && Object.prototype.hasOwnProperty.call(o, k) }
Type.obj.del = function(o, k){ Type.obj.del = function(o, k){
if(!o){ return } if(!o){ return }
o[k] = null; o[k] = null;
delete o[k]; delete o[k];
return o; return o;
} }
Type.obj.as = function(o, f, v, u){ return o[f] = o[f] || (u === v? {} : v) } Type.obj.as = function(o, k, v, u){ return o[k] = o[k] || (u === v? {} : v) }
Type.obj.ify = function(o){ Type.obj.ify = function(o){
if(obj_is(o)){ return o } if(obj_is(o)){ return o }
try{o = JSON.parse(o); try{o = JSON.parse(o);
@ -89,9 +89,9 @@
return o; return o;
} }
;(function(){ var u; ;(function(){ var u;
function map(v,f){ function map(v,k){
if(obj_has(this,f) && u !== this[f]){ return } if(obj_has(this,k) && u !== this[k]){ return }
this[f] = v; this[k] = v;
} }
Type.obj.to = function(from, to){ Type.obj.to = function(from, to){
to = to || {}; to = to || {};
@ -257,7 +257,7 @@
var Val = {}; var Val = {};
Val.is = function(v){ // Valid values are a subset of JSON: null, binary, number (!Infinity), text, or a soul relation. Arrays need special algorithms to handle concurrency, so they are not supported directly. Use an extension that supports them if needed but research their problems first. Val.is = function(v){ // Valid values are a subset of JSON: null, binary, number (!Infinity), text, or a soul relation. Arrays need special algorithms to handle concurrency, so they are not supported directly. Use an extension that supports them if needed but research their problems first.
if(v === u){ return false } if(v === u){ return false }
if(v === null){ return true } // "deletes", nulling out fields. if(v === null){ return true } // "deletes", nulling out keys.
if(v === Infinity){ return false } // we want this to be, but JSON does not support it, sad face. if(v === Infinity){ return false } // we want this to be, but JSON does not support it, sad face.
if(text_is(v) // by "text" we mean strings. if(text_is(v) // by "text" we mean strings.
|| bi_is(v) // by "binary" we mean boolean. || bi_is(v) // by "binary" we mean boolean.
@ -278,9 +278,9 @@
} }
return false; // the value was not a valid soul relation. return false; // the value was not a valid soul relation.
} }
function map(s, f){ var o = this; // map over the object... function map(s, k){ var o = this; // map over the object...
if(o.id){ return o.id = false } // if ID is already defined AND we're still looping through the object, it is considered invalid. if(o.id){ return o.id = false } // if ID is already defined AND we're still looping through the object, it is considered invalid.
if(f == rel_ && text_is(s)){ // the field should be '#' and have a text value. if(k == rel_ && text_is(s)){ // the key should be '#' and have a text value.
o.id = s; // we found the soul! o.id = s; // we found the soul!
} else { } else {
return o.id = false; // if there exists anything else on the object that isn't the soul, then it is considered invalid. return o.id = false; // if there exists anything else on the object that isn't the soul, then it is considered invalid.
@ -317,10 +317,10 @@
} }
return false; // nope! This was not a valid node. return false; // nope! This was not a valid node.
} }
function map(v, f){ // we invert this because the way we check for this is via a negation. function map(v, k){ // we invert this because the way we check for this is via a negation.
if(f === Node._){ return } // skip over the metadata. if(k === Node._){ return } // skip over the metadata.
if(!Val.is(v)){ return true } // it is true that this is an invalid node. if(!Val.is(v)){ return true } // it is true that this is an invalid node.
if(this.cb){ this.cb.call(this.as, v, f, this.n, this.s) } // optionally callback each field/value. if(this.cb){ this.cb.call(this.as, v, k, this.n, this.s) } // optionally callback each key/value.
} }
}()); }());
;(function(){ ;(function(){
@ -334,17 +334,17 @@
} }
return o.node; // This will only be a valid node if the object wasn't already deep! return o.node; // This will only be a valid node if the object wasn't already deep!
} }
function map(v, f){ var o = this.o, tmp, u; // iterate over each field/value. function map(v, k){ var o = this.o, tmp, u; // iterate over each key/value.
if(o.map){ if(o.map){
tmp = o.map.call(this.as, v, ''+f, o.node); tmp = o.map.call(this.as, v, ''+k, o.node);
if(u === tmp){ if(u === tmp){
obj_del(o.node, f); obj_del(o.node, k);
} else } else
if(o.node){ o.node[f] = tmp } if(o.node){ o.node[k] = tmp }
return; return;
} }
if(Val.is(v)){ if(Val.is(v)){
o.node[f] = v; o.node[k] = v;
} }
} }
}()); }());
@ -374,13 +374,13 @@
var perf = (typeof performance !== 'undefined')? (performance.timing && performance) : false, start = (perf && perf.timing && perf.timing.navigationStart) || (perf = false); var perf = (typeof performance !== 'undefined')? (performance.timing && performance) : false, start = (perf && perf.timing && perf.timing.navigationStart) || (perf = false);
State._ = '>'; State._ = '>';
State.drift = 0; State.drift = 0;
State.is = function(n, f, o){ // convenience function to get the state on a field on a node and return it. State.is = function(n, k, o){ // convenience function to get the state on a key on a node and return it.
var tmp = (f && n && n[N_] && n[N_][State._]) || o; var tmp = (k && n && n[N_] && n[N_][State._]) || o;
if(!tmp){ return } if(!tmp){ return }
return num_is(tmp = tmp[f])? tmp : -Infinity; return num_is(tmp = tmp[k])? tmp : -Infinity;
} }
State.lex = function(){ return State().toString(36).replace('.','') } State.lex = function(){ return State().toString(36).replace('.','') }
State.ify = function(n, f, s, v, soul){ // put a field's state on a node. State.ify = function(n, k, s, v, soul){ // put a key's state on a node.
if(!n || !n[N_]){ // reject if it is not node-like. if(!n || !n[N_]){ // reject if it is not node-like.
if(!soul){ // unless they passed a soul if(!soul){ // unless they passed a soul
return; return;
@ -388,22 +388,22 @@
n = Node.soul.ify(n, soul); // then make it so! n = Node.soul.ify(n, soul); // then make it so!
} }
var tmp = obj_as(n[N_], State._); // grab the states data. var tmp = obj_as(n[N_], State._); // grab the states data.
if(u !== f && f !== N_){ if(u !== k && k !== N_){
if(num_is(s)){ if(num_is(s)){
tmp[f] = s; // add the valid state. tmp[k] = s; // add the valid state.
} }
if(u !== v){ // Note: Not its job to check for valid values! if(u !== v){ // Note: Not its job to check for valid values!
n[f] = v; n[k] = v;
} }
} }
return n; return n;
} }
State.to = function(from, f, to){ State.to = function(from, k, to){
var val = from[f]; var val = from[k];
if(obj_is(val)){ if(obj_is(val)){
val = obj_copy(val); val = obj_copy(val);
} }
return State.ify(to, f, State.is(from, f), val, Node.soul(from)); return State.ify(to, k, State.is(from, k), val, Node.soul(from));
} }
;(function(){ ;(function(){
State.map = function(cb, s, as){ var u; // for use with Node.ify State.map = function(cb, s, as){ var u; // for use with Node.ify
@ -417,19 +417,19 @@
} }
as = as || obj_is(s)? s : u; as = as || obj_is(s)? s : u;
s = num_is(s)? s : State(); s = num_is(s)? s : State();
return function(v, f, o, opt){ return function(v, k, o, opt){
if(!cb){ if(!cb){
map.call({o: o, s: s}, v,f); map.call({o: o, s: s}, v,k);
return v; return v;
} }
cb.call(as || this || {}, v, f, o, opt); cb.call(as || this || {}, v, k, o, opt);
if(obj_has(o,f) && u === o[f]){ return } if(obj_has(o,k) && u === o[k]){ return }
map.call({o: o, s: s}, v,f); map.call({o: o, s: s}, v,k);
} }
} }
function map(v,f){ function map(v,k){
if(N_ === f){ return } if(N_ === k){ return }
State.ify(this.o, f, this.s) ; State.ify(this.o, k, this.s) ;
} }
}()); }());
var obj = Type.obj, obj_as = obj.as, obj_has = obj.has, obj_is = obj.is, obj_map = obj.map, obj_copy = obj.copy; var obj = Type.obj, obj_as = obj.as, obj_has = obj.has, obj_is = obj.is, obj_map = obj.map, obj_copy = obj.copy;
@ -456,7 +456,7 @@
this.cb.call(nf.as, n, s, nf); this.cb.call(nf.as, n, s, nf);
} }
function nf(fn){ // optional callback for each node. function nf(fn){ // optional callback for each node.
if(fn){ Node.is(nf.n, fn, nf.as) } // where we then have an optional callback for each field/value. if(fn){ Node.is(nf.n, fn, nf.as) } // where we then have an optional callback for each key/value.
} }
}()); }());
;(function(){ ;(function(){
@ -491,13 +491,13 @@
} }
return at; return at;
} }
function map(v,f,n){ function map(v,k,n){
var at = this, env = at.env, is, tmp; var at = this, env = at.env, is, tmp;
if(Node._ === f && obj_has(v,Val.rel._)){ if(Node._ === k && obj_has(v,Val.rel._)){
return n._; // TODO: Bug? return n._; // TODO: Bug?
} }
if(!(is = valid(v,f,n, at,env))){ return } if(!(is = valid(v,k,n, at,env))){ return }
if(!f){ if(!k){
at.node = at.node || n || {}; at.node = at.node || n || {};
if(obj_has(v, Node._)){ if(obj_has(v, Node._)){
at.node._ = obj_copy(v._); at.node._ = obj_copy(v._);
@ -506,21 +506,21 @@
at.rel = at.rel || Val.rel.ify(Node.soul(at.node)); at.rel = at.rel || Val.rel.ify(Node.soul(at.node));
} }
if(tmp = env.map){ if(tmp = env.map){
tmp.call(env.as || {}, v,f,n, at); tmp.call(env.as || {}, v,k,n, at);
if(obj_has(n,f)){ if(obj_has(n,k)){
v = n[f]; v = n[k];
if(u === v){ if(u === v){
obj_del(n, f); obj_del(n, k);
return; return;
} }
if(!(is = valid(v,f,n, at,env))){ return } if(!(is = valid(v,k,n, at,env))){ return }
} }
} }
if(!f){ return at.node } if(!k){ return at.node }
if(true === is){ if(true === is){
return v; return v;
} }
tmp = node(env, {obj: v, path: at.path.concat(f)}); tmp = node(env, {obj: v, path: at.path.concat(k)});
if(!tmp.node){ return } if(!tmp.node){ return }
return tmp.rel; //{'#': Node.soul(tmp.node)}; return tmp.rel; //{'#': Node.soul(tmp.node)};
} }
@ -536,14 +536,14 @@
obj_del(graph, prev); obj_del(graph, prev);
} }
} }
function valid(v,f,n, at,env){ var tmp; function valid(v,k,n, at,env){ var tmp;
if(Val.is(v)){ return true } if(Val.is(v)){ return true }
if(obj_is(v)){ return 1 } if(obj_is(v)){ return 1 }
if(tmp = env.invalid){ if(tmp = env.invalid){
v = tmp.call(env.as || {}, v,f,n); v = tmp.call(env.as || {}, v,k,n);
return valid(v,f,n, at,env); return valid(v,k,n, at,env);
} }
env.err = "Invalid value at '" + at.path.concat(f).join('.') + "'!"; env.err = "Invalid value at '" + at.path.concat(k).join('.') + "'!";
} }
function seen(env, at){ function seen(env, at){
var arr = env.seen, i = arr.length, has; var arr = env.seen, i = arr.length, has;
@ -566,23 +566,23 @@
obj_map(graph[root], map, {obj:obj, graph: graph, opt: opt}); obj_map(graph[root], map, {obj:obj, graph: graph, opt: opt});
return obj; return obj;
} }
function map(v,f){ var tmp, obj; function map(v,k){ var tmp, obj;
if(Node._ === f){ if(Node._ === k){
if(obj_empty(v, Val.rel._)){ if(obj_empty(v, Val.rel._)){
return; return;
} }
this.obj[f] = obj_copy(v); this.obj[k] = obj_copy(v);
return; return;
} }
if(!(tmp = Val.rel.is(v))){ if(!(tmp = Val.rel.is(v))){
this.obj[f] = v; this.obj[k] = v;
return; return;
} }
if(obj = this.opt.seen[tmp]){ if(obj = this.opt.seen[tmp]){
this.obj[f] = obj; this.obj[k] = obj;
return; return;
} }
this.obj[f] = this.opt.seen[tmp] = Graph.to(this.graph, tmp, this.opt); this.obj[k] = this.opt.seen[tmp] = Graph.to(this.graph, tmp, this.opt);
} }
}()); }());
var fn_is = Type.fn.is; var fn_is = Type.fn.is;
@ -668,14 +668,6 @@
Gun.ask = USE('./ask'); Gun.ask = USE('./ask');
Gun.dup = USE('./dup'); Gun.dup = USE('./dup');
Gun._ = { // some reserved key words, these are not the only ones.
node: Gun.node._ // all metadata of a node is stored in the meta property on the node.
,soul: Gun.val.rel._ // a soul is a UUID of a node but it always points to the "latest" data known.
,state: Gun.state._ // other than the soul, we store HAM metadata.
,field: '.' // a field is a property on a node which points to a value.
,value: '=' // the primitive value.
}
;(function(){ ;(function(){
Gun.create = function(at){ Gun.create = function(at){
at.root = at.root || at.gun; at.root = at.root || at.gun;
@ -719,6 +711,7 @@
if(!Gun.graph.is(msg.put, null, verify, ctx)){ ctx.err = "Error: Invalid graph!" } if(!Gun.graph.is(msg.put, null, verify, ctx)){ ctx.err = "Error: Invalid graph!" }
if(ctx.err){ return at.on('in', {'@': msg['#'], err: Gun.log(ctx.err) }) } if(ctx.err){ return at.on('in', {'@': msg['#'], err: Gun.log(ctx.err) }) }
obj_map(ctx.put, merge, ctx); obj_map(ctx.put, merge, ctx);
console.debug(3, 'PUT', ctx);
if(!ctx.async){ obj_map(ctx.map, map, ctx) } if(!ctx.async){ obj_map(ctx.map, map, ctx) }
if(u !== ctx.defer){ if(u !== ctx.defer){
setTimeout(function(){ setTimeout(function(){
@ -759,19 +752,20 @@
obj_map(node, each, as); obj_map(node, each, as);
if(!ctx.async){ return } if(!ctx.async){ return }
if(!ctx.and){ if(!ctx.and){
// If it is async, we only need to setup on listener per context (ctx)
cat.on('node', function(m){ cat.on('node', function(m){
this.to.next(m); this.to.next(m); // make sure to call other context's listeners.
if(m !== ctx.map[m.get]){ return } // filter out events not from this context! if(m !== ctx.map[m.get]){ return } // filter out events not from this context!
ctx.souls[m.get] = false; ctx.souls[m.get] = false; // set our many-async flag
obj_map(m.put, aeach, m); obj_map(m.put, aeach, m); // merge into view
if(obj_map(ctx.souls, function(v){ if(v){ return v } })){ return } if(obj_map(ctx.souls, function(v){ if(v){ return v } })){ return } // if flag still outstanding, keep waiting.
if(ctx.c){ return } ctx.c = 1; if(ctx.c){ return } ctx.c = 1; // failsafe for only being called once per context.
this.off(); this.off();
obj_map(ctx.map, map, ctx); obj_map(ctx.map, map, ctx); // all done, trigger chains.
}); });
} }
ctx.and = true; ctx.and = true;
cat.on('node', msg); cat.on('node', msg); // each node on the current context's graph needs to be emitted though.
} }
function each(val, key){ function each(val, key){
var ctx = this.ctx, graph = ctx.graph, msg = this.msg, soul = msg.get, node = msg.put, at = (msg.gun._), tmp; var ctx = this.ctx, graph = ctx.graph, msg = this.msg, soul = msg.get, node = msg.put, at = (msg.gun._), tmp;
@ -786,17 +780,21 @@
function map(msg, soul){ function map(msg, soul){
if(!msg.gun){ return } if(!msg.gun){ return }
msg.gun._.root._.stop = {}; msg.gun._.root._.stop = {};
console.debug(4, 'map ->', soul, msg.put);
(msg.gun._).on('in', msg); (msg.gun._).on('in', msg);
msg.gun._.root._.stop = {}; msg.gun._.root._.stop = {};
} }
Gun.on.get = function(msg, gun){ Gun.on.get = function(msg, gun){
var root = gun._, soul = msg.get[_soul], node = root.graph[soul], field = msg.get[_field], tmp; var root = gun._, soul = msg.get[_soul], node = root.graph[soul], has = msg.get[_has], tmp;
var next = root.next || (root.next = {}), at = ((next[soul] || empty)._); var next = root.next || (root.next = {}), at = ((next[soul] || empty)._);
if(!node || !at){ return root.on('get', msg) } if(!node || !at){ return root.on('get', msg) }
if(field){ if(has){
if(!obj_has(node, field)){ return root.on('get', msg) } if(!obj_has(node, has)){ return root.on('get', msg) }
node = Gun.state.to(node, field); node = Gun.state.to(node, has);
// If we have a key in-memory, do we really need to fetch?
// Maybe... in case the in-memory key we have is a local write
// we still need to trigger a pull/merge from peers.
} else { } else {
node = Gun.obj.copy(node); node = Gun.obj.copy(node);
} }
@ -840,7 +838,7 @@
var list_is = Gun.list.is; var list_is = Gun.list.is;
var text = Gun.text, text_is = text.is, text_rand = text.random; var text = Gun.text, text_is = text.is, text_rand = text.random;
var obj = Gun.obj, obj_is = obj.is, obj_has = obj.has, obj_to = obj.to, obj_map = obj.map, obj_copy = obj.copy; var obj = Gun.obj, obj_is = obj.is, obj_has = obj.has, obj_to = obj.to, obj_map = obj.map, obj_copy = obj.copy;
var state_lex = Gun.state.lex, _soul = Gun._.soul, _field = Gun._.field, node_ = Gun._.node, rel_is = Gun.val.rel.is; var state_lex = Gun.state.lex, _soul = Gun.val.rel._, _has = '.', node_ = Gun.node._, rel_is = Gun.val.rel.is;
var empty = {}, u; var empty = {}, u;
console.debug = function(i, s){ return (console.debug.i && i === console.debug.i && console.debug.i++) && (console.log.apply(console, arguments) || s) }; console.debug = function(i, s){ return (console.debug.i && i === console.debug.i && console.debug.i++) && (console.log.apply(console, arguments) || s) };
@ -993,7 +991,7 @@
if(cat.get && at.get !== cat.get){ if(cat.get && at.get !== cat.get){
at = obj_to(at, {get: cat.get}); at = obj_to(at, {get: cat.get});
} }
if(cat.field && coat !== cat){ if(cat.has && coat !== cat){
at = obj_to(at, {gun: cat.gun}); at = obj_to(at, {gun: cat.gun});
if(coat.ack){ if(coat.ack){
cat.ack = coat.ack; cat.ack = coat.ack;
@ -1001,14 +999,14 @@
} }
} }
if(node_ === cat.get && change && change['#']){ if(node_ === cat.get && change && change['#']){
// TODO: Potential bug? What if (soul.field = pointer) gets changed to (soul.field = primitive), we still need to clear out / wipe /reset (soul.field._) to have _id = nothing, or puts might have false positives (revert back to old soul). // TODO: Potential bug? What if (soul.has = pointer) gets changed to (soul.has = primitive), we still need to clear out / wipe /reset (soul.has._) to have _id = nothing, or puts might have false positives (revert back to old soul).
cat._id = change['#']; cat._id = change['#'];
} }
if(u === change){ if(u === change){
ev.to.next(at); ev.to.next(at);
if(cat.soul){ return } if(cat.soul){ return }
echo(cat, at, ev); echo(cat, at, ev);
if(cat.field){ if(cat.has){
not(cat, at); not(cat, at);
} }
obj_del(coat.echo, cat.id); obj_del(coat.echo, cat.id);
@ -1018,6 +1016,7 @@
if(cat.soul){ if(cat.soul){
//if(cat.root._.now){ at = obj_to(at, {put: change = coat.put}) } // TODO: Ugly hack for uncached synchronous maps. //if(cat.root._.now){ at = obj_to(at, {put: change = coat.put}) } // TODO: Ugly hack for uncached synchronous maps.
ev.to.next(at); ev.to.next(at);
console.debug(5, 'in', cat.soul, change, cat.map, cat.echo, cat.next, cat);
echo(cat, at, ev); echo(cat, at, ev);
obj_map(change, map, {at: at, cat: cat}); obj_map(change, map, {at: at, cat: cat});
return; return;
@ -1031,10 +1030,10 @@
if(!rel || tmp){*/ if(!rel || tmp){*/
if(!(rel = Gun.val.rel.is(change))){ if(!(rel = Gun.val.rel.is(change))){
if(Gun.val.is(change)){ if(Gun.val.is(change)){
if(cat.field || cat.soul){ if(cat.has || cat.soul){
not(cat, at); not(cat, at);
} else } else
if(coat.field || coat.soul){ if(coat.has || coat.soul){
(coat.echo || (coat.echo = {}))[cat.id] = cat; (coat.echo || (coat.echo = {}))[cat.id] = cat;
(cat.map || (cat.map = {}))[coat.id] = cat.map[coat.id] || {at: coat}; (cat.map || (cat.map = {}))[coat.id] = cat.map[coat.id] || {at: coat};
//if(u === coat.put){ return } // Not necessary but improves performance. If we have it but coat does not, that means we got things out of order and coat will get it. Once coat gets it, it will tell us again. //if(u === coat.put){ return } // Not necessary but improves performance. If we have it but coat does not, that means we got things out of order and coat will get it. Once coat gets it, it will tell us again.
@ -1043,10 +1042,10 @@
echo(cat, at, ev); echo(cat, at, ev);
return; return;
} }
if(cat.field && coat !== cat && obj_has(coat, 'put')){ if(cat.has && coat !== cat && obj_has(coat, 'put')){
cat.put = coat.put; cat.put = coat.put;
}; };
if((rel = Gun.node.soul(change)) && coat.field){ if((rel = Gun.node.soul(change)) && coat.has){
coat.put = (cat.root.get(rel)._).put; coat.put = (cat.root.get(rel)._).put;
} }
ev.to.next(at); ev.to.next(at);
@ -1097,7 +1096,7 @@
} }
function echo(at, msg, ev){ function echo(at, msg, ev){
if(!at.echo){ return } // || node_ === at.get ? if(!at.echo){ return } // || node_ === at.get ?
if(at.has || at.field){ msg = obj_to(msg, {event: ev}) } if(at.has){ msg = obj_to(msg, {event: ev}) }
obj_map(at.echo, reverb, msg); obj_map(at.echo, reverb, msg);
} }
function reverb(to){ function reverb(to){
@ -1113,7 +1112,7 @@
//if(data && data[_soul] && (tmp = Gun.val.rel.is(data)) && (tmp = (cat.root.get(tmp)._)) && obj_has(tmp, 'put')){ //if(data && data[_soul] && (tmp = Gun.val.rel.is(data)) && (tmp = (cat.root.get(tmp)._)) && obj_has(tmp, 'put')){
// data = tmp.put; // data = tmp.put;
//} //}
if(at.field){ if(at.has){
if(!(data && data[_soul] && Gun.val.rel.is(data) === Gun.node.soul(at.put))){ if(!(data && data[_soul] && Gun.val.rel.is(data) === Gun.node.soul(at.put))){
at.put = data; at.put = data;
} }
@ -1195,7 +1194,7 @@
var empty = {}, u; 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; var obj = Gun.obj, obj_has = obj.has, obj_put = obj.put, obj_del = obj.del, obj_to = obj.to, obj_map = obj.map;
var text_rand = Gun.text.random; var text_rand = Gun.text.random;
var _soul = Gun._.soul, _field = Gun._.field, node_ = Gun.node._; var _soul = Gun.val.rel._, node_ = Gun.node._;
})(USE, './chain'); })(USE, './chain');
;USE(function(module){ ;USE(function(module){
@ -1242,8 +1241,8 @@
if(cat.root === back){ if(cat.root === back){
at.soul = key; at.soul = key;
} else } else
if(cat.soul || cat.field || cat.has){ // TODO: Convert field to has! if(cat.soul || cat.has){
at.field = at.has = key; at.has = key;
//if(obj_has(cat.put, key)){ //if(obj_has(cat.put, key)){
//at.put = cat.put[key]; //at.put = cat.put[key];
//} //}
@ -1276,7 +1275,7 @@
;USE(function(module){ ;USE(function(module){
var Gun = USE('./root'); var Gun = USE('./root');
Gun.chain.put = function(data, cb, as){ Gun.chain.put = function(data, cb, as){
// #soul.field=value>state // #soul.has=value>state
// ~who#where.where=what>when@was // ~who#where.where=what>when@was
// TODO: BUG! Put probably cannot handle plural chains! // TODO: BUG! Put probably cannot handle plural chains!
var gun = this, at = (gun._), root = at.root, tmp; var gun = this, at = (gun._), root = at.root, tmp;
@ -1379,7 +1378,7 @@
var tmp = cat.root._.now; obj.del(cat.root._, 'now'); var tmp = cat.root._.now; obj.del(cat.root._, 'now');
var tmp2 = cat.root._.stop; var tmp2 = cat.root._.stop;
(as.ref._).now = true; (as.ref._).now = true;
//console.log("PUT!", as.env.graph); console.debug(2, "PUT!", as.env.graph);
(as.ref._).on('out', { (as.ref._).on('out', {
gun: as.ref, put: as.out = as.env.graph, opt: as.opt, '#': ask gun: as.ref, put: as.out = as.env.graph, opt: as.opt, '#': ask
}); });
@ -1388,10 +1387,10 @@
cat.root._.stop = tmp2; cat.root._.stop = tmp2;
}, as); }, as);
if(as.res){ as.res() } if(as.res){ as.res() }
} function no(v,f){ if(v){ return true } } } function no(v,k){ if(v){ return true } }
function map(v,f,n, at){ var as = this; function map(v,k,n, at){ var as = this;
if(f || !at.path.length){ return } if(k || !at.path.length){ return }
(as.res||iife)(function(){ (as.res||iife)(function(){
var path = at.path, ref = as.ref, opt = as.opt; var path = at.path, ref = as.ref, opt = as.opt;
var i = 0, l = path.length; var i = 0, l = path.length;
@ -1610,7 +1609,7 @@
}, opt.wait || 99); }, opt.wait || 99);
return; return;
} }
if(cat.field || cat.soul){ if(cat.has || cat.soul){
if(ev.off()){ return } // if it is already off, don't call again! if(ev.off()){ return } // if it is already off, don't call again!
} else { } else {
if((opt.seen = opt.seen || {})[coat.id]){ return } if((opt.seen = opt.seen || {})[coat.id]){ return }
@ -1691,9 +1690,9 @@
obj_map(msg.put, each, {at: this.as, msg: msg}); obj_map(msg.put, each, {at: this.as, msg: msg});
this.to.next(msg); this.to.next(msg);
} }
function each(v,f){ function each(v,k){
if(n_ === f){ return } if(n_ === k){ return }
var msg = this.msg, gun = msg.gun, at = this.at, tmp = (gun.get(f)._); var msg = this.msg, gun = msg.gun, at = this.at, tmp = (gun.get(k)._);
(tmp.echo || (tmp.echo = {}))[at.id] = at; (tmp.echo || (tmp.echo = {}))[at.id] = at;
} }
var obj_map = Gun.obj.map, noop = function(){}, event = {stun: noop, off: noop}, n_ = Gun.node._, u; var obj_map = Gun.obj.map, noop = function(){}, event = {stun: noop, off: noop}, n_ = Gun.node._, u;
@ -1764,12 +1763,12 @@
this.to.next(at); this.to.next(at);
var lex = at.get, soul, data, u; var lex = at.get, soul, data, u;
//setTimeout(function(){ //setTimeout(function(){
if(!lex || !(soul = lex[Gun._.soul])){ return } if(!lex || !(soul = lex['#'])){ return }
//if(0 >= at.cap){ return } //if(0 >= at.cap){ return }
var field = lex['.']; var has = lex['.'];
data = disk[soul] || u; data = disk[soul] || u;
if(data && field){ if(data && has){
data = Gun.state.to(data, field); data = Gun.state.to(data, has);
} }
if(!data && !Gun.obj.empty(opt.peers)){ // if data not found, don't ack if there are peers. if(!data && !Gun.obj.empty(opt.peers)){ // if data not found, don't ack if there are peers.
return; // Hmm, what if we have peers but we are disconnected? return; // Hmm, what if we have peers but we are disconnected?

View File

@ -40,7 +40,7 @@ Gun.on('opt', function(ctx){
this.to.next(at); this.to.next(at);
var lex = at.get, soul, data, opt, u; var lex = at.get, soul, data, opt, u;
//setTimeout(function(){ //setTimeout(function(){
if(!lex || !(soul = lex[Gun._.soul])){ return } if(!lex || !(soul = lex['#'])){ return }
//if(0 >= at.cap){ return } //if(0 >= at.cap){ return }
if(Gun.obj.is(soul)){ return match(at) } if(Gun.obj.is(soul)){ return match(at) }
var field = lex['.']; var field = lex['.'];

View File

@ -29,7 +29,7 @@ Gun.on('opt', function(ctx){
this.to.next(at); this.to.next(at);
var lex = at.get, soul, data, opt, u; var lex = at.get, soul, data, opt, u;
//setTimeout(function(){ //setTimeout(function(){
if(!lex || !(soul = lex[Gun._.soul])){ return } if(!lex || !(soul = lex['#'])){ return }
//if(0 >= at.cap){ return } //if(0 >= at.cap){ return }
var field = lex['.']; var field = lex['.'];
data = disk[soul] || u; data = disk[soul] || u;

View File

@ -3754,6 +3754,42 @@ describe('Gun', function(){
}); });
return; return;
it.only('get map should not slowdown', function(done){
this.timeout(5000);
var gun = (window.gun = Gun()).get('g/m/no/slow');
//console.log("---------- setup data done -----------");
var prev, diff, max = 25, total = 2, largest = -1, gone = {};
//var prev, diff, max = Infinity, total = 10000, largest = -1, gone = {};
// TODO: It would be nice if we could change these numbers for different platforms/versions of javascript interpreters so we can squeeze as much out of them.
gun.get('history').map().on(function(time, index){
console.log(">>>", index, time);
diff = Gun.time.is() - time;
return;
expect(gone[index]).to.not.be.ok();
gone[index] = diff;
largest = (largest < diff)? diff : largest;
//console.log(diff, '<', max);
expect(diff > max).to.not.be.ok();
});
var turns = 0;
var many = setInterval(function(){
if(turns > total || (diff || 0) > (max + 5)){
clearTimeout(many);
expect(Gun.num.is(diff)).to.be.ok();
if(done.c){ return } done.c = 1;
done();
return;
}
prev = Gun.time.is();
var put = {}; put[turns += 1] = prev;
//console.log("put", put);
console.log("------", turns, "-------");
2 === turns && (console.debug.i = 1);
console.debug(1, 'save', {history: put});
gun.put({history: put});
}, 1);
});
return;
it('Nested listener should be called', function(done){ it('Nested listener should be called', function(done){
var gun = Gun(); var gun = Gun();
@ -5711,7 +5747,7 @@ describe('Gun', function(){
//gun.get('user/beth').path('friend').put(gun.get('user/alfred')); // ideal format which we have a future test for. //gun.get('user/beth').path('friend').put(gun.get('user/alfred')); // ideal format which we have a future test for.
gun.get('user/alfred').val(function(a){ gun.get('user/alfred').val(function(a){
//console.log("*****", a); //console.log("*****", a);
//expect(a[Gun._.meta]['key']).to.be.ok(); //expect(a['_']['key']).to.be.ok();
gun.get('user/beth').put({friend: a}, function(err, ok){ // b - friend_of -> a gun.get('user/beth').put({friend: a}, function(err, ok){ // b - friend_of -> a
expect(err).to.not.be.ok(); expect(err).to.not.be.ok();
var keynode = gun.Back(-1)._.graph['user/alfred']; var keynode = gun.Back(-1)._.graph['user/alfred'];
@ -5800,8 +5836,8 @@ describe('Gun', function(){
it.skip('unique val on stream', function(done){ // TODO: THE API HAS CHANGED! REDO TEHSE! it.skip('unique val on stream', function(done){ // TODO: THE API HAS CHANGED! REDO TEHSE!
var gun = Gun({wire: {get: function(key, cb){ var gun = Gun({wire: {get: function(key, cb){
if(Gun.obj.has(key, Gun._.soul)){ if(Gun.obj.has(key, '#')){
key = key[Gun._.soul]; key = key['#'];
var node = tmp.graph[key]; var node = tmp.graph[key];
cb(null, node); cb(null, node);
cb(null, Gun.is.node.ify({}, key)); cb(null, Gun.is.node.ify({}, key));
@ -5812,10 +5848,10 @@ describe('Gun', function(){
Gun.is.node.ify(tmp.node, tmp.soul); Gun.is.node.ify(tmp.node, tmp.soul);
tmp.graph['me'] = tmp.keynode = {}; tmp.graph['me'] = tmp.keynode = {};
Gun.obj.put(tmp.rel = {}, Gun._.soul, tmp.soul); Gun.obj.put(tmp.rel = {}, '#', tmp.soul);
tmp.keynode[tmp.soul] = tmp.rel; tmp.keynode[tmp.soul] = tmp.rel;
Gun.is.node.ify(tmp.keynode, 'me'); Gun.is.node.ify(tmp.keynode, 'me');
tmp.keynode[Gun._.meta]['key'] = 1; tmp.keynode['#']['key'] = 1;
gun.get('me', function(err, data){ gun.get('me', function(err, data){
@ -6152,7 +6188,7 @@ describe('Gun', function(){
var u, gun = Gun(); var u, gun = Gun();
gun.get('set').set().set().val(function(val){ gun.get('set').set().set().val(function(val){
var keynode = gun.__.graph['set']; var keynode = gun.__.graph['set'];
expect(Gun.node.soul.ify(keynode, Gun._.key)).to.be.ok(); expect(Gun.node.soul.ify(keynode, '.')).to.be.ok();
Gun.is.node(keynode, function(rel, soul){ Gun.is.node(keynode, function(rel, soul){
rel = gun.__.by(soul).node; rel = gun.__.by(soul).node;
expect(Gun.obj.empty(rel, Gun._.meta)).to.be.ok(); expect(Gun.obj.empty(rel, Gun._.meta)).to.be.ok();
@ -6274,7 +6310,7 @@ describe('Gun', function(){
Gun.on('opt').event(function(gun, o){ Gun.on('opt').event(function(gun, o){
if(connect){ return } if(connect){ return }
gun.__.opt.wire = {get: function(key, cb, opt){ gun.__.opt.wire = {get: function(key, cb, opt){
key = key[Gun._.soul]; key = key['#'];
if(o.alice){ acb = cb; ag = gun.__.graph; } else { bcb = cb; bg = gun.__.graph; } if(o.alice){ acb = cb; ag = gun.__.graph; } else { bcb = cb; bg = gun.__.graph; }
var other = (o.alice? gun2 : gun1); var other = (o.alice? gun2 : gun1);
if(connect){ if(connect){
@ -6955,38 +6991,6 @@ describe('Gun', function(){
}) })
}); });
it('path should not slowdown', function(done){
this.timeout(5000);
var gun = Gun().put({
history: {}
});
//console.log("---------- setup data done -----------");
var prev, diff, max = 25, total = 100, largest = -1, gone = {};
//var prev, diff, max = Infinity, total = 10000, largest = -1, gone = {};
// TODO: It would be nice if we could change these numbers for different platforms/versions of javascript interpreters so we can squeeze as much out of them.
gun.path('history').map(function(time, index){
diff = Gun.time.is() - time;
expect(gone[index]).to.not.be.ok();
gone[index] = diff;
largest = (largest < diff)? diff : largest;
//console.log(turns, index, 'largest', largest, diff, '???', diff > max, diff, max);
expect(diff > max).to.not.be.ok();
});
var turns = 0;
var many = setInterval(function(){
if(turns > total || (diff || 0) > (max + 5)){
clearTimeout(many);
expect(Gun.num.is(diff)).to.be.ok();
if(done.c){ return } done(); done.c = 1;
return;
}
prev = Gun.time.is();
var put = {}; put[turns += 1] = prev;
//console.log("put", put);
gun.put({history: put});
}, 1);
});
it('path rel should not slowdown', function(done){ it('path rel should not slowdown', function(done){
this.timeout(5000); this.timeout(5000);
var gun = Gun(/*gopt*/).put({ var gun = Gun(/*gopt*/).put({
@ -7232,7 +7236,7 @@ describe('Gun', function(){
nested: 'lol' nested: 'lol'
} }
} }
env.graph[at.node._[Gun._.soul] = at.soul = $.soul] = at.node env.graph[at.node._['#'] = at.soul = $.soul] = at.node
} }
} }
var start = Date.now(); var start = Date.now();
@ -7307,13 +7311,13 @@ describe('Gun', function(){
} }
if(!Gun.node.soul(at.node)){ if(!Gun.node.soul(at.node)){
if(obj === at.obj){ if(obj === at.obj){
env.graph[at.node._[Gun._.soul] = at.soul = $.soul] = at.node; env.graph[at.node._['#'] = at.soul = $.soul] = at.node;
cb(at, at.soul); cb(at, at.soul);
} else { } else {
function path(err, data){ function path(err, data){
if(at.soul){ return } if(at.soul){ return }
at.soul = Gun.node.soul(data) || Gun.node.soul(at.obj) || Gun.roulette.call(gun); // TODO: refactor Gun.roulette! at.soul = Gun.node.soul(data) || Gun.node.soul(at.obj) || Gun.roulette.call(gun); // TODO: refactor Gun.roulette!
env.graph[at.node._[Gun._.soul] = at.soul] = at.node; env.graph[at.node._['#'] = at.soul] = at.node;
//var start = performance.now(); //var start = performance.now();
cb(at, at.soul); cb(at, at.soul);
//first = performance.now() - start;(first > .05) && console.log('here'); //first = performance.now() - start;(first > .05) && console.log('here');
@ -7650,7 +7654,7 @@ describe('Gun', function(){
} }
,get: function(lex, cb){ ,get: function(lex, cb){
setTimeout(function(){ setTimeout(function(){
var soul = lex[Gun._.soul]; var soul = lex['#'];
if(peers.localStorage){ if(peers.localStorage){
var g = peers.localStorage; var g = peers.localStorage;
console.log("VIA LOCALSTORAGE!", lex, g[soul]); console.log("VIA LOCALSTORAGE!", lex, g[soul]);
@ -7708,7 +7712,7 @@ describe('Gun', function(){
} }
,get: function(lex, cb){ ,get: function(lex, cb){
setTimeout(function(){ setTimeout(function(){
var soul = lex[Gun._.soul]; var soul = lex['#'];
var graph = server.__.graph; var graph = server.__.graph;
//console.log('server replying', soul, graph); //console.log('server replying', soul, graph);
if(!graph[soul]){ if(!graph[soul]){
@ -8088,7 +8092,7 @@ describe('Gun', function(){
ctx.get = function(key, cb){ ctx.get = function(key, cb){
var c = 0; var c = 0;
cb = cb || function(){}; cb = cb || function(){};
key = key[Gun._.soul]; key = key['#'];
if('big' !== key){ return cb(null) } if('big' !== key){ return cb(null) }
setTimeout(function badNetwork(){ setTimeout(function badNetwork(){
c += 1; c += 1;