mirror of
https://github.com/amark/gun.git
synced 2025-03-30 15:08:33 +00:00
258 lines
7.8 KiB
JavaScript
258 lines
7.8 KiB
JavaScript
/* eslint-disable require-jsdoc, no-underscore-dangle */
|
|
'use strict';
|
|
var Gun = require('../../gun');
|
|
var http = require('../http');
|
|
var url = require('url');
|
|
var WS = require('ws');
|
|
var WSS = WS.Server;
|
|
var attach = require('./server-push');
|
|
|
|
// Handles server to server sync.
|
|
require('./client.js');
|
|
|
|
Gun.on('opt', function (at) {
|
|
this.to.next(at);
|
|
var gun = at.gun, opt = at.opt;
|
|
gun.__ = at.root._;
|
|
gun.__.opt.ws = opt.ws = gun.__.opt.ws || opt.ws || {};
|
|
gun.__.opt.ws.path = gun.__.opt.ws.path || '/gun';
|
|
|
|
if(gun.__.opt.web){
|
|
setTimeout(function(){
|
|
if(gun.__.opt.web.use){
|
|
gun.__.opt.web.use(Gun.serve);
|
|
}
|
|
start(gun.__.opt.web);
|
|
},1);
|
|
}
|
|
function start (server, port, app) {
|
|
if (app && app.use) {
|
|
app.use(gun.wsp.server);
|
|
}
|
|
server = gun.__.opt.ws.server = gun.__.opt.ws.server || gun.__.opt.web || opt.ws.server || server;
|
|
|
|
if (!gun.wsp.ws) {
|
|
//console.log("????????", gun.__.opt.ws);
|
|
gun.wsp.ws = new WSS(gun.__.opt.ws);
|
|
attach(gun, gun.wsp.ws);
|
|
}
|
|
|
|
require('./ws')(gun.wsp.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', function (msg) {
|
|
var ev = this; ev.to.next(msg);
|
|
if (!ws || !ws.send || !ws._socket || !ws._socket.writable) { return ev.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.wire(req, res);
|
|
}, {headers: {'ws-rid': 1, 'gun-sid': 1}});
|
|
gun.__.opt.ws.port = gun.__.opt.ws.port || opt.ws.port || port || 80;
|
|
}
|
|
var wsp = gun.wsp = gun.wsp || function (server) {
|
|
console.log("WARNING: gun.wsp(server) should be switched to Gun({web: server}) by v0.7!")
|
|
if (!server) { return gun; }
|
|
if (Gun.fns.is(server.address)) {
|
|
if (server.address()) {
|
|
start(server, server.address().port);
|
|
return gun;
|
|
}
|
|
}
|
|
if (Gun.fns.is(server.get) && server.get('port')) {
|
|
start(server, server.get('port'));
|
|
return gun;
|
|
}
|
|
var listen = server.listen;
|
|
server.listen = function (port) {
|
|
var serve = listen.apply(server, arguments);
|
|
start(serve, port, server);
|
|
return serve;
|
|
};
|
|
return gun;
|
|
};
|
|
gun.wsp.on = gun.wsp.on || Gun.on;
|
|
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;
|
|
}
|
|
|
|
if (!req.upgrade) {
|
|
next();
|
|
return false;
|
|
}
|
|
|
|
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.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;
|
|
};
|
|
stream.sub = stream.sub || gun.wsp.on('network', function (req) {
|
|
var ev = this; ev.to.next(req);
|
|
if (!stream) { return ev.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); };
|
|
clearTimeout(stream.off);
|
|
if (req.headers.pull) {
|
|
if (stream.drain(cb)) { return; }
|
|
return stream.reply = cb;
|
|
}
|
|
}
|
|
gun.wsp.wire(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;
|
|
}
|
|
gun.wsp.msg = gun.wsp.msg || function (id) {
|
|
if (!id) {
|
|
return gun.wsp.msg.debounce[id = Gun.text.random(9)] = Gun.time.is(), id;
|
|
}
|
|
clearTimeout(gun.wsp.msg.clear);
|
|
gun.wsp.msg.clear = setTimeout(function () {
|
|
var now = Gun.time.is();
|
|
Gun.obj.map(gun.wsp.msg.debounce, function (t, id) {
|
|
if ((now - t) < (1000 * 60 * 5)) { return; }
|
|
Gun.obj.del(gun.wsp.msg.debounce, id);
|
|
});
|
|
}, 500);
|
|
if (id = gun.wsp.msg.debounce[id]) {
|
|
return gun.wsp.msg.debounce[id] = Gun.time.is(), id;
|
|
}
|
|
gun.wsp.msg.debounce[id] = Gun.time.is();
|
|
return;
|
|
};
|
|
gun.wsp.msg.debounce = gun.wsp.msg.debounce || {};
|
|
gun.wsp.wire = gun.wsp.wire || (function () {
|
|
// 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 sent to.
|
|
// all states, implemented with GET, are replied to the
|
|
// source that asked for it.
|
|
function tran (req, res) {
|
|
if (!req || !res || !req.body || !req.headers) {
|
|
return;
|
|
}
|
|
if (req.url) {
|
|
req.url = url.format(req.url);
|
|
}
|
|
// var msg = req.body;
|
|
gun.on('in', req.body);
|
|
// // AUTH for non-replies.
|
|
// if(gun.wsp.msg(msg['#'])){ return }
|
|
// gun.wsp.on('network', Gun.obj.copy(req));
|
|
// if(msg['@']){ return } // no need to process.
|
|
// if(msg['$'] && msg['$']['#']){ return tran.get(req, res) }
|
|
// //if(Gun.is.lex(msg['$'])){ return tran.get(req, res) }
|
|
// else { return tran.put(req, res) }
|
|
// cb({body: {hello: 'world'}});
|
|
// // TODO: BUG! server put should push.
|
|
}
|
|
tran.get = function (req, cb) {
|
|
var body = req.body;
|
|
var lex = body.$;
|
|
var reply = {
|
|
headers: { 'Content-Type': tran.json },
|
|
};
|
|
|
|
var graph = gun.Back(Infinity)._.graph;
|
|
var node = graph[lex['#']];
|
|
var result = Gun.graph.ify(node);
|
|
|
|
if (node) {
|
|
cb({
|
|
headers: reply.headers,
|
|
body: {
|
|
'#': gun.wsp.msg(),
|
|
'@': body['#'],
|
|
'$': result,
|
|
},
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
gun.on('out', {
|
|
gun: gun,
|
|
get: lex,
|
|
req: 1,
|
|
'#': body['#'] || Gun.on.ask(function (at, ev) {
|
|
ev.off();
|
|
var graph = at.put;
|
|
return cb({
|
|
headers: reply.headers,
|
|
body: {
|
|
'#': gun.wsp.msg(),
|
|
'@': body['#'],
|
|
'$': graph,
|
|
'!': at.err,
|
|
},
|
|
});
|
|
}),
|
|
});
|
|
};
|
|
|
|
tran.put = function (req, cb) {
|
|
// NOTE: It is highly recommended you do your own PUT/POSTs
|
|
// through your own API that then saves to gun manually.
|
|
// This will give you much more fine-grain control over
|
|
// security, transactions, and what not.
|
|
var body = req.body;
|
|
var graph = body.$;
|
|
var reply = {
|
|
headers: { 'Content-Type': tran.json },
|
|
};
|
|
|
|
gun.on('out', {
|
|
gun: gun,
|
|
put: graph,
|
|
'#': Gun.on.ask(function (ack, ev) {
|
|
ev.off();
|
|
return cb({
|
|
headers: reply.headers,
|
|
body: {
|
|
'#': gun.wsp.msg(),
|
|
'@': body['#'],
|
|
'$': ack,
|
|
'!': ack.err,
|
|
},
|
|
});
|
|
}),
|
|
});
|
|
};
|
|
|
|
tran.json = 'application/json';
|
|
return tran;
|
|
}());
|
|
|
|
if (opt.server) {
|
|
wsp(opt.server);
|
|
}
|
|
});
|