Merge branch 'develop' of https://github.com/amark/gun into develop

This commit is contained in:
Jesse Gibson 2016-08-08 17:40:36 -06:00
commit 4a0fb994be
11 changed files with 218 additions and 78 deletions

View File

@ -12,8 +12,8 @@
GUN is a realtime, distributed, offline-first, graph database engine. Lightweight and powerful, at just **~9KB** gzipped. GUN is a realtime, distributed, offline-first, graph database engine. Lightweight and powerful, at just **~9KB** gzipped.
<a href="https://youtu.be/-i-11T5ZI9o" title="1 minute demo of fault tolerance"><img src="http://img.youtube.com/vi/-i-11T5ZI9o/0.jpg" width="425px"></a>
[![1 minute demo of fault tolerance](http://img.youtube.com/vi/-i-11T5ZI9o/0.jpg)](https://youtu.be/-i-11T5ZI9o) <a href="https://youtu.be/-FN_J3etdvY" title="1 minute demo of fault tolerance"><img src="http://img.youtube.com/vi/-FN_J3etdvY/0.jpg" width="425px"></a>
## Why? ## Why?
@ -89,7 +89,7 @@ Designed with ♥ by Mark Nadal, the gun team, and many amazing contributors. L
Thanks to the following people who have contributed to GUN, via code, issues, or conversation (this list has quickly become tremendously behind! We'll probably turn this into a dedicated wiki page so you can add yourself): Thanks to the following people who have contributed to GUN, via code, issues, or conversation (this list has quickly become tremendously behind! We'll probably turn this into a dedicated wiki page so you can add yourself):
[agborkowski](https://github.com/agborkowski); [alexlafroscia](https://github.com/alexlafroscia); [anubiann00b](https://github.com/anubiann00b); [bromagosa](https://github.com/bromagosa); [coolaj86](https://github.com/coolaj86); [d-oliveros](https://github.com/d-oliveros), [danscan](https://github.com/danscan); **[forrestjt](https://github.com/forrestjt) ([file.js](https://github.com/amark/gun/blob/master/lib/file.js))**; [gedw99](https://github.com/gedw99); [HelloCodeMing](https://github.com/HelloCodeMing); **[JosePedroDias](https://github.com/josepedrodias) ([graph visualizer](http://acor.sl.pt:9966))**; **[jveres](https://github.com/jveres) ([todoMVC](https://github.com/jveres/todomvc) [live demo](http://todos.loqali.com/))**; [ndarilek](https://github.com/ndarilek); [onetom](https://github.com/onetom); [phpnode](https://github.com/phpnode); [PsychoLlama](https://github.com/PsychoLlama); **[RangerMauve](https://github.com/RangerMauve) ([schema](https://github.com/gundb/gun-schema))**; [riston](https://github.com/riston); [rootsical](https://github.com/rootsical); [rrrene](https://github.com/rrrene); [sbeleidy](https://github.com/sbeleidy) [ssr1ram](https://github.com/ssr1ram); [Xe](https://github.com/Xe); [zot](https://github.com/zot); [agborkowski](https://github.com/agborkowski); [alexlafroscia](https://github.com/alexlafroscia); [anubiann00b](https://github.com/anubiann00b); [bromagosa](https://github.com/bromagosa); [coolaj86](https://github.com/coolaj86); [d-oliveros](https://github.com/d-oliveros), [danscan](https://github.com/danscan); **[forrestjt](https://github.com/forrestjt) ([file.js](https://github.com/amark/gun/blob/master/lib/file.js))**; [gedw99](https://github.com/gedw99); [HelloCodeMing](https://github.com/HelloCodeMing); **[JosePedroDias](https://github.com/josepedrodias) ([graph visualizer](http://acor.sl.pt:9966))**; **[jveres](https://github.com/jveres) ([todoMVC](https://github.com/jveres/todomvc))**; [ndarilek](https://github.com/ndarilek); [onetom](https://github.com/onetom); [phpnode](https://github.com/phpnode); [PsychoLlama](https://github.com/PsychoLlama); **[RangerMauve](https://github.com/RangerMauve) ([schema](https://github.com/gundb/gun-schema))**; [riston](https://github.com/riston); [rootsical](https://github.com/rootsical); [rrrene](https://github.com/rrrene); [sbeleidy](https://github.com/sbeleidy) [ssr1ram](https://github.com/ssr1ram); **[Stefdv](https://github.com/stefdv) ([Polymer/web components](http://stefdv.github.io/gun-collection/components/gun-collection/))**; [Xe](https://github.com/Xe); [zot](https://github.com/zot);
[ayurmedia](https://github.com/ayurmedia); [ayurmedia](https://github.com/ayurmedia);
This list of contributors was manually compiled and alphabetically sorted. If we missed you, please submit an issue so we can get you added! This list of contributors was manually compiled and alphabetically sorted. If we missed you, please submit an issue so we can get you added!

30
examples/express-auth.js Normal file
View File

@ -0,0 +1,30 @@
console.log("If modules not found, run `npm install` in /example folder!"); // git subtree push -P examples heroku master // OR // git subtree split -P examples master && git push heroku [['HASH']]:master --force
var port = process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 80;
var express = require('express');
var app = express();
var Gun = require('gun');
var gun = Gun({
file: 'data.json',
s3: {
key: '', // AWS Access Key
secret: '', // AWS Secret Token
bucket: '' // The bucket you want to save into
}
});
gun.wsp(app/*, function(req, res, next){
console.log("auth!", req, req.body['#']);
if('get' === req.method){
if('example/todo/data' === req.body['#']){
next(req, res);
}
}
if('put' === req.method){
res({body: {err: "Permission denied!"}});
}
}*/);
app.use(express.static(__dirname)).listen(port);
console.log('Server started on port ' + port + ' with /gun');

82
gun.js
View File

@ -127,9 +127,17 @@
} }
Type.time = {}; Type.time = {};
Type.time.is = function(t){ return t? t instanceof Date : (+new Date().getTime()) } Type.time.is = function(t){ return t? t instanceof Date : (+new Date().getTime()) }
Type.time.now = function(t){ Type.time.now = (function(){
return ((t=t||Type.time.is()) > (Type.time.now.last || -Infinity)? (Type.time.now.last = t) : Type.time.now(t + 1)) + (Type.time.now.drift || 0); // TODO: BUG? Should this go on the inside? var time = Type.time.is, last = -Infinity, n = 0, d = 1000;
}; return function(){
var t = time();
if(last < t){
n = 0;
return last = t;
}
return last = t + ((n += 1) / d);
}
}());
}(Util)); }(Util));
;(function(exports){ // On event emitter generic javascript utility. ;(function(exports){ // On event emitter generic javascript utility.
function On(){}; function On(){};
@ -530,13 +538,15 @@
var gun = this, root = (gun.__ && gun.__.gun)? gun.__.gun : (gun._ = gun.__ = {gun: gun}).gun.chain(); // if root does not exist, then create a root chain. var gun = this, root = (gun.__ && gun.__.gun)? gun.__.gun : (gun._ = gun.__ = {gun: gun}).gun.chain(); // if root does not exist, then create a root chain.
root.__.by = root.__.by || function(f){ return gun.__.by[f] = gun.__.by[f] || {} }; root.__.by = root.__.by || function(f){ return gun.__.by[f] = gun.__.by[f] || {} };
root.__.graph = root.__.graph || {}; root.__.graph = root.__.graph || {};
root.__.opt = root.__.opt || {}; root.__.opt = root.__.opt || {peers: {}};
root.__.opt.wire = root.__.opt.wire || {}; root.__.opt.wire = root.__.opt.wire || {};
if(Gun.text.is(opt)){ opt = {peers: opt} } if(Gun.text.is(opt)){ opt = {peers: opt} }
if(Gun.list.is(opt)){ opt = {peers: opt} } if(Gun.list.is(opt)){ opt = {peers: opt} }
if(Gun.text.is(opt.peers)){ opt.peers = [opt.peers] } if(Gun.text.is(opt.peers)){ opt.peers = [opt.peers] }
if(Gun.list.is(opt.peers)){ opt.peers = Gun.obj.map(opt.peers, function(n,f,m){ m(n,{}) }) } if(Gun.list.is(opt.peers)){ opt.peers = Gun.obj.map(opt.peers, function(n,f,m){ m(n,{}) }) }
root.__.opt.peers = opt.peers || gun.__.opt.peers || {}; Gun.obj.map(opt.peers, function(v, f){
root.__.opt.peers[f] = v;
});
Gun.obj.map(opt.wire, function(h, f){ Gun.obj.map(opt.wire, function(h, f){
if(!Gun.fns.is(h)){ return } if(!Gun.fns.is(h)){ return }
root.__.opt.wire[f] = h; root.__.opt.wire[f] = h;
@ -908,6 +918,11 @@
} }
function each(val, field){ function each(val, field){
//if(!Gun.is.rel(val)){ path.call(this.gun, null, val, field);return;} //if(!Gun.is.rel(val)){ path.call(this.gun, null, val, field);return;}
if(opt.node){
if(!Gun.is.rel(val)){
return;
}
}
cb.hash[this.soul + field] = cb.hash[this.soul + field] || this.gun.path(field, path, {chain: chain, via: 'map'}); // TODO: path should reuse itself! We shouldn't have to do it ourselves. cb.hash[this.soul + field] = cb.hash[this.soul + field] || this.gun.path(field, path, {chain: chain, via: 'map'}); // TODO: path should reuse itself! We shouldn't have to do it ourselves.
// TODO: // TODO:
// 1. Ability to turn off an event. // automatically happens within path since reusing is manual? // 1. Ability to turn off an event. // automatically happens within path since reusing is manual?
@ -1132,7 +1147,7 @@
}(Gun)); }(Gun));
var root = this || {}; // safe for window, global, root, and 'use strict'. var root = this || {}; // safe for window, global, root, and 'use strict'.
if(root.window){ (root = window).Gun = Gun } if(typeof window !== "undefined"){ (root = window).Gun = Gun }
if(typeof module !== "undefined" && module.exports){ module.exports = Gun } if(typeof module !== "undefined" && module.exports){ module.exports = Gun }
if(typeof global !== "undefined"){ root = global; } if(typeof global !== "undefined"){ root = global; }
root.console = root.console || {log: function(s){ return s }}; // safe for old browsers root.console = root.console || {log: function(s){ return s }}; // safe for old browsers
@ -1163,7 +1178,8 @@
opt = opt || {}; opt = opt || {};
var tab = gun.tab = gun.tab || {}; var tab = gun.tab = gun.tab || {};
tab.store = tab.store || Tab.store; tab.store = tab.store || Tab.store;
tab.request = tab.request || request; tab.request = tab.request || Gun.request;
if(!tab.request){ throw new Error("Default GUN driver could not find default network abstraction.") }
tab.request.s = tab.request.s || {}; tab.request.s = tab.request.s || {};
tab.headers = opt.headers || {}; tab.headers = opt.headers || {};
tab.headers['gun-sid'] = tab.headers['gun-sid'] || Gun.text.random(); // stream id tab.headers['gun-sid'] = tab.headers['gun-sid'] || Gun.text.random(); // stream id
@ -1173,7 +1189,8 @@
var soul = lex[Gun._.soul]; var soul = lex[Gun._.soul];
if(!soul){ return } if(!soul){ return }
cb = cb || function(){}; cb = cb || function(){};
(opt.headers = Gun.obj.copy(tab.headers)).id = tab.msg(); var ropt = {};
(ropt.headers = Gun.obj.copy(tab.headers)).id = tab.msg();
(function local(soul, cb){ (function local(soul, cb){
tab.store.get(tab.prefix + soul, function(err, data){ tab.store.get(tab.prefix + soul, function(err, data){
if(!data){ return } // let the peers handle no data. if(!data){ return } // let the peers handle no data.
@ -1184,11 +1201,11 @@
}); });
}(soul, cb)); }(soul, cb));
if(!(cb.local = opt.local)){ if(!(cb.local = opt.local)){
tab.request.s[opt.headers.id] = tab.error(cb, "Error: Get failed!", function(reply){ tab.request.s[ropt.headers.id] = tab.error(cb, "Error: Get failed!", function(reply){
setTimeout(function(){ tab.put(Gun.is.graph.ify(reply.body), function(){}, {local: true, peers: {}}) },1); // and flush the in memory nodes of this graph to localStorage after we've had a chance to union on it. setTimeout(function(){ tab.put(Gun.is.graph.ify(reply.body), function(){}, {local: true, peers: {}}) },1); // and flush the in memory nodes of this graph to localStorage after we've had a chance to union on it.
}); });
Gun.obj.map(opt.peers || gun.__.opt.peers, function(peer, url){ var p = {}; Gun.obj.map(opt.peers || gun.__.opt.peers, function(peer, url){ var p = {};
tab.request(url, lex, tab.request.s[opt.headers.id], opt); tab.request(url, lex, tab.request.s[ropt.headers.id], ropt);
cb.peers = true; cb.peers = true;
}); });
var node = gun.__.graph[soul]; var node = gun.__.graph[soul];
@ -1198,18 +1215,18 @@
} tab.peers(cb); } tab.peers(cb);
} }
tab.put = tab.put || function(graph, cb, opt){ tab.put = tab.put || function(graph, cb, opt){
//console.log("SAVE", graph);
cb = cb || function(){}; cb = cb || function(){};
opt = opt || {}; opt = opt || {};
(opt.headers = Gun.obj.copy(tab.headers)).id = tab.msg(); var ropt = {};
(ropt.headers = Gun.obj.copy(tab.headers)).id = tab.msg();
Gun.is.graph(graph, function(node, soul){ Gun.is.graph(graph, function(node, soul){
if(!gun.__.graph[soul]){ return } if(!gun.__.graph[soul]){ return }
tab.store.put(tab.prefix + soul, gun.__.graph[soul], function(err){if(err){ cb({err: err}) }}); tab.store.put(tab.prefix + soul, gun.__.graph[soul], function(err){if(err){ cb({err: err}) }});
}); });
if(!(cb.local = opt.local)){ if(!(cb.local = opt.local)){
tab.request.s[opt.headers.id] = tab.error(cb, "Error: Put failed!"); tab.request.s[ropt.headers.id] = tab.error(cb, "Error: Put failed!");
Gun.obj.map(opt.peers || gun.__.opt.peers, function(peer, url){ Gun.obj.map(opt.peers || gun.__.opt.peers, function(peer, url){
tab.request(url, graph, tab.request.s[opt.headers.id], opt); tab.request(url, graph, tab.request.s[ropt.headers.id], ropt);
cb.peers = true; cb.peers = true;
}); });
} tab.peers(cb); } tab.peers(cb);
@ -1287,16 +1304,25 @@
gun.__.opt.wire.get = gun.__.opt.wire.get || tab.get; gun.__.opt.wire.get = gun.__.opt.wire.get || tab.get;
gun.__.opt.wire.put = gun.__.opt.wire.put || tab.put; gun.__.opt.wire.put = gun.__.opt.wire.put || tab.put;
gun.__.opt.wire.key = gun.__.opt.wire.key || tab.key; gun.__.opt.wire.key = gun.__.opt.wire.key || tab.key;
Tab.request = tab.request;
Gun.Tab = Tab;
}); });
}.bind(this || module)({}));
;(function(Tab){
var request = (function(){ var request = (function(){
function r(base, body, cb, opt){ function r(base, body, cb, opt){ opt = opt || {};
opt = opt || (base.length? {base: base} : base); var o = base.length? {base: base} : {};
opt.base = opt.base || base; o.base = opt.base || base;
opt.body = opt.body || body; o.body = opt.body || body;
o.headers = opt.headers;
o.url = opt.url;
cb = cb || function(){}; cb = cb || function(){};
if(!opt.base){ return } if(!o.base){ return }
r.transport(opt, cb); r.transport(o, cb);
} }
r.createServer = function(fn){ r.createServer.s.push(fn) } r.createServer = function(fn){ r.createServer.s.push(fn) }
r.createServer.ing = function(req, cb){ r.createServer.ing = function(req, cb){
@ -1311,7 +1337,7 @@
r.jsonp(opt, cb); r.jsonp(opt, cb);
} }
r.ws = function(opt, cb){ r.ws = function(opt, cb){
var ws, WS = window.WebSocket || window.mozWebSocket || window.webkitWebSocket; var ws, WS = r.WebSocket || window.WebSocket || window.mozWebSocket || window.webkitWebSocket;
if(!WS){ return } if(!WS){ return }
if(ws = r.ws.peers[opt.base]){ if(ws = r.ws.peers[opt.base]){
if(!ws.readyState){ return setTimeout(function(){ r.ws(opt, cb) },10), true } if(!ws.readyState){ return setTimeout(function(){ r.ws(opt, cb) },10), true }
@ -1328,9 +1354,10 @@
return true; return true;
} }
if(ws === false){ return } if(ws === false){ return }
ws = r.ws.peers[opt.base] = new WS(opt.base.replace('http','ws')); try{ws = r.ws.peers[opt.base] = new WS(opt.base.replace('http','ws'));
}catch(e){}
ws.onopen = function(o){ r.back = 2; r.ws(opt, cb) }; ws.onopen = function(o){ r.back = 2; r.ws(opt, cb) };
ws.onclose = window.onbeforeunload = function(c){ ws.onclose = function(c){
if(!c){ return } if(!c){ return }
if(ws && ws.close instanceof Function){ ws.close() } if(ws && ws.close instanceof Function){ ws.close() }
if(1006 === c.code){ // websockets cannot be used if(1006 === c.code){ // websockets cannot be used
@ -1343,6 +1370,7 @@
r.ws(opt, function(){}); // opt here is a race condition, is it not? Does this matter? r.ws(opt, function(){}); // opt here is a race condition, is it not? Does this matter?
}, r.back *= r.backoff); }, r.back *= r.backoff);
}; };
if(typeof window !== "undefined"){ window.onbeforeunload = ws.onclose; }
ws.onmessage = function(m){ ws.onmessage = function(m){
if(!m || !m.data){ return } if(!m || !m.data){ return }
var res; var res;
@ -1351,15 +1379,17 @@
if(!res){ return } if(!res){ return }
res.headers = res.headers || {}; res.headers = res.headers || {};
if(res.headers['ws-rid']){ return (r.ws.cbs[res.headers['ws-rid']]||function(){})(null, res) } if(res.headers['ws-rid']){ return (r.ws.cbs[res.headers['ws-rid']]||function(){})(null, res) }
//Gun.log("We have a pushed message!", res);
if(res.body){ r.createServer.ing(res, function(res){ r(opt.base, null, null, res)}) } // emit extra events. if(res.body){ r.createServer.ing(res, function(res){ r(opt.base, null, null, res)}) } // emit extra events.
}; };
ws.onerror = function(e){ Gun.log(e); }; ws.onerror = function(e){ console.log(e); };
return true; return true;
} }
r.ws.peers = {}; r.ws.peers = {};
r.ws.cbs = {}; r.ws.cbs = {};
r.jsonp = function(opt, cb){ r.jsonp = function(opt, cb){
if(typeof window === "undefined"){
return cb("JSONP is currently browser only.");
}
//Gun.log("jsonp send", opt); //Gun.log("jsonp send", opt);
r.jsonp.ify(opt, function(url){ r.jsonp.ify(opt, function(url){
//Gun.log(url); //Gun.log(url);
@ -1442,4 +1472,6 @@
} }
return r; return r;
}()); }());
if(typeof window !== "undefined"){ Gun.request = request }
if(typeof module !== "undefined" && module.exports){ module.exports.request = request }
}.bind(this || module)({})); }.bind(this || module)({}));

View File

@ -40,12 +40,14 @@ Gun.on('opt').event(function(gun, opts) {
gun.opt({wire: { gun.opt({wire: {
get: function get(lex, cb, o){ get: function get(lex, cb, o){
var node, soul = lex[Gun._.soul]; var node, soul = lex[Gun._.soul];
setImmediate(function(){
node = all.nodes[soul]; node = all.nodes[soul];
if(!node){ return cb(null) } if(!node){ return cb(null) }
cb(null, node); cb(null, node);
node = Gun.is.node.soul.ify({}, soul); node = Gun.is.node.soul.ify({}, soul);
cb(null, node); // end. cb(null, node); // end.
cb(null, {}); // done. cb(null, {}); // done.
});
}, },
put: function(graph, cb, o){ put: function(graph, cb, o){
for (key in gun.__.graph) all.nodes[key]=gun.__.graph[key]||graph[key]; for (key in gun.__.graph) all.nodes[key]=gun.__.graph[key]||graph[key];

View File

@ -2,7 +2,7 @@
console.log("Hello wonderful person! :) I'm mark@gunDB.io, message me for help or with hatemail. I want to hear from you! <3"); console.log("Hello wonderful person! :) I'm mark@gunDB.io, message me for help or with hatemail. I want to hear from you! <3");
var Gun = require('../gun'); var Gun = require('../gun');
require('./s3'); require('./s3');
require('./wsp');
require('./file'); require('./file');
require('./wsp');
module.exports = Gun; module.exports = Gun;
}()); }());

View File

@ -1,5 +1,5 @@
;(function(wsp){ ;(function(wsp){
var Gun = require('../gun') var Gun = require('../gun')
, ws = require('ws').Server , ws = require('ws').Server
, http = require('./http') , http = require('./http')
, url = require('url'); , url = require('url');
@ -10,10 +10,10 @@
server = gun.__.opt.ws.server = gun.__.opt.ws.server || opt.ws.server || server; server = gun.__.opt.ws.server = gun.__.opt.ws.server || opt.ws.server || server;
require('./ws')(gun.wsp.ws = gun.wsp.ws || new ws(gun.__.opt.ws), function(req, res){ require('./ws')(gun.wsp.ws = gun.wsp.ws || new ws(gun.__.opt.ws), function(req, res){
var ws = this; var ws = this;
req.headers['gun-sid'] = ws.sid = ws.sid? ws.sid : req.headers['gun-sid']; req.headers['gun-sid'] = ws.sid = (ws.sid? ws.sid : req.headers['gun-sid']);
ws.sub = ws.sub || gun.wsp.on('network').event(function(msg){ ws.sub = ws.sub || gun.wsp.on('network').event(function(msg){
if(!ws || !ws.send || !ws._socket || !ws._socket.writable){ return this.off() } if(!ws || !ws.send || !ws._socket || !ws._socket.writable){ return this.off() }
if(!msg || (msg.headers && msg.headers['gun-sid'] === ws.sid)){ return } if(!msg || (ws.sid && msg.headers && msg.headers['gun-sid'] === ws.sid)){ return }
if(msg && msg.headers){ delete msg.headers['ws-rid'] } if(msg && msg.headers){ delete msg.headers['ws-rid'] }
// TODO: BUG? ^ What if other peers want to ack? Do they use the ws-rid or a gun declared id? // TODO: BUG? ^ What if other peers want to ack? Do they use the ws-rid or a gun declared id?
try{ws.send(Gun.text.ify(msg)); try{ws.send(Gun.text.ify(msg));
@ -23,7 +23,8 @@
}); });
gun.__.opt.ws.port = gun.__.opt.ws.port || opt.ws.port || port || 80; gun.__.opt.ws.port = gun.__.opt.ws.port || opt.ws.port || port || 80;
} }
var wsp = gun.wsp = gun.wsp || function(server){ var wsp = gun.wsp = gun.wsp || function(server, auth){
gun.wsp.auth = auth;
if(!server){ return gun } if(!server){ return gun }
if(Gun.fns.is(server.address)){ if(Gun.fns.is(server.address)){
if(server.address()){ if(server.address()){
@ -112,15 +113,24 @@
// all streams, technically PATCH but implemented as PUT or POST, are forwarded to other trusted peers // all streams, technically PATCH but implemented as PUT or POST, are forwarded to other trusted peers
// except for the ones that are listed in the message as having already been sending to. // except for the ones that are listed in the message as having already been sending to.
// all states, implemented with GET, are replied to the source that asked for it. // all states, implemented with GET, are replied to the source that asked for it.
function tran(req, res){ function flow(req, res){
if(!req || !res || !req.body || !req.headers || !req.headers.id){ return }
if(gun.wsp.msg(req.headers.id)){ return }
req.method = req.body? 'put' : 'get';
gun.wsp.on('network').emit(Gun.obj.copy(req)); gun.wsp.on('network').emit(Gun.obj.copy(req));
if(req.headers.rid){ return } // no need to process. if(req.headers.rid){ return } // no need to process.
if(Gun.is.lex(req.body)){ return tran.get(req, res) } if(Gun.is.lex(req.body)){ return tran.get(req, res) }
else { return tran.put(req, res) } else { return tran.put(req, res) }
cb({body: {hello: 'world'}}); }
function tran(req, res){
if(!req || !res || !req.body || !req.headers || !req.headers.id){ return }
if(gun.wsp.msg(req.headers.id)){ return }
req.method = (req.body && !Gun.is.lex(req.body))? 'put' : 'get';
if(gun.wsp.auth){ return gun.wsp.auth(req, function(reply){
if(!reply.headers){ reply.headers = {} }
if(!reply.headers['Content-Type']){ reply.headers['Content-Type'] = tran.json }
if(!reply.rid){ reply.headers.rid = req.headers.id }
if(!reply.id){ reply.headers.id = gun.wsp.msg() }
res(reply);
}, flow) }
else { return flow(req, res) }
} }
tran.get = function(req, cb){ tran.get = function(req, cb){
var key = req.url.key var key = req.url.key
@ -140,7 +150,7 @@
//Gun.log("GET!", req); //Gun.log("GET!", req);
key = req.body; key = req.body;
//Gun.log("tran.get", key); //Gun.log("tran.get", key);
var opt = {key: false}; var opt = {key: false, local: true};
//gun.get(key, function(err, node){ //gun.get(key, function(err, node){
(gun.__.opt.wire.get||function(key, cb){cb(null,null)})(key, function(err, node){ (gun.__.opt.wire.get||function(key, cb){cb(null,null)})(key, function(err, node){
//Gun.log("tran.get", key, "<---", err, node); //Gun.log("tran.get", key, "<---", err, node);
@ -193,7 +203,7 @@
if(err){ return cb({headers: reply.headers, body: {err: err || "Failed."}}) } // TODO: err should already be an error object? if(err){ return cb({headers: reply.headers, body: {err: err || "Failed."}}) } // TODO: err should already be an error object?
cb({headers: reply.headers, body: {ok: ok || "Persisted."}}); cb({headers: reply.headers, body: {ok: ok || "Persisted."}});
//Gun.log("tran.put <------------------------", ok); //Gun.log("tran.put <------------------------", ok);
}); }, {local: true});
}).err){ cb({headers: reply.headers, body: {err: req.err || "Union failed."}}) } }).err){ cb({headers: reply.headers, body: {err: req.err || "Union failed."}}) }
} else { } else {
cb({headers: reply.headers, body: {err: "Not a valid graph!"}}); cb({headers: reply.headers, body: {err: "Not a valid graph!"}});
@ -209,22 +219,55 @@
wsp(opt.server); wsp(opt.server);
} }
setTimeout(function(){ // hack it in :( for now, since 0.4.x will allow us to have multiple drivers. if(gun.wsp.driver){ return }
var proxy = gun.__.opt.wire; var driver = gun.wsp.driver = {};
var driver = { var noop = function(){};
put: function(graph, cb, opt){ var get = gun.__.opt.wire.get || noop;
proxy.put(graph, cb, opt); var put = gun.__.opt.wire.put || noop;
var msg = { var driver = {
headers: {'Content-Type': 'application/json', id: gun.wsp.msg()}, put: function(graph, cb, opt){
body: graph put(graph, cb, opt);
}; opt = opt || {};
gun.wsp.on('network').emit(msg); if(opt.local){ return }
}, var id = gun.wsp.msg();
get: proxy.get gun.wsp.on('network').emit({ // sent to dynamic peers!
headers: {'Content-Type': 'application/json', id: id},
body: graph
});
var ropt = {headers:{}, WebSocket: WebSocket};
ropt.headers.id = id;
Gun.obj.map(opt.peers || gun.__.opt.peers, function(peer, url){
Gun.request(url, graph, function(err, reply){
reply.body = reply.body || reply.chunk || reply.end || reply.write;
if(err || !reply || (err = reply.body && reply.body.err)){
return cb({err: Gun.log(err || "Put failed.") });
}
cb(null, reply.body);
}, ropt);
});
},
get: function(lex, cb, opt){
get(lex, cb, opt);
opt = opt || {};
if(opt.local){ return }
if(!Gun.request){ return console.log("Server could not find default network abstraction.") }
var ropt = {headers:{}};
ropt.headers.id = gun.wsp.msg();
Gun.obj.map(opt.peers || gun.__.opt.peers, function(peer, url){
Gun.request(url, lex, function(err, reply){
reply.body = reply.body || reply.chunk || reply.end || reply.write;
if(err || !reply || (err = reply.body && reply.body.err)){
return cb({err: Gun.log(err || "Get failed.") });
}
cb(null, reply.body);
}, ropt);
});
} }
gun.__.opt.wire = driver; }
gun.opt({wire: driver}, true); var WebSocket = require('ws');
},1); Gun.request.WebSocket = WebSocket;
Gun.request.createServer(gun.wsp.wire);
gun.__.opt.wire = driver;
gun.opt({wire: driver}, true);
}); });
}({})); }({}));

View File

@ -1,6 +1,6 @@
{ {
"name": "gun", "name": "gun",
"version": "0.3.92", "version": "0.3.991",
"description": "Graph engine", "description": "Graph engine",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -3799,7 +3799,7 @@ describe('Gun', function(){
}); });
it("get context", function(done){ // TODO: HUH?????? This was randomly causing errors? it("get context", function(done){ // TODO: HUH?????? This was randomly causing errors?
var gun = Gun(); var gun = Gun();
var ref = gun.get('ctx/lol').get('ctx/foo').put({hello: 'world'}); var ref = gun.get('ctx/lol').get('ctx/foo').put({hello: 'world'});
gun.get('ctx/lol').val(function(implicit){ gun.get('ctx/lol').val(function(implicit){
done.fail = true; done.fail = true;
@ -3975,29 +3975,31 @@ describe('Gun', function(){
it("Don't put on parents", function(done){ // TODO: ADD TO 0.5 BRANCH! // Another Stefdv find. it("Don't put on parents", function(done){ // TODO: ADD TO 0.5 BRANCH! // Another Stefdv find.
var test = gun.get('test'); var test = gun.get('test');
test.path('try.this.at.lvl4').put({msg:'hoi'}) test.path('try.this.at.lvl4').put({msg:'hoi'});
test.val(function(node,b){ setTimeout(function(){ // TODO: Is this cheating??
delete node._; test.val(function(node,b){
expect(Gun.obj.empty(node, 'try')).to.be.ok(); delete node._;
node = Gun.obj.copy(gun.__.graph[Gun.is.rel(node.try)]); expect(Gun.obj.empty(node, 'try')).to.be.ok();
node = Gun.obj.copy(gun.__.graph[Gun.is.rel(node.try)]);
delete node._; delete node._;
expect(Gun.obj.empty(node, 'this')).to.be.ok(); expect(Gun.obj.empty(node, 'this')).to.be.ok();
node = Gun.obj.copy(gun.__.graph[Gun.is.rel(node.this)]); node = Gun.obj.copy(gun.__.graph[Gun.is.rel(node.this)]);
delete node._;
expect(Gun.obj.empty(node, 'at')).to.be.ok();
node = Gun.obj.copy(gun.__.graph[Gun.is.rel(node.at)]);
delete node._; delete node._;
expect(Gun.obj.empty(node, 'at')).to.be.ok(); expect(Gun.obj.empty(node, 'lvl4')).to.be.ok();
node = Gun.obj.copy(gun.__.graph[Gun.is.rel(node.at)]); node = Gun.obj.copy(gun.__.graph[Gun.is.rel(node.lvl4)]);
delete node._; delete node._;
expect(Gun.obj.empty(node, 'lvl4')).to.be.ok(); expect(Gun.obj.empty(node, 'msg')).to.be.ok();
node = Gun.obj.copy(gun.__.graph[Gun.is.rel(node.lvl4)]); expect(node.msg).to.be('hoi');
done();
delete node._; });
expect(Gun.obj.empty(node, 'msg')).to.be.ok(); },100);
expect(node.msg).to.be('hoi');
done();
});
}); });
}); });

15
test/server/http.js Normal file
View File

@ -0,0 +1,15 @@
//client.js writes data up to a listening hub.js, which relays to a server.js that reads the data.
var http = require('http');
var Gun = require('../../index');
var gun = Gun({
file: 'http.json'
});
var server = http.createServer(function(req, res){});
gun.wsp(server);
server.listen(8080);
console.log('Server started on port ' + 8080 + ' with /gun');

View File

@ -0,0 +1,9 @@
var Gun = require('../../index');
var location = {host:"localhost"};
var gun = Gun( { file: 'read.json', peers: ['http://' + location.host + ':8080/gun'] });
gun.get( 'data' ).path('stuff').map(function(val,field){ console.log( field, "=", val ); } );
console.log( "done... wait forever?" );

View File

@ -0,0 +1,7 @@
var Gun = require('../../index');
var location = {host:"localhost"};
var gun = Gun( { file: 'write.json', peers: ['http://' + location.host + ':8080/gun'] });
gun.get( 'data' ).path('stuff').put({a: {data: 1}, b: {data: 2}});