0.7 with .val(cb) also hearing .not

This commit is contained in:
Mark Nadal 2017-04-03 13:02:20 -07:00
parent 9786579eb3
commit 181b6bd767
11 changed files with 175 additions and 350 deletions

View File

@ -1,5 +1,23 @@
# CHANGELOG
## 0.7.x
Small breaking change to `.val(cb)`:
Previously `.val(cb)` would ONLY be called when data exists, like `.on(cb)`.
However, due to popular demand, people wanted `.val(cb)` to also get called for `.not(cb)` rather than (before) it would "wait" until data arrived.
NOTE: For dynamic paths, `.val(cb)` will still wait, like:
`gun.get('users').map().val(cb)` because the behavior of the `map()` is simply to not fire anything down the chain unless items are found.
## 0.6.x
Introduced experimental features, chaining `.val()` (no callback) and `.map(cb)` behaving as a map/reduce function.
It also upgraded the socket adapters and did end-to-end load testing and correctness testing.
## 0.5.9
GUN 0.3 -> 0.4 -> 0.5 Migration Guide:

177
gun.js
View File

@ -674,7 +674,7 @@
if(!(is = valid(v,f,n, at,env))){ return }
if(!f){
at.node = at.node || n || {};
if(obj_has(v, Node._) && !Gun.is(v)){
if(obj_has(v, Node._)){
at.node._ = obj_copy(v._);
}
at.node = Node.soul.ify(at.node, Val.rel.is(at.rel));
@ -812,7 +812,7 @@
Gun.is = function(gun){ return (gun instanceof Gun) }
Gun.version = 0.6;
Gun.version = 0.7;
Gun.chain = Gun.prototype;
Gun.chain.toJSON = function(){};
@ -882,6 +882,7 @@
function get(at, cat){
var soul = at.get[_soul], node = cat.graph[soul], field = at.get[_field], tmp;
var next = cat.next || (cat.next = {}), as = /*(at.gun||empty)._ ||*/ (next[soul] || (next[soul] = cat.gun.get(soul)))._;
//console.log("GET", soul, field);
if(!node){ return }
if(field){
if(!obj_has(node, field)){ return }
@ -964,176 +965,6 @@
module.exports = Gun;
})(require, './root');
;require(function(module){
return;
var Gun = require('./root');
var onto = require('./onto');
function Chain(back){
var at = this._ = {back: back, on: onto, $: this, next: {}};
at.root = back? back.root : at;
at.on('in', input, at);
at.on('out', output, at);
}
var chain = Chain.prototype;
chain.back = function(arg){ var tmp;
if(tmp = this._.back){
return tmp.$;
}
}
chain.next = function(arg){
var at = this._, cat;
if(cat = at.next[arg]){
return cat.$;
}
cat = (new Chain(at)._);
at.next[arg] = cat;
cat.key = arg;
return cat.$;
}
chain.get = function(arg){
if(typeof arg == 'string'){
var at = this._, cat;
if(cat = at.next[arg]){
return cat.$;
}
cat = (this.next(arg)._);
if(at.get || at === at.root){
cat.get = arg;
}
return cat.$;
} else {
var at = this._;
var out = {'#': Gun.text.random(), get: {}, cap: 1};
var to = at.root.on(out['#'], get, {next: arg})
at.on('in', get, to);
at.on('out', out);
}
return this;
}
function get(env){
var as = this.as;
if(as.next){
as.next(env, this);
}
}
chain.map = function(cb){
var at = this._;
var chain = new Chain(at);
var cat = chain._;
var u;
at.on('in', function(env){ var tmp;
if(!env){ return }
var cat = this.as;
var to = this.to;
if(tmp = env.put){
to.next(env);
Gun.obj.map(tmp, function(data, key){
if('_' == key){ return }
if(cb){
data = cb(data, key);
if(u === data){ return }
}
cat.on('in', Gun.obj.to(env, {put: data}));
});
}
}, cat);
return chain;
}
function input(env){ var tmp;
if(!env){ return }
var cat = this.as;
var to = this.to;
if(tmp = env.put){
if(tmp && tmp['#'] && (tmp = Gun.val.rel.is(tmp))){
//input.call(this, Gun.obj.to(env, {put: cat.root.put[tmp]}));
return;
}
cat.put = tmp;
to.next(env);
var next = cat.next;
Gun.obj.map(tmp, function(data, key){
if(!(key = next[key])){ return }
key.on('in', Gun.obj.to(env, {put: data}))
});
}
}
function output(env){ var tmp;
var u;
if(!env){ return }
var cat = this.as;
var to = this;
if(!cat.back){
env.test = true;
env.gun = cat.root.$;
Gun.on('out', env);
return;
}
if(tmp = env.get){
if(cat.get){
env = Gun.obj.to(env, {get: {'#': cat.get, '.': tmp}});
} else
if(cat.key){
env = Gun.obj.to(env, {get: Gun.obj.put({}, cat.key, tmp)});
} else {
env = Gun.obj.to(env, {get: {'*': tmp}})
}
}
cat.back.on('out', env);
}
chain.val = function(cb, opt){
var at = this._;
if(cb){
if(opt){
} else {
if(at.val){
cb(at.put, at.get, at);
}
}
this.get(function(env, ev){
cb(env.put, env.get, env);
});
}
}
var graph = {
app: {_:{'#':'app'},
foo: {_:{'#':'foo'},
bar: {'#': 'asdf'},
rab: {'#': 'fdsa'}
}/*,
oof: {_:{'#':'oof'},
bar: {bat: "really"},
rab: {bat: "nice!"}
}*/
},
asdf: {_:{'#': 'asdf'}, baz: "hello world!"},
fdsa: {_:{'#': 'fdsa'}, baz: "world hello!"}
}
Gun.on('out', function(env){
if(!env.test){ return }
setTimeout(function(){
console.log("reply", env.get);
env.gun._.on('in', {'@': env['#'],
put: Gun.graph.node(graph[env.get['#']])
});
return;
env.gun._.on('in', {put: graph, '@': env['#']});
},100);
});
setTimeout(function(){
//var c = new Chain(), u;
//c.get('app').map().map(x => x.bat? {baz: x.bat} : u).get('baz').val(function(data, key, env){
// console.log("envelope", env);
//});
},1000);
})(require, './experiment');
;require(function(module){
var Gun = require('./root');
Gun.chain.back = function(n, opt){ var tmp;
@ -2113,7 +1944,7 @@
function val(at, ev, to){
var opt = this.as, cat = opt.cat, gun = at.gun, coat = gun._, data = coat.put || at.put, tmp;
if(u === data){
return;
//return;
}
if(data && data[rel._] && (tmp = rel.is(data))){
tmp = (cat.root.get(tmp)._);

2
gun.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,7 @@
Gun.serve = require('./serve');
require('./nts');
require('./s3');
try{require('./uws');}catch(e){require('./wsp/server');}
try{require('./ws');}catch(e){require('./wsp/server');}
require('./file');
module.exports = Gun;
}());

118
lib/ws.js Normal file
View File

@ -0,0 +1,118 @@
var Gun = require('../gun');
var WebSocket = require('ws');
var url = require('url');
Gun.on('opt', function mount(at){
this.to.next(at);
if(at.once){ return }
var opt = at.opt.ws || (at.opt.ws = {});
var cat = (at.gun.back(-1)._);
opt.server = opt.server || at.opt.web;
opt.path = opt.path || at.opt.path || '/gun';
opt.web = new WebSocket.Server(opt);
var peers = cat.opt.peers;
opt.web.on('connection', function(ws){
ws.upgradeReq = ws.upgradeReq || {};
ws.url = url.parse(ws.upgradeReq.url||'', true);
ws.id = ws.id || Gun.text.random(6);
peers[ws.id] = {wire: ws};
ws.on('message', function(msg){
//console.log("MESSAGE", msg);
receive(msg, ws, cat);
});
ws.on('close', function(){
Gun.obj.del(peers, ws.id);
});
});
});
var message;
Gun.on('out', function(at){
this.to.next(at);
var cat = at.gun._.root._;
message = JSON.stringify(at);
if(cat.udrain){
cat.udrain.push(message);
return;
}
cat.udrain = [];
setTimeout(function(){
if(!cat.udrain){ return }
//if(count += cat.udrain.length){ console.log("msg out:", count) }
var tmp = cat.udrain;
cat.udrain = null;
message = JSON.stringify(tmp);
Gun.obj.map(cat.opt.peers, send, cat);
},1);
Gun.obj.map(cat.opt.peers, send, cat);
});
var count = 0;
function receive(msg, wire, cat){
if(!cat){ return }
try{msg = JSON.parse(msg);
}catch(e){}
if(msg instanceof Array){
var i = 0, m; while(m = msg[i++]){
receive(m, wire, cat);
}
return;
}
//if(++count){ console.log("msg in:", count) }
//msg.url = wire.url;
cat.gun.on('in', msg.body || msg);
}
// EVERY message taken care of. The "extra" ones are from in-memory not having "asked" for it yet - which we won't want it to do for foreign requests. Likewise, lots of chattyness because the put/ack replies happen before the `get` syncs so everybody now has it in-memory already to reply with.
function send(peer){
var msg = message, cat = this;
var wire = peer.wire || open(peer, cat);
if(!wire){ return }
if(wire.readyState === wire.OPEN){
wire.send(msg);
return;
}
(peer.queue = peer.queue || []).push(msg);
}
function open(peer, as){
if(!peer || !peer.url){ return }
var url = peer.url.replace('http', 'ws');
var wire = peer.wire = new WebSocket(url);
wire.on('close', function(){
reconnect(peer, as);
});
wire.on('error', function(error){
if(!error){ return }
if(error.code === 'ECONNREFUSED'){
reconnect(peer, as);
}
});
wire.on('open', function(){
var queue = peer.queue;
peer.queue = [];
Gun.obj.map(queue, function(msg){
message = msg;
send.call(as, peer);
});
});
wire.on('message', function(msg){
receive(msg, wire, as);
});
return wire;
}
function reconnect(peer, as){
clearTimeout(peer.defer);
peer.defer = setTimeout(function(){
open(peer, as);
}, 2 * 1000);
}

View File

@ -1,6 +1,6 @@
{
"name": "gun",
"version": "0.6.9",
"version": "0.7.0",
"description": "Graph engine",
"main": "index.js",
"browser": "gun.min.js",
@ -49,10 +49,10 @@
"dependencies": {
"aws-sdk": "~>2.15.0",
"formidable": "~>1.0.15",
"uws": "~>0.14.1",
"ws": "~>2.2.1 "
"ws": "~>2.2.3"
},
"devDependencies": {
"uws": "~>0.14.1",
"express": "~>4.13.4",
"hapi": "^16.1.0",
"inert": "^4.1.0",

View File

@ -1,169 +0,0 @@
return;
var Gun = require('./root');
var onto = require('./onto');
function Chain(back){
var at = this._ = {back: back, on: onto, $: this, next: {}};
at.root = back? back.root : at;
at.on('in', input, at);
at.on('out', output, at);
}
var chain = Chain.prototype;
chain.back = function(arg){ var tmp;
if(tmp = this._.back){
return tmp.$;
}
}
chain.next = function(arg){
var at = this._, cat;
if(cat = at.next[arg]){
return cat.$;
}
cat = (new Chain(at)._);
at.next[arg] = cat;
cat.key = arg;
return cat.$;
}
chain.get = function(arg){
if(typeof arg == 'string'){
var at = this._, cat;
if(cat = at.next[arg]){
return cat.$;
}
cat = (this.next(arg)._);
if(at.get || at === at.root){
cat.get = arg;
}
return cat.$;
} else {
var at = this._;
var out = {'#': Gun.text.random(), get: {}, cap: 1};
var to = at.root.on(out['#'], get, {next: arg})
at.on('in', get, to);
at.on('out', out);
}
return this;
}
function get(env){
var as = this.as;
if(as.next){
as.next(env, this);
}
}
chain.map = function(cb){
var at = this._;
var chain = new Chain(at);
var cat = chain._;
var u;
at.on('in', function(env){ var tmp;
if(!env){ return }
var cat = this.as;
var to = this.to;
if(tmp = env.put){
to.next(env);
Gun.obj.map(tmp, function(data, key){
if('_' == key){ return }
if(cb){
data = cb(data, key);
if(u === data){ return }
}
cat.on('in', Gun.obj.to(env, {put: data}));
});
}
}, cat);
return chain;
}
function input(env){ var tmp;
if(!env){ return }
var cat = this.as;
var to = this.to;
if(tmp = env.put){
if(tmp && tmp['#'] && (tmp = Gun.val.rel.is(tmp))){
//input.call(this, Gun.obj.to(env, {put: cat.root.put[tmp]}));
return;
}
cat.put = tmp;
to.next(env);
var next = cat.next;
Gun.obj.map(tmp, function(data, key){
if(!(key = next[key])){ return }
key.on('in', Gun.obj.to(env, {put: data}))
});
}
}
function output(env){ var tmp;
var u;
if(!env){ return }
var cat = this.as;
var to = this;
if(!cat.back){
env.test = true;
env.gun = cat.root.$;
Gun.on('out', env);
return;
}
if(tmp = env.get){
if(cat.get){
env = Gun.obj.to(env, {get: {'#': cat.get, '.': tmp}});
} else
if(cat.key){
env = Gun.obj.to(env, {get: Gun.obj.put({}, cat.key, tmp)});
} else {
env = Gun.obj.to(env, {get: {'*': tmp}})
}
}
cat.back.on('out', env);
}
chain.val = function(cb, opt){
var at = this._;
if(cb){
if(opt){
} else {
if(at.val){
cb(at.put, at.get, at);
}
}
this.get(function(env, ev){
cb(env.put, env.get, env);
});
}
}
var graph = {
app: {_:{'#':'app'},
foo: {_:{'#':'foo'},
bar: {'#': 'asdf'},
rab: {'#': 'fdsa'}
}/*,
oof: {_:{'#':'oof'},
bar: {bat: "really"},
rab: {bat: "nice!"}
}*/
},
asdf: {_:{'#': 'asdf'}, baz: "hello world!"},
fdsa: {_:{'#': 'fdsa'}, baz: "world hello!"}
}
Gun.on('out', function(env){
if(!env.test){ return }
setTimeout(function(){
console.log("reply", env.get);
env.gun._.on('in', {'@': env['#'],
put: Gun.graph.node(graph[env.get['#']])
});
return;
env.gun._.on('in', {put: graph, '@': env['#']});
},100);
});
setTimeout(function(){
//var c = new Chain(), u;
//c.get('app').map().map(x => x.bat? {baz: x.bat} : u).get('baz').val(function(data, key, env){
// console.log("envelope", env);
//});
},1000);

View File

@ -58,7 +58,7 @@ var Graph = {};
if(!(is = valid(v,f,n, at,env))){ return }
if(!f){
at.node = at.node || n || {};
if(obj_has(v, Node._) && !Gun.is(v)){
if(obj_has(v, Node._)){
at.node._ = obj_copy(v._);
}
at.node = Node.soul.ify(at.node, Val.rel.is(at.rel));

View File

@ -77,7 +77,7 @@ Gun.chain.val = function(cb, opt){
function val(at, ev, to){
var opt = this.as, cat = opt.cat, gun = at.gun, coat = gun._, data = coat.put || at.put, tmp;
if(u === data){
return;
//return;
}
if(data && data[rel._] && (tmp = rel.is(data))){
tmp = (cat.root.get(tmp)._);

View File

@ -8,7 +8,7 @@ function Gun(o){
Gun.is = function(gun){ return (gun instanceof Gun) }
Gun.version = 0.6;
Gun.version = 0.7;
Gun.chain = Gun.prototype;
Gun.chain.toJSON = function(){};
@ -78,6 +78,7 @@ Gun._ = { // some reserved key words, these are not the only ones.
function get(at, cat){
var soul = at.get[_soul], node = cat.graph[soul], field = at.get[_field], tmp;
var next = cat.next || (cat.next = {}), as = /*(at.gun||empty)._ ||*/ (next[soul] || (next[soul] = cat.gun.get(soul)))._;
//console.log("GET", soul, field);
if(!node){ return }
if(field){
if(!obj_has(node, field)){ return }

View File

@ -3500,6 +3500,32 @@ describe('Gun', function(){
},1700);
});
});
it('val should now get called if no data is found', function(done){
var gun = Gun();
gun.get('nv/foo').get('bar').get('baz').val(function(val, key){
//console.log('*******', key, val);
expect(val).to.be(undefined);
done.fbb = true;
});
gun.get('nv/totesnothing').val(function(val, key){
//console.log('***********', key, val);
expect(val).to.be(undefined);
done.t = true;
});
gun.get('nv/bz').get('lul').val(function(val, key){
//console.log('*****************', key, val);
expect(val).to.be(undefined);
done.bzl = true;
if(done.fbb && done.t && done.bzl){
if(done.c){ return } done.c = 1;
done();
}
});
});
return;
it.only('Custom extensions are chainable', function(done){
Gun.chain.filter = function(filter){