diff --git a/examples/package.json b/examples/package.json index 9c2745e3b..59cbda86c 100644 --- a/examples/package.json +++ b/examples/package.json @@ -8,7 +8,7 @@ } , "dependencies": { "express": "~>4.9.0", - "gun": "~>0.2.4" + "gun": "~>0.3.0" } , "scripts": { "start": "node http.js", diff --git a/examples/todo/index.html b/examples/todo/index.html index 92dd811c2..e0a040417 100644 --- a/examples/todo/index.html +++ b/examples/todo/index.html @@ -22,7 +22,7 @@

ToDo List

$("#todos").innerHTML = todoHTML; }); $("#addToDo").onsubmit = function(){ - gun.set(($("#todoItem").value||'').toString().replace(/\", key); - (function local(key, cb){ - var path = (path = Gun.is.soul(key))? tab.prefix + tab.prenode + path - : 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; - cb(null, graph); - (graph = {})[soul] = Gun.union.pseudo(soul); // end. - return cb(null, graph); - } else - if(Gun.obj.is(node)){ - Gun.obj.map(node, function(rel){ if(Gun.is.soul(rel)){ local(rel, cb) } }); - cb(null, {}); - } + (function local(key, cb){return; // TODO: BUG! UNDO! + tab.store.get(tab.prefix + key, function(err, data){ + if(err){ return cb(err) } + cb(err, Gun.is.graph.ify(data)); // node + cb(err, Gun.is.node.soul.ify({}, Gun.is.node.soul(data))); // end + cb(err, {}); // terminate + }); }(key, cb)); if(!(cb.local = opt.local)){ Gun.obj.map(opt.peers || gun.__.opt.peers, function(peer, url){ var p = {}; @@ -997,11 +996,6 @@ Gun.log("Stateless handshake sync:", e, r); }, {peers: tab.peers(url)}); // to the peer. // TODO: This forces local to flush again, not necessary. } - if(!Gun.is.soul(key)){ - Gun.is.graph(reply.body || gun.__.key.s[key], function(node, soul){ // make sure for each received node or nodes of our key - tab.key(key, soul, function(){}); // that the key points to it. - }); - } setTimeout(function(){ tab.put(reply.body, function(){}, {local: true}) },1); // and flush the in memory nodes of this graph to localStorage after we've had a chance to union on it. }), opt); cb.peers = true; @@ -1012,9 +1006,8 @@ cb = cb || function(){}; opt = opt || {}; 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 } - tab.store.put(tab.prefix + tab.prenode + soul, gun.__.graph[soul]); + tab.store.put(tab.prefix + soul, gun.__.graph[soul]); }); if(!(cb.local = opt.local)){ Gun.obj.map(opt.peers || gun.__.opt.peers, function(peer, url){ @@ -1023,23 +1016,12 @@ }); } tab.peers(cb); } - tab.key = tab.key || function(key, soul, cb, opt){ - var meta = {}; - opt = opt || {}; - cb = cb || function(){}; - meta[Gun._.soul] = soul = Gun.is.soul(soul) || soul; - if(!soul){ return cb({err: Gun.log("No soul!")}) } - (function(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){ - 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); - } + tab.com(function(msg, reply){ + + }); + tab.com.to(msg, function(reply){ + + }, opt); tab.error = function(cb, error, fn){ return function(err, reply){ reply.body = reply.body || reply.chunk || reply.end || reply.write; @@ -1102,18 +1084,18 @@ Gun.obj.map(gun.__.opt.peers, function(){ // only create server if peers and do it once by returning immediately. 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; - gun.__.opt.hooks.key = gun.__.opt.hooks.key || tab.key; + gun.__.opt.wire.get = gun.__.opt.wire.get || tab.get; + gun.__.opt.wire.put = gun.__.opt.wire.put || tab.put; + gun.__.opt.wire.key = gun.__.opt.wire.key || tab.key; }); - var store = (function(){ - function s(){} - var store = window.localStorage || {setItem: function(){}, removeItem: function(){}, getItem: function(){}}; - s.put = function(key, val){ return store.setItem(key, Gun.text.ify(val)) } - s.get = function(key){ return Gun.obj.ify(store.getItem(key) || null) } - s.del = function(key){ return store.removeItem(key) } - return s; - }()); + + ;(function(exports){ + exports.com = function(){ + + }; + com.to = function(){}; + }(Tab)); + var request = (function(){ function r(base, body, cb, opt){ opt = opt || (base.length? {base: base} : base); diff --git a/lib/file.js b/lib/file.js index edec46ecd..ee17f4133 100644 --- a/lib/file.js +++ b/lib/file.js @@ -36,33 +36,23 @@ Gun.on('opt').event(function(gun, opts) { }); } - gun.opt({hooks: { + gun.opt({wire: { get: function get(key, cb, o){ - var graph, soul; - if(soul = Gun.is.soul(key)){ - if(all.nodes[soul]){ - (graph = {})[soul] = all.nodes[soul]; - cb(null, graph); - (graph = {})[soul] = Gun.union.pseudo(soul); - cb(null, graph); // end. - } - return; - } - Gun.obj.map(all.keys[key], function(rel){ - if(Gun.is.soul(rel)){ get(soul = rel, cb, o) } - }); - return soul? cb(null, {}) : cb(null, null); + var graph, soul = key; + (graph = {})[soul] = all.nodes[soul]; + console.log("FILE NODE", graph); + if(!graph[soul]){ return cb(null, null) } + cb(null, graph); + (graph = {})[soul] = Gun.is.node.ify({}, soul); + console.log("END NODE", graph); + cb(null, graph); // end. + console.log("DONE", {}); + cb(null, {}); // done. }, put: function(graph, cb, o){ for (key in gun.__.graph) all.nodes[key]=gun.__.graph[key]; writeFile(cb); - }, - key: function(key, soul, cb, o){ - var meta = {}; - meta[Gun._.soul] = soul = Gun.is.soul(soul) || soul; - ((all.keys = all.keys || {})[key] = all.keys[key] || {})[soul] = meta; - writeFile(cb); - }, + }/*, all: function(list, opt, cb) { opt = opt || {}; opt.from = opt.from || ''; @@ -88,11 +78,11 @@ Gun.on('opt').event(function(gun, opts) { match[key][Gun._.soul] = soul; } return match; - } + }*/ }}, true); gun.all = gun.all || function(url, cb) { url = require('url').parse(url, true); - var r = gun.__.opt.hooks.all(all.keys, { + var r = gun.__.opt.wire.all(all.keys, { from: url.pathname, upto: url.query['*'], start: url.query['*>'], @@ -102,8 +92,4 @@ Gun.on('opt').event(function(gun, opts) { cb = cb || function() {}; cb(null, r); } -<<<<<<< HEAD }, 100); -======= -}); ->>>>>>> master diff --git a/lib/wsp.js b/lib/wsp.js index 095ac9972..f98111014 100644 --- a/lib/wsp.js +++ b/lib/wsp.js @@ -6,6 +6,100 @@ , url = require('url'); Gun.on('opt').event(function(gun, opt){ gun.__.opt.ws = opt.ws = gun.__.opt.ws || opt.ws || {}; + var wsp = gun.wsp = gun.wsp || function(server){ + if(!server){ return gun } + function start(port, server){ + gun.__.opt.ws.server = gun.__.opt.ws.server || opt.ws.server || server; + gun.__.opt.ws.port = gun.__.opt.ws.port || opt.ws.port || port || 80; + if(server.use){ server.use(gun.__.opt.ws.server) } + require('./ws')(gun.wsp.ws = gun.wsp.ws || new ws(gun.__.opt.ws), function(req, res){ + var ws = this; + 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){ + 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 && 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? + try{ws.send(Gun.text.ify(msg)); + }catch(e){} // juuuust in case. + }); + gun.wsp.EXPLODE(req, res); + }); + } + if(Gun.fns.is(server.address)){ + if(server.address()){ + start(server, server.address().port); + return gun; + } + } + var listen = server.listen; + server.listen = function(port){ + var serve = listen.apply(server, arguments); + start(serve, port); + return serve; + } + return gun; + } + gun.wsp.on = gun.wsp.on || Gun.on.create(); + gun.wsp.regex = gun.wsp.regex || opt.route || opt.path || /^\/gun/i; + gun.wsp.poll = gun.wsp.poll || opt.poll || 1; + gun.wsp.pull = gun.wsp.pull || opt.pull || gun.wsp.poll * 1000; + gun.wsp.server = gun.wsp.server || function(req, res, next){ // http + next = next || function(){}; + if(!req || !res){ return next(), false } + if(!req.url){ return next(), false } + if(!req.method){ return next(), false } + var msg = {}; + msg.url = url.parse(req.url, true); + if(!gun.wsp.regex.test(msg.url.pathname)){ return next(), false } // TODO: BUG! If the option isn't a regex then this will fail! + if(msg.url.pathname.replace(gun.wsp.regex,'').slice(0,3).toLowerCase() === '.js'){ + res.writeHead(200, {'Content-Type': 'text/javascript'}); + res.end(gun.wsp.js = gun.wsp.js || require('fs').readFileSync(__dirname + '/../gun.js')); // gun server is caching the gun library for the client + return true; + } + return http(req, res, function(req, res){ + if(!req){ return next() } + var stream, cb = res = require('./jsonp')(req, res); + if(req.headers && (stream = req.headers['gun-sid'])){ + stream = (gun.wsp.peers = gun.wsp.peers || {})[stream] = gun.wsp.peers[stream] || {sid: stream}; + stream.sub = stream.sub || gun.wsp.on('network').event(function(req){ + if(!stream){ return this.off() } // self cleans up after itself! + if(!req || (req.headers && req.headers['gun-sid'] === stream.sid)){ return } + (stream.queue = stream.queue || []).push(req); + stream.drain(stream.reply); + }); + cb = function(r){ (r.headers||{}).poll = gun.wsp.poll; res(r) } + stream.drain = stream.drain || function(res){ + if(!res || !stream || !stream.queue || !stream.queue.length){ return } + res({headers: {'gun-sid': stream.sid}, body: stream.queue }); + stream.off = setTimeout(function(){ stream = null }, gun.wsp.pull); + stream.reply = stream.queue = null; + return true; + } + clearTimeout(stream.off); + if(req.headers.pull){ + if(stream.drain(cb)){ return } + return stream.reply = cb; + } + } + gun.wsp.EXPLODE(req, cb); + }), true; + } + if((gun.__.opt.maxSockets = opt.maxSockets || gun.__.opt.maxSockets) !== false){ + require('https').globalAgent.maxSockets = require('http').globalAgent.maxSockets = gun.__.opt.maxSockets || Infinity; + } + if(opt.server){ + wsp(opt.server); + } + return; + + + + + + + + var wsp = gun.wsp = gun.wsp || {}; gun.attach = gun.attach || function(app){ if(app.use){ app.use(gun.server); @@ -26,7 +120,7 @@ try{ws.send(Gun.text.ify(msg)); }catch(e){} // juuuust in case. }); - gun.__.opt.hooks.transport(req, res); + gun.__.opt.wire.transport(req, res); }); gun.__.opt.ws.port = port || opt.ws.port || gun.__.opt.ws.port || 80; return server; @@ -72,7 +166,7 @@ return tab.reply = cb; } } - gun.__.opt.hooks.transport(req, cb); + gun.__.opt.wire.transport(req, cb); }), true; } gun.server.on = gun.server.on || Gun.on.create(); @@ -107,11 +201,13 @@ return cb({headers: reply.headers, body: {time: Gun.time.is() }}); } /* NTS END! SHOULD HAVE BEEN ITS OWN MODULE */ + /* ALL HACK! SHOULD BE ITS OWN MODULE OR CORE? */ if(req && req.url && Gun.obj.has(req.url.query, '*')){ return gun.all(req.url.key + req.url.search, function(err, list){ cb({headers: reply.headers, body: (err? (err.err? err : {err: err || "Unknown error."}) : list || null ) }) }); } + /* END ALL HACK! */ if(!key){ if(!Gun.obj.has(req.url.query, Gun._.soul)){ return cb({headers: reply.headers, body: {err: "No key or soul to get."}}); @@ -120,9 +216,9 @@ key[Gun._.soul] = req.url.query[Gun._.soul]; } console.log("tran.get", key); - gun.get(key, function(err, graph){ + gun.__.opt.wire.get(key, function(err, graph){ //tran.sub.scribe(req.tab, graph._[Gun._.soul]); - //console.log("tran.get", key, "<---", err, graph); + console.log("tran.get", key, "<---", err, graph); if(err || !graph){ return cb({headers: reply.headers, body: (err? (err.err? err : {err: err || "Unknown error."}) : null)}); } @@ -166,33 +262,25 @@ var reply = {headers: {'Content-Type': tran.json}}; if(!req.body){ return cb({headers: reply.headers, body: {err: "No body"}}) } gun.server.on('network').emit(Gun.obj.copy(req)); - if(tran.put.key(req, cb)){ return } + //if(tran.put.key(req, cb)){ return } // some NEW code that should get revised. - if(Gun.is.node(req.body) || Gun.is.graph(req.body)){ - //console.log("tran.put", req.body); + console.log("tran.put", req.body); + if(Gun.is.graph(req.body)){ if(req.err = Gun.union(gun, req.body, function(err, ctx){ // TODO: BUG? Probably should give me ctx.graph if(err){ return cb({headers: reply.headers, body: {err: err || "Union failed."}}) } var ctx = ctx || {}; ctx.graph = {}; Gun.is.graph(req.body, function(node, soul){ - ctx.graph[soul] = gun.__.graph[soul]; // TODO: BUG? Probably should be delta fields + ctx.graph[soul] = gun.__.graph[soul]; }); - (gun.__.opt.hooks.put || function(g,cb){cb("No save.")})(ctx.graph, function(err, ok){ - if(err){ return cb({headers: reply.headers, body: {err: err || "Failed."}}) } + (gun.__.opt.wire.put || function(g,cb){cb("No save.")})(ctx.graph, function(err, ok){ + 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."}}); }); }).err){ cb({headers: reply.headers, body: {err: req.err || "Union failed."}}) } + } else { + cb({headers: reply.headers, body: {err: "Not a valid graph!"}}); } } - tran.put.key = function(req, cb){ // key hook! - if(!req || !req.url || !req.url.key || !Gun.obj.has(req.body, Gun._.soul)){ return } - var index = req.url.key, soul = Gun.is.soul(req.body); - console.log("tran.key", index, req.body); - gun.key(index, function(err, reply){ - if(err){ return cb({headers: {'Content-Type': tran.json}, body: {err: err}}) } - cb({headers: {'Content-Type': tran.json}, body: reply}); // TODO: Fix so we know what the reply is. - }, soul); - return true; - } gun.server.on('network').event(function(req){ // TODO: MARK! You should move the networking events to here, not in WSS only. }); @@ -200,9 +288,9 @@ return tran; }()); - opt.hooks = opt.hooks || {}; - gun.opt({hooks: { - transport: opt.hooks.transport || gun.server.transport + opt.wire = opt.wire || {}; + gun.opt({wire: { + transport: opt.wire.transport || gun.server.transport }}, true); }); }({})); diff --git a/package.json b/package.json index 690477bf6..23c7e80a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.2.5", + "version": "0.3.0", "description": "Graph engine", "main": "index.js", "scripts": {