mirror of
https://github.com/amark/gun.git
synced 2025-06-07 14:46:44 +00:00
live push, albeit needs improvements
This commit is contained in:
parent
8024d51950
commit
cabd7f21da
@ -17,8 +17,8 @@ app.listen(port);
|
|||||||
|
|
||||||
console.log('Express started on port ' + port + ' with /gun');
|
console.log('Express started on port ' + port + ' with /gun');
|
||||||
|
|
||||||
gun.load('blob/data', function(){ // ugly little idempotent initializer, in case no data is set
|
gun.load('blob/data', function(){ // ugh need to initialize the data if there is none, what a waste of LOC!
|
||||||
gun.set({_:{'#': "yVbyf7BqlXVQQUOE5cw9rf8h",'>':{hello: 1407328713707,from: 1407328713707}}, // this is an actual gun object, this won't overwrite any new changes
|
gun.set({_:{'#': "yVbyf7BqlXVQQUOE5cw9rf8h",'>':{hello: 1407328713707,from: 1407328713707}}, // this is a nasty trick to force the ID to overwrite itself
|
||||||
hello: "world",
|
hello: "world",
|
||||||
from: "Mark Nadal"
|
from: "Mark Nadal"
|
||||||
}).key('blob/data');
|
}).key('blob/data');
|
||||||
|
@ -55,6 +55,12 @@
|
|||||||
$scope.$data = gun.load('blob/data', function(data){
|
$scope.$data = gun.load('blob/data', function(data){
|
||||||
$scope.data = data;
|
$scope.data = data;
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
|
Gun.on(data._[Gun.sym.id]).event(function(node){ // one liner-ify this!
|
||||||
|
Gun.obj.map(node, function(val, field){
|
||||||
|
$scope.data[field] = val;
|
||||||
|
});
|
||||||
|
$scope.$apply();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
$scope.add = function(a,b,c){
|
$scope.add = function(a,b,c){
|
||||||
$scope.$data.path($scope.field).set(
|
$scope.$data.path($scope.field).set(
|
||||||
|
146
gun.js
146
gun.js
@ -4,12 +4,12 @@
|
|||||||
if(!Gun.is(gun)){
|
if(!Gun.is(gun)){
|
||||||
return new Gun(opt);
|
return new Gun(opt);
|
||||||
}
|
}
|
||||||
gun.init(opt);
|
gun.opt(opt);
|
||||||
}
|
}
|
||||||
Gun.is = function(gun){ return (gun instanceof Gun)? true : false }
|
Gun.is = function(gun){ return (gun instanceof Gun)? true : false }
|
||||||
Gun._ = {};
|
Gun._ = {};
|
||||||
Gun.chain = Gun.prototype;
|
Gun.chain = Gun.prototype;
|
||||||
Gun.chain.init = function(opt, stun){ // idempotently update or set options
|
Gun.chain.opt = function(opt, stun){ // idempotently update or set options
|
||||||
var gun = this;
|
var gun = this;
|
||||||
gun._ = gun._ || {};
|
gun._ = gun._ || {};
|
||||||
gun.__ = gun.__ || {};
|
gun.__ = gun.__ || {};
|
||||||
@ -28,7 +28,7 @@
|
|||||||
if(!Gun.fns.is(h)){ return }
|
if(!Gun.fns.is(h)){ return }
|
||||||
gun.__.opt.hook[f] = h;
|
gun.__.opt.hook[f] = h;
|
||||||
});
|
});
|
||||||
if(!stun){ Gun.on('init').emit(gun, opt) }
|
if(!stun){ Gun.on('opt').emit(gun, opt) }
|
||||||
return gun;
|
return gun;
|
||||||
}
|
}
|
||||||
Gun.chain.chain = function(from){
|
Gun.chain.chain = function(from){
|
||||||
@ -225,6 +225,7 @@
|
|||||||
Gun.text = {};
|
Gun.text = {};
|
||||||
Gun.text.is = function(t){ return typeof t == 'string'? true : false }
|
Gun.text.is = function(t){ return typeof t == 'string'? true : false }
|
||||||
Gun.text.ify = function(t){
|
Gun.text.ify = function(t){
|
||||||
|
if(Gun.text.is(t)){ return t }
|
||||||
if(JSON){ return JSON.stringify(t) }
|
if(JSON){ return JSON.stringify(t) }
|
||||||
return (t && t.toString)? t.toString() : t;
|
return (t && t.toString)? t.toString() : t;
|
||||||
}
|
}
|
||||||
@ -363,7 +364,7 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
Gun.HAM = function(current, delta, some){ // TODO: BUG! HAM on sub-graphs has not yet been put into code, thus divergences could occur - this is alpha!
|
Gun.HAM = function(current, delta, some){ // TODO: BUG! HAM on sub-graphs has not yet been put into code, thus divergences could occur - this is alpha!
|
||||||
function HAM(machineState, incomingState, currentState, incomingValue, currentValue){
|
function HAM(machineState, incomingState, currentState, incomingValue, currentValue){ // TODO: Lester's comments on roll backs could be vulnerable to divergence, investigate!
|
||||||
if(machineState < incomingState){
|
if(machineState < incomingState){
|
||||||
// the incoming value is outside the boundary of the machine's state, it must be reprocessed in another state.
|
// the incoming value is outside the boundary of the machine's state, it must be reprocessed in another state.
|
||||||
return {amnesiaQuarantine: true};
|
return {amnesiaQuarantine: true};
|
||||||
@ -609,34 +610,94 @@
|
|||||||
}
|
}
|
||||||
}({}));
|
}({}));
|
||||||
|
|
||||||
;(function(Page){
|
;(function(tab){
|
||||||
if(!this.Gun){ return }
|
if(!this.Gun){ return }
|
||||||
if(!window.JSON){ Gun.log("Include JSON first: ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js") } // for old IE use
|
if(!window.JSON){ Gun.log("Include JSON first: ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js") } // for old IE use
|
||||||
Gun.on('init').event(function(gun, opt){
|
Gun.on('opt').event(function(gun, opt){
|
||||||
Page.load = function(key, cb, opt){
|
tab.server = tab.server || function(req, res, next){
|
||||||
|
|
||||||
|
}
|
||||||
|
tab.load = tab.load || function(key, cb, opt){
|
||||||
cb = cb || function(){};
|
cb = cb || function(){};
|
||||||
opt = opt || {};
|
opt = opt || {};
|
||||||
Gun.obj.map(gun.__.opt.peers, function(peer, url){
|
Gun.obj.map(gun.__.opt.peers, function(peer, url){
|
||||||
Page.ajax(url + '/' + key, null, function(data){
|
tab.ajax(url + '/' + key, null, function(reply){
|
||||||
Gun.log('via', url, key, data);
|
Gun.log('via', url, key, reply);
|
||||||
// alert(data + data.hello + data.from + data._);
|
if(!reply){ return } // handle reconnect?
|
||||||
cb(null, data);
|
if(reply.body && reply.body.err){
|
||||||
|
cb(reply.body.err);
|
||||||
|
} else {
|
||||||
|
cb(null, reply.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
(function(){
|
||||||
|
tab.subscribe.sub = (reply.headers || {})['Gun-Sub'];
|
||||||
|
var data = reply.body;
|
||||||
if(!data || !data._){ return }
|
if(!data || !data._){ return }
|
||||||
Page.subscribe(data._[Gun.sym.id]);
|
tab.subscribe(data._[Gun.sym.id]);
|
||||||
});
|
}());
|
||||||
|
}, {head: {'Gun-Sub': 1}});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Page.set = function(nodes, cb){
|
tab.set = tab.set || function(nodes, cb){
|
||||||
cb = cb || function(){};
|
cb = cb || function(){};
|
||||||
// TODO: batch and throttle later.
|
// TODO: batch and throttle later.
|
||||||
console.log('ajax set', nodes);
|
console.log('ajax set', nodes);
|
||||||
Gun.obj.map(gun.__.opt.peers, function(peer, url){
|
Gun.obj.map(gun.__.opt.peers, function(peer, url){
|
||||||
Page.ajax(url, nodes, function(reply){
|
tab.ajax(url, nodes, function(reply){
|
||||||
console.log("set confirmed?", reply);
|
console.log("set confirmed?", reply);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Page.query = function(params){
|
tab.subscribe = function(id){
|
||||||
|
tab.subscribe.to = tab.subscribe.to || {};
|
||||||
|
if(id){
|
||||||
|
tab.subscribe.to[id] = 1;
|
||||||
|
}
|
||||||
|
var opt = {
|
||||||
|
//head: {'Gun-Sub': 1},
|
||||||
|
headers: {
|
||||||
|
'Gun-Transport': 'XHR-SLP',
|
||||||
|
'Gun-Sub': tab.subscribe.sub || ''
|
||||||
|
}
|
||||||
|
}, query = tab.subscribe.sub? '' : tab.subscribe.query(tab.subscribe.to);
|
||||||
|
console.log("SUB", tab.subscribe.sub);
|
||||||
|
Gun.obj.map(gun.__.opt.peers, function(peer, url){
|
||||||
|
tab.ajax(url + query, null, function(reply){
|
||||||
|
tab.subscribe.poll();
|
||||||
|
if(!reply){ return } // do anything?
|
||||||
|
if(reply.headers){
|
||||||
|
tab.subscribe.sub = reply.headers['Gun-Sub'] || tab.subscribe.sub;
|
||||||
|
}
|
||||||
|
var data = reply.body
|
||||||
|
, union = function(node){ // maybe we shouldn't have this type of logic, below, in a hook?
|
||||||
|
// should we pass it off to a gun API? same with everywhere else this shows up then.
|
||||||
|
if(!node || !node._ || !node._[Gun.sym.id]){ return } // do anything?
|
||||||
|
var context = {nodes: {}};
|
||||||
|
context.nodes[node._[Gun.sym.id]] = node;
|
||||||
|
context = Gun.chain.set.now.union.call(gun, context.nodes);
|
||||||
|
if(context.err){ return } // do anything?
|
||||||
|
Gun.obj.map(context.nodes, function(node, id){
|
||||||
|
Gun.on(id).emit(node); // TODO: we shouldn't use Gun's global event namespace like this, change to local
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if(!data){ return } // do anything?
|
||||||
|
if(data.err){ return } // do anything?
|
||||||
|
if(data._){
|
||||||
|
union(data);
|
||||||
|
} else {
|
||||||
|
Gun.obj.map(data, function(node, id){
|
||||||
|
union(node);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, opt);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
tab.subscribe.poll = function(){
|
||||||
|
clearTimeout(tab.subscribe.poll.id);
|
||||||
|
tab.subscribe.poll.id = setTimeout(tab.subscribe, 1); // 1000 * 10); // should enable some server-side control of this.
|
||||||
|
}
|
||||||
|
tab.subscribe.query = function(params){
|
||||||
var s = '?'
|
var s = '?'
|
||||||
, uri = encodeURIComponent;
|
, uri = encodeURIComponent;
|
||||||
Gun.obj.map(params, function(val, field){
|
Gun.obj.map(params, function(val, field){
|
||||||
@ -644,18 +705,7 @@
|
|||||||
});
|
});
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
Page.subscribe = function(id){
|
tab.ajax =
|
||||||
Page.subscribe.to = Page.subscribe.to || {};
|
|
||||||
Page.subscribe.to[id] = 1;
|
|
||||||
var query = Page.query(Page.subscribe.to) || '';
|
|
||||||
Gun.obj.map(gun.__.opt.peers, function(peer, url){
|
|
||||||
Page.ajax(url + query, null, function(data){
|
|
||||||
console.log("subscribe reply!", data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
console.log("live", query);
|
|
||||||
}
|
|
||||||
Page.ajax =
|
|
||||||
window.ajax =
|
window.ajax =
|
||||||
function(url, data, cb, opt){
|
function(url, data, cb, opt){
|
||||||
/*
|
/*
|
||||||
@ -668,11 +718,13 @@
|
|||||||
*/
|
*/
|
||||||
var u;
|
var u;
|
||||||
opt = opt || {};
|
opt = opt || {};
|
||||||
|
opt.head = opt.head || {};
|
||||||
|
opt.reshead = {};
|
||||||
|
opt.headers = opt.headers || {};
|
||||||
if(data === u || data === null){
|
if(data === u || data === null){
|
||||||
data = u;
|
data = u;
|
||||||
} else {
|
} else {
|
||||||
try{data = JSON.stringify(data);
|
try{data = JSON.stringify(data);
|
||||||
opt.headers = opt.headers || {};
|
|
||||||
opt.headers["Content-Type"] = "application/json;charset=utf-8";
|
opt.headers["Content-Type"] = "application/json;charset=utf-8";
|
||||||
}catch(e){}
|
}catch(e){}
|
||||||
}
|
}
|
||||||
@ -694,20 +746,24 @@
|
|||||||
}
|
}
|
||||||
opt.xhr = null;
|
opt.xhr = null;
|
||||||
}
|
}
|
||||||
opt.data = opt.data || function(d){
|
opt.data = opt.data || function(d, head){
|
||||||
var t;
|
var reply = {};
|
||||||
try{t = JSON.parse(d) || d;
|
reply.headers = head;
|
||||||
|
try{reply.body = JSON.parse(d) || d;
|
||||||
}catch(e){
|
}catch(e){
|
||||||
t = d;
|
reply.body = d;
|
||||||
}
|
}
|
||||||
if(cb){ cb(t) }
|
if(cb){ cb(reply) }
|
||||||
}
|
}
|
||||||
opt.chunk = function(status, text, force){
|
opt.chunk = function(status, text, force){
|
||||||
if(status !== 200){ return }
|
if(status !== 200){ return }
|
||||||
|
opt.each(opt.head, function(val, i){
|
||||||
|
opt.reshead[i] = opt.xhr.getResponseHeader(i);
|
||||||
|
});
|
||||||
var d, b, p = 1;
|
var d, b, p = 1;
|
||||||
while(p || force){
|
while(p || force){
|
||||||
if(u !== d){
|
if(u !== d){
|
||||||
opt.data(d);
|
opt.data(d, opt.reshead);
|
||||||
force = false;
|
force = false;
|
||||||
}
|
}
|
||||||
b = text.slice(opt.i = opt.i || 0);
|
b = text.slice(opt.i = opt.i || 0);
|
||||||
@ -771,12 +827,18 @@
|
|||||||
opt.error();
|
opt.error();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
opt.each = function(obj, cb){
|
||||||
|
if(!obj || !cb){ return }
|
||||||
|
for(var i in obj){
|
||||||
|
if(obj.hasOwnProperty(i)){
|
||||||
|
cb(obj[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if(opt.headers){
|
if(opt.headers){
|
||||||
try{for(var i in opt.headers){
|
try{opt.each(opt.headers, function(val, i){
|
||||||
if(opt.headers.hasOwnProperty(i)){
|
opt.xhr.setRequestHeader(i, val);
|
||||||
opt.xhr.setRequestHeader(i, opt.headers[i]);
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
opt.error();
|
opt.error();
|
||||||
return;
|
return;
|
||||||
@ -788,7 +850,7 @@
|
|||||||
}
|
}
|
||||||
return opt;
|
return opt;
|
||||||
}
|
}
|
||||||
gun.__.opt.hook.load = gun.__.opt.hook.load || Page.load;
|
gun.__.opt.hook.load = gun.__.opt.hook.load || tab.load;
|
||||||
gun.__.opt.hook.set = gun.__.opt.hook.set || Page.set;
|
gun.__.opt.hook.set = gun.__.opt.hook.set || tab.set;
|
||||||
});
|
});
|
||||||
}({}));
|
}({}));
|
@ -1,5 +1,5 @@
|
|||||||
{ "name": "gun"
|
{ "name": "gun"
|
||||||
, "version": "0.0.2b"
|
, "version": "0.0.3"
|
||||||
, "author": "Mark Nadal"
|
, "author": "Mark Nadal"
|
||||||
, "description": "Graph engine."
|
, "description": "Graph engine."
|
||||||
, "engines": {
|
, "engines": {
|
||||||
|
172
shots.js
172
shots.js
@ -3,62 +3,56 @@
|
|||||||
, S3 = require(__dirname+'/gate/s3') // redis has been removed, can be replaced with a disk system
|
, S3 = require(__dirname+'/gate/s3') // redis has been removed, can be replaced with a disk system
|
||||||
, url = require('url')
|
, url = require('url')
|
||||||
, meta = {};
|
, meta = {};
|
||||||
Gun.on('init').event(function(gun, opt){
|
Gun.on('opt').event(function(gun, opt){
|
||||||
gun.server = gun.server || function(req, res, next){ // this whole function needs refactoring and modularization
|
gun.server = gun.server || function(req, res, next){ // this whole function needs refactoring and modularization
|
||||||
next = next || function(){};
|
next = next || function(){};
|
||||||
if(!req || !res){ return next() }
|
if(!req || !res){ return next() }
|
||||||
if(!req.url){ return next() }
|
if(!req.url){ return next() }
|
||||||
if(!req.method){ return next() }
|
if(!req.method){ return next() }
|
||||||
var tmp = {};
|
var msg = {};
|
||||||
tmp.url = url.parse(req.url, true);
|
msg.url = url.parse(req.url, true);
|
||||||
if(!gun.server.regex.test(tmp.url.pathname)){ return next() }
|
if(!gun.server.regex.test(msg.url.pathname)){ return next() }
|
||||||
tmp.key = tmp.url.pathname.replace(gun.server.regex,'') || '';
|
msg.url.key = msg.url.pathname.replace(gun.server.regex,'') || '';
|
||||||
if(tmp.key.toLowerCase() === '.js'){
|
if(msg.url.key.toLowerCase() === '.js'){
|
||||||
res.writeHead(200, {'Content-Type': 'text/javascript'});
|
res.writeHead(200, {'Content-Type': 'text/javascript'});
|
||||||
res.end(gun.server.js = gun.server.js || require('fs').readFileSync(__dirname + '/gun.js')); // gun server is caching the gun library for the client
|
res.end(gun.server.js = gun.server.js || require('fs').readFileSync(__dirname + '/gun.js')); // gun server is caching the gun library for the client
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("\ngun server has requests!", req.method, req.url, req.headers, req.body);
|
msg.url.key = msg.url.key.replace(/^\//i,'') || ''; // strip the base
|
||||||
tmp.key = tmp.key.replace(/^\//i,'') || ''; // strip the base
|
msg.method = (req.method||'').toLowerCase();
|
||||||
tmp.method = (req.method||'').toLowerCase();
|
msg.headers = req.headers;
|
||||||
if('get' === tmp.method){ // get is used as subscribe
|
msg.body = req.body; // TODO: include body-parser here?
|
||||||
console.log("URL?", tmp.url);
|
if('get' === msg.method){ // get is used as subscribe
|
||||||
if(tmp.url && tmp.url.query){
|
gun.__.opt.hook.sub(msg, function(reply){
|
||||||
/*
|
if(!res){ return }
|
||||||
long polling! Idea: On data-flush or res.end, issue a timeout token,
|
if(!reply){ return res.end() }
|
||||||
that keeps the 'connection' alive even while disconnected.
|
if(reply.headers){
|
||||||
Subsequent requests use the timeout token and thus continue off as before, seamlessly.
|
if(!res._headerSent){
|
||||||
If after the timeout no follow up has been made, we assume the client has dropped / disconnected.
|
Gun.obj.map(reply.headers, function(val, field){
|
||||||
*/
|
res.setHeader(field, val);
|
||||||
Gun.obj.map(tmp.url.query, function(){
|
|
||||||
tmp.query = true;
|
|
||||||
// subscribe this req/res to the ids, then make POSTS publish to them and reply!
|
|
||||||
// MARK! COME BACK HERE
|
|
||||||
});
|
});
|
||||||
if(tmp.query){
|
|
||||||
return; // we'll wait until we get updates before we reply. Long polling (should probably be implemented as a hook itself! so websockets can replace it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!tmp.key){
|
meta.CORS(req, res); // add option to disable this
|
||||||
return meta.JSON(res, {gun: true});
|
if(reply.chunk){
|
||||||
|
res.write(Gun.text.ify(reply.chunk));
|
||||||
}
|
}
|
||||||
// raw test for now, no auth:
|
if(reply.body){
|
||||||
gun.load(tmp.key, function(err, data){
|
res.end(Gun.text.ify(reply.body));
|
||||||
meta.CORS(req, res);
|
}
|
||||||
return meta.JSON(res, data || err);
|
});
|
||||||
})
|
return;
|
||||||
} else
|
} else
|
||||||
if('post' === tmp.method || 'patch' === tmp.method){ // post is used as patch, sad that patch has such poor support
|
if('post' === msg.method || 'patch' === msg.method){ // post is used as patch, sad that patch has such poor support
|
||||||
if(!req.body){
|
if(!msg.body){
|
||||||
console.log("Warn: No body on POST?");
|
console.log("Warn: No body on POST?");
|
||||||
}
|
}
|
||||||
// raw test for now, no auth:
|
// raw test for now, no auth:
|
||||||
// should probably load all the nodes first?
|
// should probably load all the nodes first?
|
||||||
var context = Gun.chain.set.now.union.call(gun, req.body); // data safely transformed
|
var context = Gun.chain.set.now.union.call(gun, msg.body); // data safely transformed
|
||||||
if(context.err){
|
if(context.err){
|
||||||
return meta.JSON(res, context.err); // need to standardize errors more
|
return meta.JSON(res, context.err); // need to use the now standardized errors
|
||||||
}
|
}
|
||||||
// console.log("-------- union ---------");Gun.obj.map(gun.__.nodes, function(node){ console.log(node); });console.log("------------------------");
|
|
||||||
/*
|
/*
|
||||||
WARNING! TODO: BUG! Do not send OK confirmation if amnesiaQuaratine is activated! Not until after it has actually been processed!!!
|
WARNING! TODO: BUG! Do not send OK confirmation if amnesiaQuaratine is activated! Not until after it has actually been processed!!!
|
||||||
*/
|
*/
|
||||||
@ -73,15 +67,26 @@
|
|||||||
context.err = "Warning! You have no persistence layer to save to!";
|
context.err = "Warning! You have no persistence layer to save to!";
|
||||||
Gun.log(context.err);
|
Gun.log(context.err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var diff = msg.body
|
||||||
|
msg.body = null;
|
||||||
|
Gun.obj.map(context.nodes, function(node, id){
|
||||||
|
var req = Gun.obj.copy(msg);
|
||||||
|
msg.body = node;
|
||||||
|
gun.server.push.on(id).emit(msg);
|
||||||
|
});
|
||||||
|
msg.body = diff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gun.server.regex = /^\/gun/i;
|
gun.server.regex = /^\/gun/i;
|
||||||
|
gun.server.clients = {};
|
||||||
|
gun.server.push = Gun.on.split();
|
||||||
var s3 = gun.__.opt.s3 = gun.__.opt.s3 || S3(opt && opt.s3);
|
var s3 = gun.__.opt.s3 = gun.__.opt.s3 || S3(opt && opt.s3);
|
||||||
s3.prefix = s3.prefix || opt.s3.prefix || '';
|
s3.prefix = s3.prefix || opt.s3.prefix || '';
|
||||||
s3.prekey = s3.prekey || opt.s3.prekey || '';
|
s3.prekey = s3.prekey || opt.s3.prekey || '';
|
||||||
s3.prenode = s3.prenode || opt.s3.prenode || '_/nodes/';
|
s3.prenode = s3.prenode || opt.s3.prenode || '_/nodes/';
|
||||||
gun.__.opt.batch = opt.batch || gun.__.opt.batch || 10;
|
gun.__.opt.batch = opt.batch || gun.__.opt.batch || 10;
|
||||||
gun.__.opt.throttle = opt.throttle || gun.__.opt.throttle || 2;
|
gun.__.opt.throttle = opt.throttle || gun.__.opt.throttle || 15;
|
||||||
if(!gun.__.opt.keepMaxSockets){ require('https').globalAgent.maxSockets = require('http').globalAgent.maxSockets = Infinity } // WARNING: Document this!
|
if(!gun.__.opt.keepMaxSockets){ require('https').globalAgent.maxSockets = require('http').globalAgent.maxSockets = Infinity } // WARNING: Document this!
|
||||||
|
|
||||||
s3.load = s3.load || function(key, cb, opt){
|
s3.load = s3.load || function(key, cb, opt){
|
||||||
@ -174,17 +179,104 @@
|
|||||||
}, {Metadata: {'#': id}});
|
}, {Metadata: {'#': id}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gun.server.sub = (function(){
|
||||||
|
function sub(req, cb){
|
||||||
|
//console.log("\n\n\n", req);
|
||||||
|
req.sub = req.headers['gun-sub'];
|
||||||
|
req.transport = req.headers['gun-transport'];
|
||||||
|
if(req.transport === 'XHR-SLP'){ return sub.SLP(req, cb) }
|
||||||
|
if(!req.url.key){ return sub.keyless(req, cb) }
|
||||||
|
// raw test for now, no auth:
|
||||||
|
req.tab = sub.s[req.sub] || {};
|
||||||
|
cb.header = {'Content-Type': sub.json};
|
||||||
|
cb.header['Gun-Sub'] = req.tab.sub =
|
||||||
|
req.sub = req.tab.sub || req.sub || Gun.text.random();
|
||||||
|
gun.load(req.url.key, function(node){
|
||||||
|
sub.scribe(req.tab, node._[Gun.sym.id]);
|
||||||
|
cb({
|
||||||
|
headers: cb.header
|
||||||
|
,body: Gun.text.ify(node)
|
||||||
|
});
|
||||||
|
}).blank(function(){
|
||||||
|
cb({
|
||||||
|
headers: cb.header
|
||||||
|
,body: Gun.text.ify(null)
|
||||||
|
});
|
||||||
|
}).dud(function(err){
|
||||||
|
cb({
|
||||||
|
headers: cb.header
|
||||||
|
,body: Gun.text.ify({err: err || "Unknown error."})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
sub.s = {};
|
||||||
|
sub.scribe = function(tab, id){
|
||||||
|
sub.s[tab.sub] = tab;
|
||||||
|
tab.subs = tab.subs || {};
|
||||||
|
tab.subs[id] = tab.subs[id] || gun.server.push.on(id).event(function(req){
|
||||||
|
if(!req){ return }
|
||||||
|
if(!tab){ return this.off() } // resolve any dangling callbacks
|
||||||
|
req.sub = req.sub || req.headers['gun-sub'];
|
||||||
|
if(req.sub === tab.sub){ return } // do not send back to the tab that sent it
|
||||||
|
if(Gun.fns.is(tab.reply)){
|
||||||
|
tab.reply({
|
||||||
|
headers: {'Content-Type': sub.json, 'Gun-Sub': tab.sub}
|
||||||
|
,body: Gun.text.ify(req.body)
|
||||||
|
})
|
||||||
|
tab.reply = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(tab.queue = tab.queue || []).push(req.body);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
sub.SLP = function(req, cb){ // Streaming Long Polling
|
||||||
|
//console.log("<-- ", req.sub, req.transport ," -->");
|
||||||
|
req.tab = sub.s[req.sub];
|
||||||
|
if(!req.tab){
|
||||||
|
cb({
|
||||||
|
headers: {'Content-Type': sub.json, 'Gun-Sub': ''}
|
||||||
|
,body: Gun.text.ify({err: "Please re-initialize sub."})
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
req.tab.sub = req.tab.sub || req.sub;
|
||||||
|
if(req.tab.queue && req.tab.queue.length){
|
||||||
|
cb({ headers: {'Content-Type': sub.json, 'Gun-Sub': req.sub} });
|
||||||
|
while(1 < req.tab.queue.length){
|
||||||
|
cb({ chunk: Gun.text.ify(req.tab.queue.shift() + '\n') });
|
||||||
|
}
|
||||||
|
cb({ body: Gun.text.ify(req.tab.queue.shift()) });
|
||||||
|
} else {
|
||||||
|
req.tab.reply = cb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sub.keyless = function(req, cb){
|
||||||
|
cb({
|
||||||
|
headers: {'Content-Type': sub.json}
|
||||||
|
,body: {gun: true}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
sub.json = 'application/json';
|
||||||
|
return sub;
|
||||||
|
}());
|
||||||
|
|
||||||
opt.hook = opt.hook || {};
|
opt.hook = opt.hook || {};
|
||||||
gun.init({hook: {
|
gun.opt({hook: {
|
||||||
load: opt.hook.load || s3.load
|
load: opt.hook.load || s3.load
|
||||||
,set: opt.hook.set || s3.set
|
,set: opt.hook.set || s3.set
|
||||||
,key: opt.hook.key || s3.key
|
,key: opt.hook.key || s3.key
|
||||||
|
,sub: opt.hook.sub || gun.server.sub
|
||||||
}}, true);
|
}}, true);
|
||||||
});
|
});
|
||||||
meta.json = 'application/json';
|
meta.json = 'application/json';
|
||||||
meta.JSON = function(res, data){
|
meta.JSON = function(res, data, multi){
|
||||||
if(!res || res._headerSent){ return }
|
if(res && !res._headerSent){
|
||||||
res.setHeader('Content-Type', meta.json);
|
res.setHeader('Content-Type', meta.json);
|
||||||
|
}
|
||||||
|
if(!data && multi){
|
||||||
|
res.write(JSON.stringify(multi||'')+'\n');
|
||||||
|
return;
|
||||||
|
}
|
||||||
return res.end(JSON.stringify(data||''));
|
return res.end(JSON.stringify(data||''));
|
||||||
};
|
};
|
||||||
meta.CORS = function(req, res){
|
meta.CORS = function(req, res){
|
||||||
|
Loading…
x
Reference in New Issue
Block a user