diff --git a/gun.js b/gun.js index eb7382a0..4e23322d 100644 --- a/gun.js +++ b/gun.js @@ -1,6 +1,6 @@ -/* eslint-disable */ -/* eslint-enable no-console */ -//console.log("!!!!!!!!!!!!!!!! WARNING THIS IS GUN 0.5 !!!!!!!!!!!!!!!!!!!!!!"); +/* eslint-disable */ +/* eslint-enable no-console */ +//console.log("!!!!!!!!!!!!!!!! WARNING THIS IS GUN 0.5 !!!!!!!!!!!!!!!!!!!!!!"); ;(function(){ /* UNBUILD */ @@ -75,7 +75,7 @@ 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.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, f, v){ return (o||{})[f] = v, o } Type.obj.has = function(o, f){ return o && Object.prototype.hasOwnProperty.call(o, f) } Type.obj.del = function(o, k){ if(!o){ return } @@ -165,7 +165,7 @@ var obj = Type.obj, obj_is = obj.is, obj_has = obj.has, obj_map = obj.map; module.exports = Type; })(require, './type'); - + ;require(function(module){ // On event emitter generic javascript utility. function Scope(){ @@ -297,7 +297,7 @@ ;require(function(module){ var On = require('./on'); - + function Chain(create, opt){ opt = opt || {}; opt.id = opt.id || '#'; @@ -314,7 +314,7 @@ return; } if(at.stun === stun){ - delete at.stun; + delete at.stun; } off = true; var i = 0, q = res.queue, l = q.length, c, v; @@ -348,6 +348,7 @@ on.ack = function(at, reply){ if(!at || !reply || !ask.on){ return } var id = at[opt.id] || at; + if(!ask.ons[id]){ return } ask.on(id, reply); return true; } @@ -478,11 +479,11 @@ } if(incomingState < currentState){ return {historical: true}; // the incoming value is within the boundary of the machine's state, but not within the range. - + } if(currentState < incomingState){ return {converge: true, incoming: true}; // the incoming value is within both the boundary and the range of the machine's state. - + } if(incomingState === currentState){ if(incomingValue === currentValue){ // Note: while these are practically the same, the deltas could be technically different @@ -622,7 +623,7 @@ if(o.node){ o.node[f] = tmp } return; } - if(Val.is(v)){ + if(Val.is(v)){ o.node[f] = v; } } @@ -707,8 +708,8 @@ } function map(n, s){ // we invert this because the way we check for this is via a negation. if(!n || s !== Node.soul(n) || !Node.is(n, this.fn)){ return true } // it is true that this is an invalid graph. - if(!fn_is(this.cb)){ return } - nf.n = n; nf.as = this.as; + if(!fn_is(this.cb)){ return } + nf.n = n; nf.as = this.as; this.cb.call(nf.as, n, s, nf); } }()); @@ -717,7 +718,7 @@ var at = {path: [], obj: obj}; if(!env){ env = {}; - } else + } else if(typeof env === 'string'){ env = {soul: env}; } else @@ -887,7 +888,7 @@ Gun.graph = require('./graph'); Gun.on = require('./onify')(); - + /* var opt = {chain: 'in', back: 'out', extend: 'root', id: Gun._.soul}; Gun.chain = require('./chain')(Gun, opt); @@ -930,28 +931,28 @@ gun.on('in', input, at); gun.on('out', output, at); } - function output(at){ - var cat = this, gun = cat.gun, tmp; - if(at['#']){ - dedup.track(at['#']); - } - if(at.put){ - cat.on('in', obj_to(at, {gun: cat.gun})); + function output(at){ + var cat = this, gun = cat.gun, tmp; + // TODO: BUG! Outgoing `get` to read from in memory!!! + if(at.get && get(at, cat)){ return } + //if(at.put){ + cat.on('in', obj_to(at, {gun: cat.gun})); // TODO: PERF! input now goes to output so it would be nice to reduce the circularity here for perf purposes. + //} + if(at['#']){ + dedup.track(at['#']); } if(!at.gun){ at = Gun.obj.to(at, {gun: gun}); } - if(at.put){ Gun.on('put', at) } - if(at.get){ get(at, cat) } - - // Reads and writes both trigger output. - if (at.put !== undefined || at.get !== undefined) { - Gun.on('out', at); - } - // Gun.on('out', at); - return; - if(!cat.back){ return } - cat.back.on('out', at); + //if(at.put){ Gun.on('put', at) } + //if(at.get){ get(at, cat) } + // Reads and writes both trigger output. // that should be intended. + //if (at.put !== undefined || at.get !== undefined) { + Gun.on('out', at); + //} + // Gun.on('out', at); + //if(!cat.back){ return } + //cat.back.on('out', at); } function get(at, cat){ var soul = at.get[_soul], node = cat.graph[soul], field = at.get[_field]; @@ -961,38 +962,36 @@ node = Gun.obj.put({_: node._}, field, node[field]); } cat.on('in', { - '@': at.req? at['#'] : 0, // temporary hack + '@': at['#'], put: Gun.graph.node(node) // TODO: BUG! Clone node! }); - return; + return true; } - Gun.on('get', at); + //Gun.on('get', at); } function input(at){ var cat = this; - if(at['@']){ + if(!at.gun){ at.gun = cat.gun } + if(at['@']){ if(!at['#']){ - at['#'] = Gun.text.random(); + at['#'] = Gun.text.random(); // TODO: Use what is used other places instead. dedup.track(at['#']); cat.on('out', at); } + //if(at.err || u === at.put){ + Gun.on.ack(at['@'], at); + //return; + //} } if(at['#'] && dedup.check(at['#'])){ return } - /* - if(at['@'] || at.err || u === at.put){ - at.gun = at.gun || cat.gun; - Gun.on.ack(at['@'], at); - return; - } - */ - if(!at.gun){ at.gun = cat.gun } - if(at.put){ + if(at.put){ if(cat.graph){ Gun.obj.map(at.put, ham, {at: at, cat: this}); // all unions must happen first, sadly. } Gun.obj.map(at.put, map, {at: at, cat: this}); + if(0 === at['@']){ return } // TODO: UNCLEAN! Temporary hack for now. Gun.on('put', at); } - if(at.get){ Gun.on('get', at) } + if(at.get){ Gun.on('get', at) } } function ham(data, key){ var cat = this.cat, graph = cat.graph; @@ -1092,7 +1091,7 @@ var is = state_is(node, field), cs = state_is(vertex, field); if(u === is || u === cs){ return true } // it is true that this is an invalid HAM comparison. var iv = rel_is(value) || value, cv = rel_is(vertex[field]) || vertex[field]; - + @@ -1162,7 +1161,7 @@ var obj = Gun.obj, obj_is = obj.is, obj_put = obj.put, obj_map = obj.map, obj_empty = obj.empty; var num = Gun.num, num_is = num.is; var _soul = Gun.val.rel._, _field = '.'; - + ;(function(){ var obj = {}, u; Gun.chain.Back = function(n, opt){ var tmp; if(-1 === n || Infinity === n){ @@ -1258,10 +1257,9 @@ as.ref.on('out', { gun: as.ref, put: as.out = as.env.graph, opt: as.opt, '#': Gun.on.ask(function(ack, ev){ - if(ack && 0 === ack.ok){ return } - ev.off(); // One response is good enough for us currently. Later we may want to adjust this. + ev.off(); // One response is good enough for us currently. Later we may want to provide an option to adjust this. if(!as.opt.any){ return } - as.opt.any.call(as.opt.as || as.gun, ack.err, ack.ok); + as.opt.any.call(as.opt.as || as.gun, ack.err, ack.ok, ev); }, as.opt) }); if(as.res){ as.res() } @@ -1293,7 +1291,7 @@ as.batch(); } - function any(at, ev){ + function any(at, ev){ function implicit(at){ // TODO: CLEAN UP!!!!! if(!at || !at.get){ return } // TODO: CLEAN UP!!!!! as.data = obj_put({}, tmp = at.get, as.data); // TODO: CLEAN UP!!!!! @@ -1304,9 +1302,9 @@ implicit(at); // TODO: CLEAN UP!!!!! } // TODO: CLEAN UP!!!!! var as = this; - if(at.err){ + if(at.err){ console.log("Please report this as an issue! Put.any.err"); - return + return } var cat = as.ref._, data = at.put, opt = as.opt, root, tmp; if(u === data){ @@ -1425,7 +1423,7 @@ var cat = back._, path = cat.path, gun = back.chain(), at = gun._; if(!path){ path = cat.path = {} } path[at.get = key] = gun; - at.stun = at.stun || cat.stun; // TODO: BUG! Clean up! This is kinda ugly. These need to be attached all the way down regardless of whether a gun chain has been cached or not for the first time. + at.stun = at.stun || cat.stun; // TODO: BUG! Clean up! This is kinda ugly. These need to be attached all the way down regardless of whether a gun chain has been cached or not for the first time. Gun.on('path', at); //gun.on('in', input, at); // For 'in' if I add my own listeners to each then I MUST do it before in gets called. If I listen globally for all incoming data instead though, regardless of individual listeners, I can transform the data there and then as well. gun.on('out', output, at); // However for output, there isn't really the global option. I must listen by adding my own listener individually BEFORE this one is ever called. @@ -1655,7 +1653,7 @@ at = obj_to(at, {put: data = cat.change = cat.put = Gun.state.ify(Gun.node.ify({}, tmp))}); } // TODO: BUG! Need to use at.put > cat.put for merged cache? - if(tmp = opt.change){ // TODO: BUG! Opt is outer scope, gun/cat/data might be iterative and thus only inner scope? Aka, we can't use it for all of them. + if(tmp = opt.change){ // TODO: BUG! Opt is outer scope, gun/cat/data might be iterative and thus only inner scope? Aka, we can't use it for all of them. if(1 === tmp){ opt.change = true; } else { @@ -1668,11 +1666,11 @@ if(last[id] == data && obj_has(last, id)){ return } last[id] = data; // TODO: PERF! Memory optimizaiton? Can we avoid this. */ - + if(last.put === data && last.get === id){ return } last.get = id; last.put = data; - + cat.last = data; if(opt.as){ any.call(opt.as, at, ev); @@ -1689,6 +1687,7 @@ if(!f || obj_has(tmp[s], f)){ ev.off(); at['@'] = 0; + at['#'] = 0; return root.on('in', at); } /* @@ -1731,6 +1730,37 @@ via: at }); } + + function ackk(at, ev){ var gun = this.gun; + var cat = gun._; + if(u !== cat.change){ return ev.off() } + // TODO: PERF! Memory. If somebody `gun.off()` we should clean up these requests. + // TODO: PERF! Memory. If peers only reply with `not` (or we never get replies) these event listeners will be left hanging - even if we get push updates that the data does exist. + if(cat.root === cat.back){ + //at.gun = cat.gun; + if(at.gun === cat.gun){ return } + at = { + get: cat.get, + gun: cat.gun, + via: at, + put: at.put[cat.get] + } + + } else { + if(obj_has(at.put, cat.get)){ return ev.off() } + at = { + get: cat.get, + gun: gun, + via: at.via? at : { + get: cat.back._.get, + gun: cat.back, + via: at + } + } + } + //at.get = at.get || cat.get; + cat.on('in', at); + } var obj = Gun.obj, obj_has = obj.has, obj_to = obj.to; var empty = {}, u; var _soul = Gun._.soul, _field = Gun._.field, _sid = Gun.on.ask._, _rid = Gun.on.ack._; @@ -1956,7 +1986,7 @@ } //if(obj_empty(value, Gun._.meta) && !(opt && opt.empty)){ // TODO: PERF! Deprecate!??? - + //} else { //console.log("value", value); //if(!(value||empty)['#']/* || !val_rel_is(value)*/){ // TODO: Performance hit!???? // TODO: BUG! WE should avoid this. So that way it is usable with gun plugin chains. @@ -2115,20 +2145,22 @@ ;require(function(module){ if(typeof JSON === 'undefined'){ throw new Error("Include JSON first: ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js") } // for old IE use if(typeof Gun === 'undefined'){ return } // TODO: localStorage is Browser only. But it would be nice if it could somehow plugin into NodeJS compatible localStorage APIs? - + var root, noop = function(){}; if(typeof window !== 'undefined'){ root = window } var store = root.localStorage || {setItem: noop, removeItem: noop, getItem: noop}; function put(at){ var err, id, opt, root = at.gun._.root; - (opt = at.opt || {}).prefix = opt.prefix || at.gun.Back('opt.prefix') || 'gun/'; + (opt = {}).prefix = (at.opt || opt).prefix || at.gun.Back('opt.prefix') || 'gun/'; Gun.graph.is(at.put, function(node, soul){ //try{store.setItem(opt.prefix + soul, Gun.text.ify(node)); try{store.setItem(opt.prefix + soul, Gun.text.ify(root._.graph[soul]||node)); }catch(e){ err = e || "localStorage failure" } }); //console.log('@@@@@@@@@@local put!'); - Gun.on.ack(at, {err: err, ok: 0}); // TODO: Reliability! Are we sure we want to have localStorage ack? + if(Gun.obj.empty(gun.Back('opt.peers'))){ + Gun.on.ack(at, {err: err, ok: 0}); // only ack if there are no peers. + } } function get(at){ var gun = at.gun, lex = at.get, soul, data, opt, u; @@ -2136,7 +2168,12 @@ (opt = at.opt || {}).prefix = opt.prefix || at.gun.Back('opt.prefix') || 'gun/'; if(!lex || !(soul = lex[Gun._.soul])){ return } data = Gun.obj.ify(store.getItem(opt.prefix + soul) || null); - if(!data){ return } // localStorage isn't trustworthy to say "not found". + if(!data){ // localStorage isn't trustworthy to say "not found". + if(Gun.obj.empty(gun.Back('opt.peers'))){ + gun.Back(-1).on('in', {'@': at['#']}); + } + return; + } if(Gun.obj.has(lex, '.')){var tmp = data[lex['.']];data = {_: data._};if(u !== tmp){data[lex['.']] = tmp}} //console.log('@@@@@@@@@@@@local get', data, at); gun.Back(-1).on('in', {'@': at['#'], put: Gun.graph.node(data)}); @@ -2145,7 +2182,7 @@ Gun.on('put', put); Gun.on('get', get); })(require, './adapters/localStorage'); - + ;require(function(module){ function r(base, body, cb, opt){ var o = base.length? {base: base} : {}; @@ -2187,7 +2224,7 @@ } if(!ws.readyState){ return setTimeout(function(){ r.ws(opt, cb, req) },100), true } ws.sending = true; - ws.send(JSON.stringify(req)); + ws.send(JSON.stringify(req)); return true; } if(ws === false){ return } @@ -2328,20 +2365,18 @@ ;require(function(module){ if(typeof JSON === 'undefined'){ throw new Error("Include JSON first: ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js") } // for old IE use if(typeof Gun === 'undefined'){ return } // TODO: window.Websocket is Browser only. But it would be nice if it could somehow merge it with lib/WSP? - + var root, noop = function(){}; if(typeof window !== 'undefined'){ root = window } var Tab = {}; Tab.on = Gun.on;//Gun.on.create(); Tab.peers = require('../polyfill/peer'); - Gun.on('get', function(at){ + Gun.on('out', function(at){ + if(at.put){ return } // TODO: BUG! Doing this for now, to debug. However puts are handled below anyways, but it would be nice if we could switch over to this for both? var gun = at.gun, opt = at.opt || {}, peers = opt.peers || gun.Back('opt.peers'); if(!peers || Gun.obj.empty(peers)){ - //setTimeout(function(){ Gun.log.once('peers', "Warning! You have no peers to connect to!"); - at.gun.Back(-1).on('in', {'@': at['#']}); - //},100); return; } var msg = at; @@ -2365,11 +2400,10 @@ var opt = at.gun.Back('opt') || {}, peers = opt.peers; if(!peers || Gun.obj.empty(peers)){ Gun.log.once('peers', "Warning! You have no peers to save to!"); - at.gun.Back(-1).on('in', {'@': at['#']}); return; } if(false === opt.websocket || (at.opt && false === at.opt.websocket)){ return } - var msg = { + var msg = at || { '#': at['#'] || Gun.text.random(9), // msg ID '$': at.put // msg BODY }; @@ -2386,7 +2420,7 @@ Tab.peers.request.createServer(function(req, res){ if(!req || !res || !req.body || !req.headers){ return } var msg = req.body; - gun.on('in', req.body); + gun.on('in', req.body); return; // AUTH for non-replies. if(server.msg(msg['#'])){ return } @@ -2395,7 +2429,7 @@ if(Tab.ons[tmp = msg['@'] || msg['#']]){ Tab.on(tmp, [msg['!'], msg['$']]); } - return + return } if(msg['$'] && msg['$']['#']){ return server.get(req, res) } else { return server.put(req, res) } @@ -2440,12 +2474,12 @@ Gun.obj.del(server.msg.debounce, id); }); },500); - if(server.msg.debounce[id]){ + if(server.msg.debounce[id]){ return server.msg.debounce[id] = Gun.time.is(), id; } server.msg.debounce[id] = Gun.time.is(); return; - }; + }; server.msg.debounce = server.msg.debounce || {}; }); diff --git a/lib/wsp/client.js b/lib/wsp/client.js index d1c1082a..80b408f6 100644 --- a/lib/wsp/client.js +++ b/lib/wsp/client.js @@ -91,7 +91,7 @@ Gun.on('opt', function (context) { if (!request || !request.body) { return; } - + root.on('in', request.body); }); }); diff --git a/lib/wsp/server-push.js b/lib/wsp/server-push.js index 5cd20470..727f8d1e 100644 --- a/lib/wsp/server-push.js +++ b/lib/wsp/server-push.js @@ -63,21 +63,19 @@ function attach (gun, server) { root._.servers.push(server); var pool = {}; var sid = Gun.text.random(); - server.on('connection', function (socket) { socket.id = socket.id || Gun.text.random(10); pool[socket.id] = socket; - + /* socket.on('message', function (message) { var data = Gun.obj.ify(message); if (!data || !data.body) { return; } - root.on('in', data.body); }); - + */ socket.once('close', function () { delete pool[socket.id]; }); @@ -92,7 +90,6 @@ function attach (gun, server) { headers: { 'gun-sid': sid }, body: context, }; - send(msg, pool); }); } diff --git a/lib/wsp/server.js b/lib/wsp/server.js index 9c486f64..3c56a425 100644 --- a/lib/wsp/server.js +++ b/lib/wsp/server.js @@ -150,9 +150,7 @@ Gun.on('opt', function (at) { req.url = url.format(req.url); } // var msg = req.body; - // console.log('SERVER', req); gun.on('in', req.body); - // console.log('-----------------'); // // AUTH for non-replies. // if(gun.wsp.msg(msg['#'])){ return } // gun.wsp.on('network', Gun.obj.copy(req)); diff --git a/lib/wsp/ws.js b/lib/wsp/ws.js index 45dc100a..5b95932d 100644 --- a/lib/wsp/ws.js +++ b/lib/wsp/ws.js @@ -1,4 +1,4 @@ -var Gun = require('../../gun') +var Gun = require('../../gun') , url = require('url'); module.exports = function(wss, server, opt){ wss.on('connection', function(ws){ @@ -27,7 +27,7 @@ module.exports = function(wss, server, opt){ (reply.headers = reply.headers || {})['ws-rid'] = msg.headers['ws-rid']; } try{ws.send(Gun.text.ify(reply)); - }catch(e){} // juuuust in case. + }catch(e){} // juuuust in case. }); }); ws.off = function(m){