clean up timing problems

This commit is contained in:
Mark Nadal 2015-06-07 05:00:36 -07:00
parent 3e6fc92949
commit f8e4196dc9
4 changed files with 101 additions and 1765 deletions

1259
_gun.js

File diff suppressed because it is too large Load Diff

86
gun.js
View File

@ -120,7 +120,7 @@
Gun.obj.map(delta, function update(incoming, field){
if(field === Gun._.meta){ return }
var ctx = {incoming: {}, current: {}}, state;
ctx.drift = Gun.time.is();
ctx.drift = (ctx.drift = Gun.time.is()) > (Gun.time.now.last || -Infinity)? ctx.drift : Gun.time.now.last;
ctx.incoming.value = Gun.is.soul(incoming) || incoming;
ctx.current.value = Gun.is.soul(vertex[field]) || vertex[field];
ctx.incoming.state = Gun.num.is(ctx.tmp = ((delta._||{})[Gun._.HAM]||{})[field])? ctx.tmp : -Infinity;
@ -207,6 +207,7 @@
if(opt === null){ return gun }
opt = opt || {};
gun.__.opt = gun.__.opt || {};
gun.__.flag = gun.__.flag || {};
gun.__.keys = gun.__.keys || {};
gun.__.graph = gun.__.graph || {};
gun.__.on = gun.__.on || Gun.on.create();
@ -232,17 +233,17 @@
gun.__ = from.__;
gun._ = {on: Gun.on.create()};
gun._.status = function(e){
var proxy = function(chain, cb){
var proxy = function(chain, cb, i){
return Gun.obj.map(gun._.graph, function(on, soul){
setImmediate(function(){ cb.call(on, on.status) });
return on; // TODO: BUG! What about plural graphs?
}) || gun._.on(e)[chain](function(status){
if(status){ (gun._.graph = gun._.graph || {})[status.soul] = this }
cb.call(this, this.status = status);
});
}, i);
}
proxy.event = function(cb){ return proxy('event', cb) };
proxy.once = function(cb){ return proxy('once', cb) };
proxy.event = function(cb, i){ return proxy('event', cb, i) };
proxy.once = function(cb, i){ return proxy('once', cb, i) };
proxy.emit = function(){
var args = arguments;
setImmediate(function(me){ (me = gun._.on(e)).emit.apply(me, args) })
@ -266,19 +267,16 @@
} else { load(key) } // not in memory
} else
if(ctx.key){
(function foo(){ // TODO: JANKY! UGLY!!!! Can resolve as soon as the object exists.
if(ctx.node = gun.__.keys[ctx.key]){ // in memory, or from put.key
if(true === ctx.node){
setTimeout(foo,0);
} else {
cb.call(gun, null, Gun.obj.copy(ctx.node));
var soul = Gun.is.soul.on(ctx.node);
gun._.status('soul').emit({soul: soul});
gun._.status('node').emit({soul: soul});
}
} else { load(key) } // not in memory
})();
function get(soul){
if(!(soul = Gun.is.soul.on(ctx.node = gun.__.keys[ctx.key]))){ return }
cb.call(gun, null, Gun.obj.copy(ctx.node));
gun._.status('soul').emit({soul: soul});
gun._.status('node').emit({soul: soul});
}
if(gun.__.keys[ctx.key]){ get() } // in memory
else if(ctx.flag = gun.__.flag[key]){ // will be in memory
ctx.flag.once(get);
} else { load(key) } // not in memory
} else { cb.call(gun, {err: Gun.log("No key or relation to get!")}) }
@ -308,11 +306,11 @@
if(!key){ return cb.call(gun, {err: Gun.log('No key!')}), gun }
cb = cb || function(){};
opt = opt || {};
gun.__.keys[key] = true;
(gun.__.flag[key] = gun._.status('node')).once(function($){
gun.__.keys[key] = gun.__.graph[$.soul];
delete gun.__.flag[key];
}, -1);
gun._.status('soul').event(function($){ // TODO: once per soul in graph. (?)
gun._.status('node').once(function($){
gun.__.keys[key] = gun.__.graph[$.soul];
});
if(Gun.fns.is(ctx.hook = gun.__.opt.hooks.key)){
ctx.hook(key, $.soul, function(err, data){
return cb.call(gun, err, data);
@ -374,7 +372,6 @@
var node = gun.__.graph[$.soul], field = Gun.text.ify(path.shift()), val;
if(path.length){
if(Gun.is.soul(val = node[field])){
//root.console.log('path RECURSION', field);
gun.get(val, function(err, data){
if(err){ return cb.call(gun, err, data) }
if(!data){ return cb.call(gun, null) }
@ -444,7 +441,7 @@
If this causes any application-level concern, it can compare against the live data by immediately reading it, or accessing the logs if enabled.
*/
Chain.put = function(val, cb, opt){ // handle case where val is a gun context!
var gun = this.chain(), drift = Gun.time.is();
var gun = this.chain(), drift = Gun.time.now();
cb = cb || function(){};
opt = opt || {};
@ -454,7 +451,7 @@
}
gun.back._.status('soul').event(function($){ // TODO: maybe once per soul?
var ctx = {}, obj = val, $ = Gun.obj.copy($);
console.log("chain.put", val, $);
console.log("chain.put", val);
if(Gun.is.value(obj)){
if($.from && $.at){
$.soul = $.from;
@ -485,14 +482,14 @@
}
if(!Gun.is.soul.on(at.node)){
if(obj === at.obj){
env.graph[at.node._[Gun._.soul] = $.soul] = at.node;
cb(at, $.soul);
env.graph[at.node._[Gun._.soul] = at.soul = $.soul] = at.node;
cb(at, at.soul);
} else {
$.empty? path() : gun.back.path(at.path.join('.'), path); // TODO: clean this up.
function path(err, data){
var soul = Gun.is.soul.on(data) || Gun.roulette.call(gun);
env.graph[at.node._[Gun._.soul] = soul] = at.node;
cb(at, soul);
at.soul = Gun.is.soul.on(data) || Gun.is.soul.on(at.obj) || Gun.roulette.call(gun);
env.graph[at.node._[Gun._.soul] = at.soul] = at.node;
cb(at, at.soul);
};
}
}
@ -506,8 +503,8 @@
if(err || ify.err){ return cb.call(gun, err || ify.err) }
if(err = Gun.union(gun, ify.graph).err){ return cb.call(gun, err) }
if($.from = Gun.is.soul(ify.root[$.field])){ $.soul = $.from; $.field = null }
gun._.on('soul').emit({soul: $.soul, field: $.field, candy: true});
gun._.on('node').emit({soul: $.soul, field: $.field, barf: false});
gun._.on('soul').emit({soul: $.soul, field: $.field});
gun._.on('node').emit({soul: $.soul, field: $.field});
if(Gun.fns.is(ctx.hook = gun.__.opt.hooks.put)){
ctx.hook(ify.graph, function(err, data){ // now iterate through those nodes to a persistence layer and get a callback once all are saved
if(err){ return cb.call(gun, err) }
@ -669,6 +666,11 @@
}
Util.time = {};
Util.time.is = function(t){ return t? t instanceof Date : (+new Date().getTime()) }
Util.time.now = function(t){
return (t=t||Util.time.is()) > (Util.time.now.last || -Infinity)? (Util.time.now.last = t) : Util.time.now(t + 1);
return (t = Util.time.is() + Math.random()) > (Util.time.now.last || -Infinity)?
(Util.time.now.last = t) : Util.time.now();
};
}(Gun));
;Gun.on=(function(){
// events are fundamentally different, being synchronously 1 to N fan out,
@ -790,9 +792,18 @@
return end;
}
function map(ctx, cb){
var rel = function(at, soul){
at.soul = at.soul || soul;
setImmediate(function(){ unique(ctx) },0);
if(!at.back || !at.back.length){ return }
Gun.list.map(at.back, function(rel){
rel[Gun._.soul] = at.soul;
});
}, it;
Gun.obj.map(ctx.at.obj, function(val, field){
ctx.at.val = val;
ctx.at.field = field;
it = cb(ctx, rel) || true;
if(field === Gun._.meta){
ctx.at.node[field] = Gun.obj.copy(val); // TODO: BUG! Is this correct?
return;
@ -817,15 +828,8 @@
} else {
ctx.at.node[field] = Gun.obj.copy(val);
}
cb(ctx, function(at, soul){
at.soul = at.soul || soul;
setImmediate(function(){ unique(ctx) },0);
if(!at.back || !at.back.length){ return }
Gun.list.map(at.back, function(rel){
rel[Gun._.soul] = at.soul;
});
});
});
if(!it){ cb(ctx, rel) }
}
function unique(ctx){
if(ctx.err || !Gun.list.map(ctx.seen, function(at){
@ -844,8 +848,8 @@
} else {
module.exports = Gun;
}
var setImmediate = setImmediate || function(cb){return setTimeout(cb,0)};
var root = this || {}; // safe for window, global, root, and 'use strict'.
root.setImmediate = root.setImmediate || function(cb){ return setTimeout(cb,0) };
root.console = root.console || {log: function(s){ return s }}; // safe for old browsers
var console = {log: Gun.log = function(s){return (Gun.log.verbose && root.console.log.apply(root.console, arguments)), s}};
}({}));

View File

@ -1,449 +0,0 @@
//var Gun = Gun || module.exports || require('../gun');
var Gun = Gun || require('../gun');
Gun.chain.chain = function(from){
var gun = Gun(null);
from = from || this;
gun.back = from;
gun.__ = from.__;
gun._ = {on: Gun.on.create() };
return gun;
}
Gun.chain.get = function(key, cb, opt){ // get opens up a reference to a node and loads it.
var gun = this.chain(), ctx = {};
if(!key){ return cb.call(gun, {err: Gun.log("No key or relation to get!") }), gun }
ctx.key = Gun.text.is(key) && key; // if key is text, then key, else false.
ctx.soul = Gun.is.soul(key); // if key is a soul, then the soul, else false.
cb = cb || function(){};
opt = opt || {};
if(ctx.soul){
Gun.fns.async(function(){ open(ctx.soul) });
if(ctx.node = gun.__.graph[ctx.soul]){ // in memory
cb.call(gun, null, Gun.obj.copy(ctx.node));
} else { load(key) } // not in memory
} else
if(ctx.key){
(function foo(){ // TODO: UGLY!!!!
if(ctx.node = gun.__.keys[ctx.key]){ // in memory, or from put.key
if(true === ctx.node){
Gun.fns.async(foo);
} else {
cb.call(gun, null, Gun.obj.copy(ctx.node));
Gun.fns.async(function(){ open(Gun.is.soul.on(ctx.node)) });
}
} else { load(key) } // not in memory
})();
} else { cb.call(gun, {err: Gun.log("No key or relation to get!")}) }
function open(soul){
if(!soul || ctx.open){ return }
ctx.open = true;
gun._.on('soul').emit(soul);
}
function load(key){
if(Gun.fns.is(ctx.hook = gun.__.opt.hooks.get)){
ctx.hook(key, function(err, data){ // multiple times potentially
//console.log("chain.get from load", err, data);
if(err){ return cb.call(gun, err, data) }
if(!data){ return cb.call(gun, null) } // TODO: will have have `not` be based on open?
if(ctx.soul = Gun.is.soul.on(data)){
open(ctx.soul);
} else { return cb.call(gun, {err: Gun.log('No soul on data!') }, data) }
if(err = Gun.union(gun, data).err){ return cb.call(gun, err) }
cb.call(gun, null, data);
}, opt);
} else {
root.console.log("Warning! You have no persistence layer to get from!");
cb.call(gun, null, null); // Technically no error, but no way we can get data.
}
}
return gun;
}
Gun.chain.put = function(val, cb, opt){ // handle case where val is a gun context!
var gun = this.chain(), drift = Gun.time.is(), flag;
cb = cb || function(){};
opt = opt || {};
if(!gun.back.back){
gun = gun.chain();
Gun.fns.async(function(){
flag = true;
gun.back._.on('soul').emit(Gun.is.soul.on(val) || Gun.roulette.call(gun));
});
}
//gun.back._.on('soul').event(function(soul, field, from, at){
Gun.when(gun.back, function(soul, field, from, at){
console.log("chain.put", field, val, "on", soul, 'or', from, at);
var ctx = {}, obj = val;
if(Gun.is.value(obj)){
if(from && at){
soul = from;
field = at;
} // no else!
if(!field){
return cb.call(gun, {err: Gun.log("No field exists for " + (typeof obj) + "!")});
} else
if(gun.__.graph[soul]){
ctx.tmp = {};
ctx.tmp[ctx.field = field] = obj;
obj = ctx.tmp;
} else {
return cb.call(gun, {err: Gun.log("No node exists to put " + (typeof obj) + " in!")});
}
}
if(Gun.obj.is(obj)){
if(field && !ctx.field){
ctx.tmp = {};
ctx.tmp[ctx.field = field] = obj;
obj = ctx.tmp;
}
Gun.ify(obj, function(env, cb){
var at;
if(!env || !(at = env.at) || !env.at.node){ return }
if(!at.node._){
at.node._ = {};
}
if(!Gun.is.soul.on(at.node)){
if(obj === at.obj){
env.graph[at.node._[Gun._.soul] = soul] = at.node;
cb(at, soul);
} else {
console.log('we are not at root, where are we at?', at);
flag? path() : gun.back.path(at.path.join('.'), path);
function path(err, data){
var soul = Gun.is.soul.on(data) || Gun.roulette.call(gun);
console.log("put pathing not root", soul, err, data);
env.graph[at.node._[Gun._.soul] = soul] = at.node;
cb(at, soul);
};
}
}
if(!at.node._[Gun._.HAM]){
at.node._[Gun._.HAM] = {};
}
if(!at.field){ return }
at.node._[Gun._.HAM][at.field] = drift;
})(function(err, ify){
console.log("chain.put PUT", ify.graph);
if(err || ify.err){ return cb.call(gun, err || ify.err) }
if(err = Gun.union(gun, ify.graph).err){ return cb.call(gun, err) }
if(from = Gun.is.soul(ify.root[field])){ soul = from; field = null }
gun._.on('soul').emit(soul, field);
if(Gun.fns.is(ctx.hook = gun.__.opt.hooks.put)){
ctx.hook(ify.graph, function(err, data){ // now iterate through those nodes to a persistence layer and get a callback once all are saved
if(err){ return cb.call(gun, err) }
return cb.call(gun, null, data);
}, opt);
} else {
root.console.log("Warning! You have no persistence layer to save to!");
cb.call(gun, null); // This is in memory success, hardly "success" at all.
}
});
}
});
return gun;
}
Gun.chain.key = function(key, cb, opt){
var gun = this, ctx = {};
if(!key){ return cb.call(gun, {err: Gun.log('No key!')}), gun }
cb = cb || function(){};
opt = opt || {};
gun.__.keys[key] = true;
//gun._.on('soul').event(function(soul){
Gun.when(gun, function(soul){
Gun.fns.async(function wait(node){ // TODO: UGLY!!! JANKY!!!
node = gun.__.graph[soul];
if(true === node){ return Gun.fns.async(wait) }
gun.__.keys[key] = node;
});
if(Gun.fns.is(ctx.hook = gun.__.opt.hooks.key)){
ctx.hook(key, soul, function(err, data){
return cb.call(gun, err, data);
}, opt);
} else {
root.console.log("Warning! You have no key hook!");
cb.call(gun, null); // This is in memory success, hardly "success" at all.
}
});
return gun;
}
Gun.chain.path = function(path, cb){
var gun = this.chain(), ctx = {};
cb = cb || function(){};
path = (Gun.text.ify(path) || '').split('.');
//gun.back._.on('soul').event(function trace(soul){ // TODO: Check for field as well and merge?
Gun.when(gun.back, function trace(soul){ // TODO: Check for field as well and merge?
var node = gun.__.graph[soul], field = node && Gun.text.ify(path.shift()), val;
console.log("path...", soul, field, node);
if(!node){ // handle later
return Gun.fns.async(function(){ // TODO: UGLY!!! JANKY!!!
trace(soul);
});
} else
if(path.length){
if(Gun.is.soul(val = node[field])){
gun.get(val, function(err, data){
if(err){ return cb.call(gun, err, data) }
if(!data){ return cb.call(gun, null) }
trace(Gun.is.soul.on(data));
});
} else {
cb.call(gun, null);
}
} else
if(!Gun.obj.has(node, field)){ // TODO: THIS MAY NOT BE CORRECT BEHAVIOR!!!!
cb.call(gun, null, null, field);
gun._.on('soul').emit(soul, field); // if .put is after, makes sense. If anything else, makes sense to wait.
} else
if(Gun.is.soul(val = node[field])){
gun.get(val, cb);
gun._.on('soul').emit(Gun.is.soul(val), null, soul, field);
} else {
cb.call(gun, null, val, field);
gun._.on('soul').emit(soul, field);
}
});
return gun;
}
Gun.chain.on = function(cb){ // TODO: BUG! Major problem with events is that they won't re-trigger either if listened later.
var gun = this, ctx = {};
cb = cb || function(){};
Gun.when(gun, function(soul, field){
gun.__.on(soul).event(function(delta){
cb.call(gun, delta);
});
});
return gun;
}
Gun.chain.val = function(cb){ // TODO: BUG! Major problem with events is that they won't re-trigger either if listened later.
var gun = this, ctx = {};
cb = cb || function(){};
Gun.when(gun, function(soul, field){
Gun.fns.async(function wait(node){ // TODO: UGLY!!! JANKY!!!
node = gun.__.graph[soul];
if(!node || true === node){ return Gun.fns.async(wait) }
cb.call(gun, field? node[field] : Gun.obj.copy(node));
});
});
return gun;
}
Gun.when = function(gun, cb){ // how much memory will this consume?
var setImmediate = setImmediate || function(cb){return setTimeout(cb,0)};
Gun.obj.map(gun._.graph, function(on, soul){
setImmediate(function(){ cb.apply(on, on.args) });
});
gun._.on('soul').event(function(soul){
cb.apply((gun._.graph = gun._.graph || {})[this.soul = soul] = this, this.args = arguments);
});
}
Gun.union = function(gun, prime){
var ctx = {};
ctx.graph = gun.__.graph;
if(!ctx.graph){ ctx.err = {err: Gun.log("No graph!") } }
if(!prime){ ctx.err = {err: Gun.log("No data to merge!") } }
if(ctx.soul = Gun.is.soul.on(prime)){
ctx.tmp = {};
ctx.tmp[ctx.soul] = prime;
prime = ctx.tmp;
}
if(ctx.err){ return ctx }
(function union(graph, prime){
Gun.obj.map(prime, function(node, soul){
soul = Gun.is.soul.on(node);
if(!soul){ return }
var vertex = graph[soul];
if(!vertex){ // disjoint
gun.__.on(soul).emit(graph[soul] = node); // TODO: BUG! We should copy the node in, not pass by reference?
return;
}
Gun.HAM(vertex, node, function(){}, function(vertex, field, value){
if(!vertex){ return }
var change = {};
change._ = change._ || {};
change._[Gun._.soul] = Gun.is.soul.on(vertex);
change._[Gun._.HAM] = change._[Gun._.HAM] || {};
vertex[field] = change[field] = value;
vertex._[Gun._.HAM][field] = change._[Gun._.HAM][field] = node._[Gun._.HAM][field];
//context.nodes[change._[Gun._.soul]] = change;
//context('change').fire(change);
}, function(){
});
});
})(ctx.graph, prime);
return ctx;
}
Gun.HAM = function(vertex, delta, lower, each, upper){
var ctx = {};
Gun.obj.map(delta, function update(incoming, field){
if(field === Gun._.meta){ return }
if(!Gun.obj.has(vertex, field)){ // does not need to be applied through HAM
each.call({incoming: true, converge: true}, vertex, field, incoming);
}
var drift = Gun.time.is();
var value = Gun.is.soul(incoming) || incoming;
var current = Gun.is.soul(vertex[field]) || vertex[field];
// TODO! BUG: Check for state existence so we don't crash if it isn't there. Maybe do this in union?
var state = HAM(drift, delta._[Gun._.HAM][field], vertex._[Gun._.HAM][field], value, current);
//console.log("the server state is",drift,"with delta:current",delta._[Gun._.HAM][field],vertex._[Gun._.HAM][field]);
//console.log("having incoming value of",value,'and',current);
if(state.err){
root.console.log(".!HYPOTHETICAL AMNESIA MACHINE ERR!.", state.err); // this error should never happen.
return;
}
if(state.state || state.quarantineState || state.current){
lower.call(state, vertex, field, incoming);
return;
}
if(state.incoming){
each.call(state, vertex, field, incoming);
return;
}
if(state.amnesiaQuarantine){
ctx.up += 1;
Gun.schedule(delta._[Gun._.HAM][field], function(){ // TODO: BUG!!! Don't hardcode this!
update(incoming, field);
ctx.up -= 1;
upper.call(state, vertex, field, incoming);
});
}
});
function HAM(machineState, incomingState, currentState, incomingValue, currentValue){ // TODO: Lester's comments on roll backs could be vulnerable to divergence, investigate!
if(machineState < incomingState){
// the incoming value is outside the boundary of the machine's state, it must be reprocessed in another state.
return {amnesiaQuarantine: true};
}
if(incomingState < currentState){
// the incoming value is within the boundary of the machine's state, but not within the range.
return {quarantineState: true};
}
if(currentState < incomingState){
// the incoming value is within both the boundary and the range of the machine's state.
return {converge: true, incoming: true};
}
if(incomingState === currentState){
if(incomingValue === currentValue){ // Note: while these are practically the same, the deltas could be technically different
return {state: true};
}
/*
The following is a naive implementation, but will always work.
Never change it unless you have specific needs that absolutely require it.
If changed, your data will diverge unless you guarantee every peer's algorithm has also been changed to be the same.
As a result, it is highly discouraged to modify despite the fact that it is naive,
because convergence (data integrity) is generally more important.
Any difference in this algorithm must be given a new and different name.
*/
if(String(incomingValue) < String(currentValue)){ // String only works on primitive values!
return {converge: true, current: true};
}
if(String(currentValue) < String(incomingValue)){ // String only works on primitive values!
return {converge: true, incoming: true};
}
}
return {err: "you have not properly handled recursion through your data or filtered it as JSON"};
}
}
Gun.ify = (function(){
function ify(data, cb, opt){
console.log("=================================================================");
//Gun.log.verbose = true;
opt = opt || {};
cb = cb || function(env, cb){ cb(env.at, Gun.roulette()) };
var ctx = {}, end = function(fn){
Gun.fns.async(function wait(){ // TODO: clean this up, possibly?
if(ctx.err || !Gun.list.map(ctx.seen, function(at){
if(!at.soul){ return true }
})){
fn(ctx.err, ctx)
} else {
Gun.fns.async(wait); // TODO: BUG! JANKY!!! Make this cleaner.
}
});
}
if(!data){ return ctx.err = Gun.log('Serializer does not have correct parameters.'), end }
ctx.at = {};
ctx.root = {};
ctx.graph = {};
ctx.queue = [];
ctx.seen = [];
ctx.loop = true;
ctx.at.path = [];
ctx.at.obj = data;
ctx.at.node = ctx.root;
while(ctx.loop && !ctx.err){
seen(ctx, ctx.at);
map(ctx, cb);
if(ctx.queue.length){
ctx.at = ctx.queue.shift();
} else {
ctx.loop = false;
}
}
return end;
}
function map(ctx, cb){
console.log("scanning", Object.keys(ctx.at.obj));
Gun.obj.map(ctx.at.obj, function(val, field){
ctx.at.val = val;
ctx.at.field = field;
//(ctx.at.path = ctx.at.path || [field]); // TODO: BUG! Do later.
if(field === Gun._.meta){
ctx.at.node[field] = Gun.obj.copy(val); // TODO: BUG! Is this correct?
return;
}
if(false && notValidField(field)){ // TODO: BUG! Do later for ACID "consistency" guarantee.
return ctx.err = {err: Gun.log('Invalid field name on ' + ctx.at.path.join('.'))};
}
if(!Gun.is.value(val)){
var at = {obj: val, node: {}, back: [], path: [field]}, tmp = {}, was;
at.path = (ctx.at.path||[]).concat(at.path || []);
if(!Gun.obj.is(val)){
return ctx.err = {err: Gun.log('Invalid value at ' + at.path.join('.') + '!' )};
}
if(was = seen(ctx, at)){
tmp[Gun._.soul] = Gun.is.soul.on(was.node) || null;
(was.back = was.back || []).push(ctx.at.node[field] = tmp);
} else {
ctx.queue.push(at);
tmp[Gun._.soul] = null;
at.back.push(ctx.at.node[field] = tmp);
}
} else {
ctx.at.node[field] = val; // TODO: BUG? the soul could be passed as ref, is that okay?
}
cb(ctx, function(at, soul){
at.soul = at.soul || soul;
if(!at.back || !at.back.length){ return }
Gun.list.map(at.back, function(rel){ // TODO: BUG? sync issues?
rel[Gun._.soul] = at.soul;
});
});
});
}
function seen(ctx, at){
var log = []; ctx.seen.forEach(function(val){ log.push(Object.keys(val.obj)) });
//console.log('have we seen it yet?\n', at.obj, '\n = \n', log, '\n---------');
return Gun.list.map(ctx.seen, function(has){
if(at.obj === has.obj){ return has }
}) || (ctx.seen.push(at) && false);
}
return ify;
}({}));

View File

@ -588,7 +588,7 @@ describe('Gun', function(){
var prime = {
'asdf': {
_: {'#': 'asdf', '>':{
x: Date.now() + (100) // above now or upper boundary, aka future.
x: Date.now() + (200) // above now or upper boundary, aka future.
}},
x: 'how are you?'
}
@ -597,7 +597,7 @@ describe('Gun', function(){
expect(gun.__.graph['asdf'].x).to.be('hello');
var now = Date.now();
var ctx = Gun.union(gun, prime, function(){
expect(Date.now() - now).to.be.above(75);
expect(Date.now() - now).to.be.above(100);
expect(gun.__.graph['asdf'].x).to.be('how are you?');
done();
});
@ -607,7 +607,7 @@ describe('Gun', function(){
var prime = {
'asdf': {
_: {'#': 'asdf', '>':{
y: Date.now() + (100) // above now or upper boundary, aka future.
y: Date.now() + (200) // above now or upper boundary, aka future.
}},
y: 'goodbye'
}
@ -616,7 +616,7 @@ describe('Gun', function(){
expect(gun.__.graph['asdf'].y).to.not.be.ok();
var now = Date.now();
var ctx = Gun.union(gun, prime, function(){
expect(Date.now() - now).to.be.above(75);
expect(Date.now() - now).to.be.above(100);
expect(gun.__.graph['asdf'].y).to.be('goodbye');
done();
});
@ -627,7 +627,7 @@ describe('Gun', function(){
'asdf': {
_: {'#': 'asdf', '>':{
y: Date.now() + (2), // above now or upper boundary, aka future.
z: Date.now() + (100) // above now or upper boundary, aka future.
z: Date.now() + (200) // above now or upper boundary, aka future.
}},
y: 'bye',
z: 'who'
@ -638,7 +638,7 @@ describe('Gun', function(){
expect(gun.__.graph['asdf'].z).to.not.be.ok();
var now = Date.now();
var ctx = Gun.union(gun, prime, function(){
expect(Date.now() - now).to.be.above(75);
expect(Date.now() - now).to.be.above(100);
expect(gun.__.graph['asdf'].y).to.be('bye');
expect(gun.__.graph['asdf'].z).to.be('who');
done();
@ -651,7 +651,7 @@ describe('Gun', function(){
_: {'#': 'asdf', '>':{
w: Date.now() + (2), // above now or upper boundary, aka future.
x: Date.now() - (60 * 1000), // above now or upper boundary, aka future.
y: Date.now() + (100), // above now or upper boundary, aka future.
y: Date.now() + (200), // above now or upper boundary, aka future.
z: Date.now() + (50) // above now or upper boundary, aka future.
}},
w: true,
@ -667,7 +667,7 @@ describe('Gun', function(){
expect(gun.__.graph['asdf'].z).to.be('who');
var now = Date.now();
var ctx = Gun.union(gun, prime, function(){
expect(Date.now() - now).to.be.above(75);
expect(Date.now() - now).to.be.above(100);
expect(gun.__.graph['asdf'].w).to.be(true);
expect(gun.__.graph['asdf'].x).to.be('how are you?');
expect(gun.__.graph['asdf'].y).to.be('farewell');
@ -785,7 +785,7 @@ describe('Gun', function(){
expect(done.err).to.be.ok();
expect(done.flag).to.not.be.ok();
done();
}, 150);
}, 500);
});
/*
@ -1003,9 +1003,7 @@ describe('Gun', function(){
it('get put null', function(done){
gun.put({last: {some: 'object'}}).path('last').val(function(val){
expect(val.some).to.be('object');
}).put(null, function(err){
//console.log("ERR?", err);
}).val(function(val){
}).put(null).val(function(val){
expect(val).to.be(null);
done();
});
@ -1019,7 +1017,7 @@ describe('Gun', function(){
expect(val).to.be('bar'); // this should work
done();
});
}, 100);
}, 500);
});
it('var get path', function(done){ // contexts should be able to be saved to a variable
@ -1030,7 +1028,7 @@ describe('Gun', function(){
expect(val).to.be('bar'); // this should work
done();
});
}, 100);
}, 500);
});
it('get not put val path val', function(done){
@ -1038,7 +1036,7 @@ describe('Gun', function(){
return this.put({
id: 'foobar',
title: 'awesome title',
todos: {hi: 'you'} // TODO: BUG! This should be empty?
todos: {}
}).key("examples/list/foobar");
}).val(function(data){
expect(data.id).to.be('foobar');
@ -1126,7 +1124,7 @@ describe('Gun', function(){
done();
});
});
}, 50);
}, 500);
});
it('path path', function(done){
@ -1198,6 +1196,48 @@ describe('Gun', function(){
});
});
});
it('val path put val', function(done){
var gun = Gun();
var al = gun.put({gender:'m', age:30, name:'alfred'}).key('user/alfred');
var beth = gun.put({gender:'f', age:22, name:'beth' }).key('user/beth');
al.val(function(a){
beth.path('friend').put(a).val(function(aa){
expect(Gun.is.soul.on(a)).to.be(Gun.is.soul.on(aa));
done();
});
});
});
it('val path put val key', function(done){ // bug discovered from Jose's visualizer
var gun = Gun(), s = Gun.time.is(), n = function(){ return Gun.time.is() }
this.timeout(5000);
gun.put({gender:'m', age:30, name:'alfred'}).key('user/alfred');
gun.put({gender:'f', age:22, name:'beth' }).key('user/beth');
gun.get('user/alfred').val(function(a){
gun.get('user/beth').path('friend').put(a); // b - friend_of -> a
gun.get('user/beth').val(function(b){
gun.get('user/alfred').path('friend').put(b, function(){ // a - friend_of -> b
gun.get('user/beth').path('cat').put({name: "fluffy", age: 3, coat: "tabby"}, function(err, ok){
gun.get('user/alfred').path('friend.cat').key('the/cat');
gun.get('the/cat').val(function(c){
expect(c.name).to.be('fluffy');
expect(c.age).to.be(3);
expect(c.coat).to.be('tabby');
done();
});
});
});
});
});
});
return;
it('map', function(done){
var c = 0, map = gun.put({a: {here: 'you'}, b: {go: 'dear'}, c: {sir: '!'} });