From e6b0659a6552d12c5c2d25d7b46aa1e221588549 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Wed, 14 Oct 2015 18:18:27 -0700 Subject: [PATCH] fix path val calling undefined --- gun.js | 60 ++++++++++++---------------- test/common.js | 105 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 34 deletions(-) diff --git a/gun.js b/gun.js index 7a379f08..9d4a9da8 100644 --- a/gun.js +++ b/gun.js @@ -146,7 +146,7 @@ if(field === Gun._.meta){ return } now.end = false; var ctx = {incoming: {}, current: {}}, state; - ctx.drift = (ctx.drift = Gun.time.is()) > (Gun.time.now.last || -Infinity)? ctx.drift : Gun.time.now.last; + ctx.drift = Gun.time.now(); //(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; @@ -497,6 +497,8 @@ } if(!Gun.obj.has(node, field)){ if(opt.end || (!ctx.path.length && gun.__.meta($.soul).end)){ // TODO: Make it so you can adjust how many terminations! + console.log("whap!"); + // TODO: BUG! `chain` here is incorrect on unknowns. cb.call(chain, null, null, field); src._.at('soul').emit({soul: $.soul, field: field, gun: chain, PATH: 'SOUL'}); } @@ -529,7 +531,7 @@ node = Gun.union.pseudo($.key, gun.__.key.s[$.key]) || node; } if($.field){ - if(ctx[$.soul + $.field]){ return } + if(!Gun.obj.has(node, $.field) || ctx[$.soul + $.field]){ return } ctx[$.soul + $.field] = true; // TODO: unregister instead? return cb.call($.gun || gun, node[$.field], $.field || $.at); } @@ -589,8 +591,8 @@ */ Chain.put = function(val, cb, opt){ // TODO: handle case where val is a gun context! var gun = this.chain(), call = function(){ - gun.back._.at('soul').emit({soul: Gun.is.soul.on(val) || Gun.roulette.call(gun), empty: true, PUT: 'SOUL'}); - }, drift = Gun.time.now(); + gun.back._.at('soul').emit({soul: Gun.is.soul.on(val) || Gun.roulette.call(gun), empty: true, PUT: 'SOUL'}); // TODO: refactor Gun.roulette! + }, drift = Gun.time.now(); // TODO: every instance of gun maybe should have their own version of time. cb = cb || function(){}; opt = opt || {}; if(!gun.back.back){ @@ -638,7 +640,7 @@ } else { function path(err, data){ if(at.soul){ return } - at.soul = Gun.is.soul.on(data) || Gun.is.soul.on(at.obj) || Gun.roulette.call(gun); + at.soul = Gun.is.soul.on(data) || Gun.is.soul.on(at.obj) || Gun.roulette.call(gun); // TODO: refactor Gun.roulette! env.graph[at.node._[Gun._.soul] = at.soul] = at.node; cb(at, at.soul); }; @@ -698,14 +700,14 @@ return gun; } Chain.set = function(val, cb, opt){ - var gun = this, ctx = {}, drift = Gun.time.now(); + var gun = this, ctx = {}, drift = Gun.text.ify(Gun.time.now()||0).replace('.','D'); // TODO: every gun instance should maybe have their own version of time. cb = cb || function(){}; opt = opt || {}; if(!gun.back){ gun = gun.put({}) } gun = gun.not(function(key){ return key? this.put({}).key(key) : this.put({}) }); if(!val && !Gun.is.value(val)){ return gun } - var obj = {}, index = 'I' + drift + 'R' + Gun.text.random(5); + var obj = {}, index = 'I' + drift + 'R' + Gun.text.random(5); // TODO: Make this configurable! obj[index] = val; return Gun.is.value(val)? gun.put(obj, cb) : gun.put(obj, cb).path(index); } @@ -721,7 +723,7 @@ next._.at('soul').once(function($){ $.N0T = 'KICK SOUL'; gun._.at('soul').emit($) }); }, chain = gun.chain(), next = cb.call(chain, key, kick), c = -1; if(Gun.is(next)){ kick(next) } - chain._.at('soul').emit({soul: Gun.roulette.call(chain), empty: true, key: key, N0T: 'SOUL', WAS: 'ON'}); // WAS ON + chain._.at('soul').emit({soul: Gun.roulette.call(chain), empty: true, key: key, N0T: 'SOUL', WAS: 'ON'}); // WAS ON! TOOD: refactor Gun.roulette }); return gun; @@ -848,9 +850,7 @@ 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(); + return ((t=t||Util.time.is()) > (Util.time.now.last || -Infinity)? (Util.time.now.last = t) : Util.time.now(t + 1)) + (Util.time.now.drift || 0); }; }; ;(function(schedule){ // maybe use lru-cache @@ -859,13 +859,13 @@ schedule.sort = Gun.list.sort('when'); schedule.set = function(future){ if(Infinity <= (schedule.soonest = future)){ return } - var now = Gun.time.is(); + var now = Gun.time.now(); // WAS time.is() TODO: Hmmm, this would make it hard for every gun instance to have their own version of time. future = (future <= now)? 0 : (future - now); clearTimeout(schedule.id); schedule.id = setTimeout(schedule.check, future); } schedule.check = function(){ - var now = Gun.time.is(), soonest = Infinity; + var now = Gun.time.now(), soonest = Infinity; // WAS time.is() TODO: Same as above about time. Hmmm. schedule.waiting.sort(schedule.sort); schedule.waiting = Gun.list.map(schedule.waiting, function(wait, i, map){ if(!wait){ return } @@ -889,22 +889,13 @@ ;Gun.ify=(function(Serializer){ function ify(data, cb, opt){ opt = opt || {}; - cb = cb || function(env, cb){ cb(env.at, Gun.roulette()) }; + cb = cb || function(env, cb){ cb(env.at, Gun.roulette()) }; // TODO: refactor Gun.roulette var end = function(fn){ ctx.end = fn || function(){}; if(ctx.err){ return ctx.end(ctx.err, ctx), ctx.end = function(){} } unique(ctx); - }, ctx = {}; + }, ctx = {at: {path: [], obj: data}, root: {}, graph: {}, queue: [], seen: [], loop: true}; 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); @@ -986,13 +977,14 @@ if(!window.JSON){ throw new Error("Include JSON first: ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js") } // for old IE use Gun.on('opt').event(function(gun, opt){ opt = opt || {}; - var tab = gun.__.tab = gun.__.tab || {}; + var tab = gun.tab = gun.tab || {}; + tab.store = tab.store || store; + tab.request = tab.request || request; tab.headers = opt.headers || {}; tab.headers['gun-sid'] = tab.headers['gun-sid'] || Gun.text.random(); // stream id tab.prefix = tab.prefix || opt.prefix || 'gun/'; tab.prekey = tab.prekey || opt.prekey || ''; tab.prenode = tab.prenode || opt.prenode || '_/nodes/'; - window.tab = tab; window.store = store; tab.get = tab.get || function(key, cb, opt){ if(!key){ return } cb = cb || function(){}; @@ -1007,7 +999,7 @@ Gun.log("tab get --->", key); (function local(key, cb){ var path = (path = Gun.is.soul(key))? tab.prefix + tab.prenode + path - : tab.prefix + tab.prekey + key, node = store.get(path), graph, soul; + : tab.prefix + tab.prekey + key, node = tab.store.get(path), graph, soul; if(Gun.is.node(node)){ (cb.graph = cb.graph || {} )[soul = Gun.is.soul.on(node)] = (graph = {})[soul] = cb.node = node; @@ -1022,7 +1014,7 @@ }(key, cb)); if(!(cb.local = opt.local)){ Gun.obj.map(opt.peers || gun.__.opt.peers, function(peer, url){ var p = {}; - request(url, null, tab.error(cb, "Error: Get failed through " + url, function(reply){ + tab.request(url, null, tab.error(cb, "Error: Get failed through " + url, function(reply){ if(!p.graph && !Gun.obj.empty(cb.graph)){ // if we have local data tab.put(p.graph = cb.graph, function(e,r){ // then sync it if we haven't already Gun.log("Stateless handshake sync:", e, r); @@ -1044,11 +1036,11 @@ Gun.is.graph(graph, function(node, soul){ if(!opt.local){ gun.__.on(soul).emit(node) } // TODO: Should this be in core? if(!gun.__.graph[soul]){ return } - store.put(tab.prefix + tab.prenode + soul, gun.__.graph[soul]); + tab.store.put(tab.prefix + tab.prenode + soul, gun.__.graph[soul]); }); if(!(cb.local = opt.local)){ Gun.obj.map(opt.peers || gun.__.opt.peers, function(peer, url){ - request(url, graph, tab.error(cb, "Error: Put failed on " + url), {headers: tab.headers}); + tab.request(url, graph, tab.error(cb, "Error: Put failed on " + url), {headers: tab.headers}); cb.peers = true; }); } tab.peers(cb); @@ -1060,12 +1052,12 @@ meta[Gun._.soul] = soul = Gun.is.soul(soul) || soul; if(!soul){ return cb({err: Gun.log("No soul!")}) } (function(souls){ - (souls = store.get(tab.prefix + tab.prekey + key) || {})[soul] = meta; - store.put(tab.prefix + tab.prekey + key, souls); + (souls = tab.store.get(tab.prefix + tab.prekey + key) || {})[soul] = meta; + tab.store.put(tab.prefix + tab.prekey + key, souls); }()); if(!(cb.local = opt.local || opt.soul)){ Gun.obj.map(opt.peers || gun.__.opt.peers, function(peer, url){ - request(url, meta, tab.error(cb, "Error: Key failed to be made on " + url), {url: {pathname: '/' + key }, headers: tab.headers}); + tab.request(url, meta, tab.error(cb, "Error: Key failed to be made on " + url), {url: {pathname: '/' + key }, headers: tab.headers}); cb.peers = true; }); } tab.peers(cb); @@ -1130,7 +1122,7 @@ return true; } Gun.obj.map(gun.__.opt.peers, function(){ // only create server if peers and do it once by returning immediately. - return (tab.request = tab.request || request.createServer(tab.server) || true); + return (tab.server.able = tab.server.able || tab.request.createServer(tab.server) || true); }); gun.__.opt.hooks.get = gun.__.opt.hooks.get || tab.get; gun.__.opt.hooks.put = gun.__.opt.hooks.put || tab.put; diff --git a/test/common.js b/test/common.js index 90f31009..60762ce7 100644 --- a/test/common.js +++ b/test/common.js @@ -1837,6 +1837,63 @@ describe('Gun', function(){ }) }); + it.skip("gun get empty set, path val -> this put", function(done){ // Issue #99 #101, bug in survey and trace game. + var test = {c: 0}, u; + var gun = Gun(); + console.log("game = gun get GAME set"); + var game = gun.get('some/not/yet/set/put/thing').set(); + console.log("me = game data path ALIAS val"); + // TODO: add one for NOT + // the behavior we decided is VAL will hang until data defined + // NOT will get called after first peer (or configurable). + var me = game.path('alias').on(function(val){ + console.log("TESTING!!!!", val); + expect(val).to.not.be(u); + var meid = Gun.is.soul.on(val); + var self = this; + expect(self === game).to.not.be.ok(); + expect(self === me).to.be.ok(); + if(test.c++){ return } + self.put({x: 0, y: 0}); + setTimeout(function(){ + var graph = Gun.obj.copy(game.__.graph); + Gun.obj.map(graph, function(node){delete node._}); + + },100); + }) + }); + + // gr.put({a: {b: {c: 'd'}}}).path('z').set().val(); TEST sets on paths. + + it.skip("gun get empty set path empty later path put multi", function(done){ // Issue #99 #101, bug in survey and trace game. + Gun.log.verbose = true; + var gun = Gun(); + var data = gun.get('some/not/yet/set/put/thing/2').set(); + var path = data.path('sub'); + function put(d, t, f){ + setTimeout(function(){ + path.put(d, function(err, ok){ + expect(err).to.not.be.ok(); + if(f){ + path.val(function(v){ + delete v._; + expect(v).to.eql(d); + done(); + }); + } + }); + setTimeout(function(){ + data.val(function(v){ + console.log(d, "DATA", data.__.graph); + }); + },2) + },t || 10); + }; + put({on: 'bus', not: 'transparent'}); + put({on: null, not: 'torrent'}, 100); + put({on: 'sub', not: 'parent'}, 250, true); + }); + it("ToDo", function(done){ // Simulate ToDo app! var gun = Gun().get('example/todo/data'); gun.on(function renderToDo(val){ @@ -1881,6 +1938,54 @@ describe('Gun', function(){ game.put({board: {11: ' ', 22: ' ', 33: 'A'}}); },100); }); + + it("gun get path empty val", function(done){ + done.c = 0; + var u; + var gun = Gun(); + var game = gun.get('players').set(); + var me = game.path('player3').val(function(val){ + if(!done.c){ done.fail = true } + expect(val).to.not.be(u); + expect(val.x).to.be(0); + expect(val.y).to.be(0); + expect(done.fail).to.not.be.ok(); + done(); + }); + setTimeout(function(){ + done.c++; + expect(done.fail).to.not.be.ok(); + me.put({x: 0, y: 0}); + },10) + }); + + it.only("gun get path empty on", function(done){ + done.c = 0; + var u; + var gun = Gun(); + var game = gun.get('players').set(); + var me = game.path('player3').on(function(val){ + if(!done.c){ done.fail = true } + expect(val).to.not.be(u); + expect(val.x).to.be(0); + expect(val.y).to.be(0); + expect(done.fail).to.not.be.ok(); + done(); + }); + setTimeout(function(){ + done.c++; + expect(done.fail).to.not.be.ok(); + me.put({x: 0, y: 0}); + },10) + }); + + it.skip("gun get path empty not", function(done){ + var g = Gun(); + }); + + it.skip("gun get path empty set", function(done){ + var g = Gun(); + }); }); describe('Streams', function(){