mirror of
https://github.com/amark/gun.git
synced 2025-03-30 15:08:33 +00:00
Update gun.js
This commit is contained in:
parent
ca30236be5
commit
53d5417d4a
862
gun.js
862
gun.js
@ -1,5 +1,5 @@
|
||||
//console.log("!!!!!!!!!!!!!!!! WARNING THIS IS GUN 0.5 !!!!!!!!!!!!!!!!!!!!!!");
|
||||
;(function(){
|
||||
//console.log("!!!!!!!!!!!!!!!! WARNING THIS IS GUN 0.5 !!!!!!!!!!!!!!!!!!!!!!");
|
||||
;(function(){
|
||||
|
||||
/* UNBUILD */
|
||||
var root;
|
||||
@ -119,7 +119,7 @@
|
||||
t.r[k] = v;
|
||||
return;
|
||||
} t.r = t.r || [];
|
||||
t.r.push(k);
|
||||
t.r.push(k);
|
||||
};
|
||||
Type.obj.map = function(l, c, _){
|
||||
var u, i = 0, x, r, ll, lle, f = fn_is(c);
|
||||
@ -903,40 +903,40 @@
|
||||
|
||||
;(function(){
|
||||
|
||||
Gun.chain.opt = function(opt){
|
||||
opt = opt || {};
|
||||
var peers = obj_is(opt) ? opt.peers : opt;
|
||||
if (text_is(peers)) {
|
||||
peers = [peers];
|
||||
}
|
||||
if (list_is(peers)) {
|
||||
peers = obj_map(peers, function (url, field, m) {
|
||||
m(url, {});
|
||||
});
|
||||
}
|
||||
if (!obj_is(opt)) {
|
||||
opt = {};
|
||||
}
|
||||
opt.peers = peers;
|
||||
var gun = this, at = gun._;
|
||||
at.root = at.root || gun;
|
||||
Gun.chain.opt = function(opt){
|
||||
opt = opt || {};
|
||||
var peers = obj_is(opt) ? opt.peers : opt;
|
||||
if (text_is(peers)) {
|
||||
peers = [peers];
|
||||
}
|
||||
if (list_is(peers)) {
|
||||
peers = obj_map(peers, function (url, field, m) {
|
||||
m(url, {});
|
||||
});
|
||||
}
|
||||
if (!obj_is(opt)) {
|
||||
opt = {};
|
||||
}
|
||||
opt.peers = peers;
|
||||
var gun = this, at = gun._;
|
||||
at.root = at.root || gun;
|
||||
at.graph = at.graph || {};
|
||||
at.dedup = new Dedup();
|
||||
at.opt = at.opt || {};
|
||||
|
||||
at.opt.peers = Gun.obj.to(at.opt.peers || {}, peers);
|
||||
Gun.obj.to(opt, at.opt);
|
||||
|
||||
Gun.on('opt', at);
|
||||
if(!at.once){
|
||||
gun.on('in', input, at);
|
||||
gun.on('out', output, at);
|
||||
}
|
||||
at.once = true;
|
||||
return gun;
|
||||
}
|
||||
at.opt = at.opt || {};
|
||||
|
||||
at.opt.peers = Gun.obj.to(at.opt.peers || {}, peers);
|
||||
Gun.obj.to(opt, at.opt);
|
||||
|
||||
Gun.on('opt', at);
|
||||
if(!at.once){
|
||||
gun.on('in', input, at);
|
||||
gun.on('out', output, at);
|
||||
}
|
||||
at.once = true;
|
||||
return gun;
|
||||
}
|
||||
function output(at){
|
||||
var cat = this, gun = cat.gun, tmp;
|
||||
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){
|
||||
@ -1034,8 +1034,8 @@
|
||||
var de = this;
|
||||
var now = Gun.time.is();
|
||||
var oldest = now;
|
||||
var maxAge = 5 * 60 * 1000;
|
||||
// TODO: Gun.scheduler already does this? Reuse that.
|
||||
var maxAge = 5 * 60 * 1000;
|
||||
// TODO: Gun.scheduler already does this? Reuse that.
|
||||
Gun.obj.map(de.cache, function (time, id) {
|
||||
oldest = Math.min(now, time);
|
||||
|
||||
@ -1043,8 +1043,8 @@
|
||||
return;
|
||||
}
|
||||
|
||||
delete de.cache[id];
|
||||
});
|
||||
delete de.cache[id];
|
||||
});
|
||||
|
||||
var done = Gun.obj.empty(de.cache);
|
||||
|
||||
@ -1435,8 +1435,8 @@
|
||||
return gun;
|
||||
}
|
||||
function output(at){
|
||||
var cat = this, gun = cat.gun, root = gun.Back(-1), put, get, tmp;
|
||||
if(!at.gun){
|
||||
var cat = this, gun = cat.gun, root = gun.Back(-1), put, get, tmp;
|
||||
if(!at.gun){
|
||||
at.gun = gun;
|
||||
}
|
||||
if(at.get && !at.get[_soul]){
|
||||
@ -1750,7 +1750,7 @@
|
||||
via: at,
|
||||
put: at.put[cat.get]
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
if(obj_has(at.put, cat.get)){ return ev.off() }
|
||||
at = {
|
||||
@ -2142,13 +2142,13 @@
|
||||
var put = {}, soul = Gun.node.soul(node);
|
||||
if(!soul){ return cb.call(gun, {err: Gun.log('Only a node can be linked! Not "' + node + '"!')}) }
|
||||
gun.put(Gun.obj.put(put, soul, Gun.val.rel.ify(soul)), cb, opt);
|
||||
});
|
||||
}, {wait:0});
|
||||
}
|
||||
}());
|
||||
})(require, './api');
|
||||
|
||||
;require(function(module){
|
||||
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?
|
||||
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 }
|
||||
@ -2177,7 +2177,7 @@
|
||||
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)});
|
||||
@ -2187,391 +2187,391 @@
|
||||
Gun.on('get', get);
|
||||
})(require, './adapters/localStorage');
|
||||
|
||||
;require(function(module){
|
||||
var Gun = require('./gun');
|
||||
|
||||
// Check for stone-age browsers.
|
||||
if (typeof JSON === 'undefined') {
|
||||
throw new Error(
|
||||
'Gun depends on JSON. Please load it first:\n' +
|
||||
'ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js'
|
||||
);
|
||||
}
|
||||
|
||||
function Client (url, options) {
|
||||
if (!(this instanceof Client)) {
|
||||
return new Client(url, options);
|
||||
}
|
||||
|
||||
this.url = Client.formatURL(url);
|
||||
this.socket = null;
|
||||
this.queue = [];
|
||||
this.sid = Gun.text.random(10);
|
||||
|
||||
this.on = Gun.on;
|
||||
|
||||
this.options = options || {};
|
||||
this.resetBackoff();
|
||||
}
|
||||
|
||||
Client.prototype = {
|
||||
constructor: Client,
|
||||
|
||||
drainQueue: function () {
|
||||
var queue = this.queue;
|
||||
var client = this;
|
||||
|
||||
// Reset the queue.
|
||||
this.queue = [];
|
||||
|
||||
// Send each message.
|
||||
queue.forEach(function (msg) {
|
||||
client.send(msg);
|
||||
});
|
||||
|
||||
return queue.length;
|
||||
},
|
||||
|
||||
connect: function () {
|
||||
var client = this;
|
||||
var socket = new Client.WebSocket(this.url);
|
||||
this.socket = socket;
|
||||
|
||||
// Forward messages into the emitter.
|
||||
socket.addEventListener('message', function (msg) {
|
||||
client.on('message', msg);
|
||||
});
|
||||
|
||||
// Reconnect on close events.
|
||||
socket.addEventListener('close', function () {
|
||||
client.scheduleReconnect();
|
||||
});
|
||||
|
||||
// Send the messages in the queue.
|
||||
this.ready(function () {
|
||||
client.drainQueue();
|
||||
});
|
||||
|
||||
return socket;
|
||||
},
|
||||
|
||||
resetBackoff: function () {
|
||||
var backoff = this.options;
|
||||
|
||||
this.backoff = {
|
||||
time: backoff.time || 100,
|
||||
max: backoff.max || 30000,
|
||||
factor: backoff.factor || 2
|
||||
};
|
||||
|
||||
return this.backoff;
|
||||
},
|
||||
|
||||
nextBackoff: function () {
|
||||
var backoff = this.backoff;
|
||||
var next = backoff.time * backoff.factor;
|
||||
var max = backoff.max;
|
||||
|
||||
if (next > max) {
|
||||
next = max;
|
||||
}
|
||||
|
||||
return (backoff.time = next);
|
||||
},
|
||||
|
||||
// Try to efficiently reconnect.
|
||||
scheduleReconnect: function () {
|
||||
var client = this;
|
||||
var time = this.backoff.time;
|
||||
this.nextBackoff();
|
||||
|
||||
setTimeout(function () {
|
||||
client.connect();
|
||||
|
||||
client.ready(function () {
|
||||
client.resetBackoff();
|
||||
});
|
||||
}, time);
|
||||
},
|
||||
|
||||
isClosed: function () {
|
||||
var socket = this.socket;
|
||||
|
||||
if (!socket) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var state = socket.readyState;
|
||||
|
||||
if (state === socket.CLOSING || state === socket.CLOSED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
ready: function (callback) {
|
||||
var socket = this.socket;
|
||||
var state = socket.readyState;
|
||||
|
||||
if (state === socket.OPEN) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
if (state === socket.CONNECTING) {
|
||||
socket.addEventListener('open', callback);
|
||||
}
|
||||
},
|
||||
|
||||
send: function (msg) {
|
||||
if (this.isClosed()) {
|
||||
this.queue.push(msg);
|
||||
|
||||
// Will send once connected.
|
||||
this.connect();
|
||||
return false;
|
||||
}
|
||||
|
||||
var socket = this.socket;
|
||||
|
||||
// Make sure the socket is open.
|
||||
this.ready(function () {
|
||||
socket.send(msg);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
Client.WebSocket = window.WebSocket ||
|
||||
window.webkitWebSocket ||
|
||||
window.mozWebSocket ||
|
||||
null;
|
||||
}
|
||||
|
||||
Client.isSupported = Client.WebSocket !== null;
|
||||
|
||||
// Ensure the protocol is correct.
|
||||
Client.formatURL = function (url) {
|
||||
return url.replace('http', 'ws');
|
||||
};
|
||||
|
||||
// Send a message to a group of peers.
|
||||
Client.broadcast = function (urls, msg) {
|
||||
var pool = Client.pool;
|
||||
msg.headers = msg.headers || {};
|
||||
|
||||
Gun.obj.map(urls, function (options, addr) {
|
||||
|
||||
var url = Client.formatURL(addr);
|
||||
|
||||
var peer = pool[url];
|
||||
|
||||
var envelope = {
|
||||
headers: Gun.obj.to(msg.headers, {
|
||||
'gun-sid': peer.sid
|
||||
}),
|
||||
body: msg.body
|
||||
};
|
||||
|
||||
var serialized = Gun.text.ify(envelope);
|
||||
|
||||
peer.send(serialized);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// A map of URLs to client instances.
|
||||
Client.pool = {};
|
||||
|
||||
// Close all WebSockets when the window closes.
|
||||
if (typeof window !== 'undefined') {
|
||||
window.addEventListener('unload', function () {
|
||||
Gun.obj.map(Client.pool, function (client) {
|
||||
if (client.isClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
client.socket.close();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Define client instances as gun needs them.
|
||||
// Sockets will not be opened until absolutely necessary.
|
||||
Gun.on('opt', function (ctx) {
|
||||
|
||||
var gun = ctx.gun;
|
||||
var peers = gun.Back('opt.peers') || {};
|
||||
|
||||
Gun.obj.map(peers, function (options, addr) {
|
||||
var url = Client.formatURL(addr);
|
||||
|
||||
// Ignore clients we've seen before.
|
||||
if (Client.pool.hasOwnProperty(url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var client = new Client(url, options.backoff);
|
||||
|
||||
// Add it to the pool.
|
||||
Client.pool[url] = client;
|
||||
|
||||
// Listen to incoming messages.
|
||||
client.on('message', function (msg) {
|
||||
var data;
|
||||
|
||||
try {
|
||||
data = Gun.obj.ify(msg.data);
|
||||
} catch (err) {
|
||||
// Invalid message, discard it.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data || !data.body) {
|
||||
return;
|
||||
}
|
||||
|
||||
gun.on('in', data.body);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function request (peers, ctx) {
|
||||
if (Client.isSupported) {
|
||||
Client.broadcast(peers, { body: ctx });
|
||||
}
|
||||
}
|
||||
|
||||
// Broadcast the messages.
|
||||
Gun.on('out', function (ctx) {
|
||||
var gun = ctx.gun;
|
||||
|
||||
var peers = gun.Back('opt.peers') || {};
|
||||
|
||||
// Validate.
|
||||
if (Gun.obj.empty(peers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
request(peers, ctx);
|
||||
});
|
||||
|
||||
request.jsonp = function (opt, cb) {
|
||||
request.jsonp.ify(opt, function (url) {
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
request.jsonp.send(url, function (err, reply) {
|
||||
cb(err, reply);
|
||||
request.jsonp.poll(opt, reply);
|
||||
}, opt.jsonp);
|
||||
});
|
||||
};
|
||||
request.jsonp.send = function (url, cb, id) {
|
||||
var js = document.createElement('script');
|
||||
js.src = url;
|
||||
js.onerror = function () {
|
||||
(window[js.id] || function () {})(null, {
|
||||
err: 'JSONP failed!'
|
||||
});
|
||||
};
|
||||
window[js.id = id] = function (res, err) {
|
||||
cb(err, res);
|
||||
cb.id = js.id;
|
||||
js.parentNode.removeChild(js);
|
||||
delete window[cb.id];
|
||||
};
|
||||
js.async = true;
|
||||
document.getElementsByTagName('head')[0].appendChild(js);
|
||||
return js;
|
||||
};
|
||||
request.jsonp.poll = function (opt, res) {
|
||||
if (!opt || !opt.base || !res || !res.headers || !res.headers.poll) {
|
||||
return;
|
||||
}
|
||||
var polls = request.jsonp.poll.s = request.jsonp.poll.s || {};
|
||||
polls[opt.base] = polls[opt.base] || setTimeout(function () {
|
||||
var msg = {
|
||||
base: opt.base,
|
||||
headers: { pull: 1 }
|
||||
};
|
||||
|
||||
request.each(opt.headers, function (header, name) {
|
||||
msg.headers[name] = header;
|
||||
});
|
||||
|
||||
request.jsonp(msg, function (err, reply) {
|
||||
delete polls[opt.base];
|
||||
|
||||
var body = reply.body || [];
|
||||
while (body.length && body.shift) {
|
||||
var res = reply.body.shift();
|
||||
if (res && res.body) {
|
||||
request.createServer.ing(res, function () {
|
||||
request(opt.base, null, null, res);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, res.headers.poll);
|
||||
};
|
||||
request.jsonp.ify = function (opt, cb) {
|
||||
var uri = encodeURIComponent, query = '?';
|
||||
if (opt.url && opt.url.pathname) {
|
||||
query = opt.url.pathname + query;
|
||||
}
|
||||
query = opt.base + query;
|
||||
request.each((opt.url || {}).query, function (value, key) {
|
||||
query += (uri(key) + '=' + uri(value) + '&');
|
||||
});
|
||||
if (opt.headers) {
|
||||
query += uri('`') + '=' + uri(
|
||||
JSON.stringify(opt.headers)
|
||||
) + '&';
|
||||
}
|
||||
if (request.jsonp.max < query.length) {
|
||||
return cb();
|
||||
}
|
||||
var random = Math.floor(Math.random() * (0xffff + 1));
|
||||
query += (uri('jsonp') + '=' + uri(opt.jsonp = 'P' + random));
|
||||
if (opt.body) {
|
||||
query += '&';
|
||||
var w = opt.body, wls = function (w, l, s) {
|
||||
return uri('%') + '=' + uri(w+'-'+(l||w)+'/'+(s||w)) + '&' + uri('$') + '=';
|
||||
;require(function(module){
|
||||
var Gun = require('./gun');
|
||||
|
||||
// Check for stone-age browsers.
|
||||
if (typeof JSON === 'undefined') {
|
||||
throw new Error(
|
||||
'Gun depends on JSON. Please load it first:\n' +
|
||||
'ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js'
|
||||
);
|
||||
}
|
||||
|
||||
function Client (url, options) {
|
||||
if (!(this instanceof Client)) {
|
||||
return new Client(url, options);
|
||||
}
|
||||
|
||||
this.url = Client.formatURL(url);
|
||||
this.socket = null;
|
||||
this.queue = [];
|
||||
this.sid = Gun.text.random(10);
|
||||
|
||||
this.on = Gun.on;
|
||||
|
||||
this.options = options || {};
|
||||
this.resetBackoff();
|
||||
}
|
||||
|
||||
Client.prototype = {
|
||||
constructor: Client,
|
||||
|
||||
drainQueue: function () {
|
||||
var queue = this.queue;
|
||||
var client = this;
|
||||
|
||||
// Reset the queue.
|
||||
this.queue = [];
|
||||
|
||||
// Send each message.
|
||||
queue.forEach(function (msg) {
|
||||
client.send(msg);
|
||||
});
|
||||
|
||||
return queue.length;
|
||||
},
|
||||
|
||||
connect: function () {
|
||||
var client = this;
|
||||
var socket = new Client.WebSocket(this.url);
|
||||
this.socket = socket;
|
||||
|
||||
// Forward messages into the emitter.
|
||||
socket.addEventListener('message', function (msg) {
|
||||
client.on('message', msg);
|
||||
});
|
||||
|
||||
// Reconnect on close events.
|
||||
socket.addEventListener('close', function () {
|
||||
client.scheduleReconnect();
|
||||
});
|
||||
|
||||
// Send the messages in the queue.
|
||||
this.ready(function () {
|
||||
client.drainQueue();
|
||||
});
|
||||
|
||||
return socket;
|
||||
},
|
||||
|
||||
resetBackoff: function () {
|
||||
var backoff = this.options;
|
||||
|
||||
this.backoff = {
|
||||
time: backoff.time || 100,
|
||||
max: backoff.max || 30000,
|
||||
factor: backoff.factor || 2
|
||||
};
|
||||
|
||||
return this.backoff;
|
||||
},
|
||||
|
||||
nextBackoff: function () {
|
||||
var backoff = this.backoff;
|
||||
var next = backoff.time * backoff.factor;
|
||||
var max = backoff.max;
|
||||
|
||||
if (next > max) {
|
||||
next = max;
|
||||
}
|
||||
if (typeof w != 'string') {
|
||||
w = JSON.stringify(w);
|
||||
query += uri('^') + '=' + uri('json') + '&';
|
||||
}
|
||||
w = uri(w);
|
||||
var i = 0, l = w.length
|
||||
, s = request.jsonp.max - (query.length + wls(l.toString()).length);
|
||||
if (s < 0){
|
||||
return cb();
|
||||
}
|
||||
while (w) {
|
||||
cb(query + wls(i, (i += s), l) + w.slice(0, i));
|
||||
w = w.slice(i);
|
||||
}
|
||||
} else {
|
||||
cb(query);
|
||||
}
|
||||
};
|
||||
request.jsonp.max = 2000;
|
||||
request.each = function (obj, cb, as) {
|
||||
if (!obj || !cb) {
|
||||
return;
|
||||
}
|
||||
for (var key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
cb.call(as, obj[key], key);
|
||||
}
|
||||
}
|
||||
};
|
||||
module.exports = Client;
|
||||
})(require, './polyfill/request');
|
||||
|
||||
}());
|
||||
|
||||
return (backoff.time = next);
|
||||
},
|
||||
|
||||
// Try to efficiently reconnect.
|
||||
scheduleReconnect: function () {
|
||||
var client = this;
|
||||
var time = this.backoff.time;
|
||||
this.nextBackoff();
|
||||
|
||||
setTimeout(function () {
|
||||
client.connect();
|
||||
|
||||
client.ready(function () {
|
||||
client.resetBackoff();
|
||||
});
|
||||
}, time);
|
||||
},
|
||||
|
||||
isClosed: function () {
|
||||
var socket = this.socket;
|
||||
|
||||
if (!socket) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var state = socket.readyState;
|
||||
|
||||
if (state === socket.CLOSING || state === socket.CLOSED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
ready: function (callback) {
|
||||
var socket = this.socket;
|
||||
var state = socket.readyState;
|
||||
|
||||
if (state === socket.OPEN) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
if (state === socket.CONNECTING) {
|
||||
socket.addEventListener('open', callback);
|
||||
}
|
||||
},
|
||||
|
||||
send: function (msg) {
|
||||
if (this.isClosed()) {
|
||||
this.queue.push(msg);
|
||||
|
||||
// Will send once connected.
|
||||
this.connect();
|
||||
return false;
|
||||
}
|
||||
|
||||
var socket = this.socket;
|
||||
|
||||
// Make sure the socket is open.
|
||||
this.ready(function () {
|
||||
socket.send(msg);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
Client.WebSocket = window.WebSocket ||
|
||||
window.webkitWebSocket ||
|
||||
window.mozWebSocket ||
|
||||
null;
|
||||
}
|
||||
|
||||
Client.isSupported = Client.WebSocket !== null;
|
||||
|
||||
// Ensure the protocol is correct.
|
||||
Client.formatURL = function (url) {
|
||||
return url.replace('http', 'ws');
|
||||
};
|
||||
|
||||
// Send a message to a group of peers.
|
||||
Client.broadcast = function (urls, msg) {
|
||||
var pool = Client.pool;
|
||||
msg.headers = msg.headers || {};
|
||||
|
||||
Gun.obj.map(urls, function (options, addr) {
|
||||
|
||||
var url = Client.formatURL(addr);
|
||||
|
||||
var peer = pool[url];
|
||||
|
||||
var envelope = {
|
||||
headers: Gun.obj.to(msg.headers, {
|
||||
'gun-sid': peer.sid
|
||||
}),
|
||||
body: msg.body
|
||||
};
|
||||
|
||||
var serialized = Gun.text.ify(envelope);
|
||||
|
||||
peer.send(serialized);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// A map of URLs to client instances.
|
||||
Client.pool = {};
|
||||
|
||||
// Close all WebSockets when the window closes.
|
||||
if (typeof window !== 'undefined') {
|
||||
window.addEventListener('unload', function () {
|
||||
Gun.obj.map(Client.pool, function (client) {
|
||||
if (client.isClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
client.socket.close();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Define client instances as gun needs them.
|
||||
// Sockets will not be opened until absolutely necessary.
|
||||
Gun.on('opt', function (ctx) {
|
||||
|
||||
var gun = ctx.gun;
|
||||
var peers = gun.Back('opt.peers') || {};
|
||||
|
||||
Gun.obj.map(peers, function (options, addr) {
|
||||
var url = Client.formatURL(addr);
|
||||
|
||||
// Ignore clients we've seen before.
|
||||
if (Client.pool.hasOwnProperty(url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var client = new Client(url, options.backoff);
|
||||
|
||||
// Add it to the pool.
|
||||
Client.pool[url] = client;
|
||||
|
||||
// Listen to incoming messages.
|
||||
client.on('message', function (msg) {
|
||||
var data;
|
||||
|
||||
try {
|
||||
data = Gun.obj.ify(msg.data);
|
||||
} catch (err) {
|
||||
// Invalid message, discard it.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data || !data.body) {
|
||||
return;
|
||||
}
|
||||
|
||||
gun.on('in', data.body);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function request (peers, ctx) {
|
||||
if (Client.isSupported) {
|
||||
Client.broadcast(peers, { body: ctx });
|
||||
}
|
||||
}
|
||||
|
||||
// Broadcast the messages.
|
||||
Gun.on('out', function (ctx) {
|
||||
var gun = ctx.gun;
|
||||
|
||||
var peers = gun.Back('opt.peers') || {};
|
||||
|
||||
// Validate.
|
||||
if (Gun.obj.empty(peers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
request(peers, ctx);
|
||||
});
|
||||
|
||||
request.jsonp = function (opt, cb) {
|
||||
request.jsonp.ify(opt, function (url) {
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
request.jsonp.send(url, function (err, reply) {
|
||||
cb(err, reply);
|
||||
request.jsonp.poll(opt, reply);
|
||||
}, opt.jsonp);
|
||||
});
|
||||
};
|
||||
request.jsonp.send = function (url, cb, id) {
|
||||
var js = document.createElement('script');
|
||||
js.src = url;
|
||||
js.onerror = function () {
|
||||
(window[js.id] || function () {})(null, {
|
||||
err: 'JSONP failed!'
|
||||
});
|
||||
};
|
||||
window[js.id = id] = function (res, err) {
|
||||
cb(err, res);
|
||||
cb.id = js.id;
|
||||
js.parentNode.removeChild(js);
|
||||
delete window[cb.id];
|
||||
};
|
||||
js.async = true;
|
||||
document.getElementsByTagName('head')[0].appendChild(js);
|
||||
return js;
|
||||
};
|
||||
request.jsonp.poll = function (opt, res) {
|
||||
if (!opt || !opt.base || !res || !res.headers || !res.headers.poll) {
|
||||
return;
|
||||
}
|
||||
var polls = request.jsonp.poll.s = request.jsonp.poll.s || {};
|
||||
polls[opt.base] = polls[opt.base] || setTimeout(function () {
|
||||
var msg = {
|
||||
base: opt.base,
|
||||
headers: { pull: 1 }
|
||||
};
|
||||
|
||||
request.each(opt.headers, function (header, name) {
|
||||
msg.headers[name] = header;
|
||||
});
|
||||
|
||||
request.jsonp(msg, function (err, reply) {
|
||||
delete polls[opt.base];
|
||||
|
||||
var body = reply.body || [];
|
||||
while (body.length && body.shift) {
|
||||
var res = reply.body.shift();
|
||||
if (res && res.body) {
|
||||
request.createServer.ing(res, function () {
|
||||
request(opt.base, null, null, res);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, res.headers.poll);
|
||||
};
|
||||
request.jsonp.ify = function (opt, cb) {
|
||||
var uri = encodeURIComponent, query = '?';
|
||||
if (opt.url && opt.url.pathname) {
|
||||
query = opt.url.pathname + query;
|
||||
}
|
||||
query = opt.base + query;
|
||||
request.each((opt.url || {}).query, function (value, key) {
|
||||
query += (uri(key) + '=' + uri(value) + '&');
|
||||
});
|
||||
if (opt.headers) {
|
||||
query += uri('`') + '=' + uri(
|
||||
JSON.stringify(opt.headers)
|
||||
) + '&';
|
||||
}
|
||||
if (request.jsonp.max < query.length) {
|
||||
return cb();
|
||||
}
|
||||
var random = Math.floor(Math.random() * (0xffff + 1));
|
||||
query += (uri('jsonp') + '=' + uri(opt.jsonp = 'P' + random));
|
||||
if (opt.body) {
|
||||
query += '&';
|
||||
var w = opt.body, wls = function (w, l, s) {
|
||||
return uri('%') + '=' + uri(w+'-'+(l||w)+'/'+(s||w)) + '&' + uri('$') + '=';
|
||||
}
|
||||
if (typeof w != 'string') {
|
||||
w = JSON.stringify(w);
|
||||
query += uri('^') + '=' + uri('json') + '&';
|
||||
}
|
||||
w = uri(w);
|
||||
var i = 0, l = w.length
|
||||
, s = request.jsonp.max - (query.length + wls(l.toString()).length);
|
||||
if (s < 0){
|
||||
return cb();
|
||||
}
|
||||
while (w) {
|
||||
cb(query + wls(i, (i += s), l) + w.slice(0, i));
|
||||
w = w.slice(i);
|
||||
}
|
||||
} else {
|
||||
cb(query);
|
||||
}
|
||||
};
|
||||
request.jsonp.max = 2000;
|
||||
request.each = function (obj, cb, as) {
|
||||
if (!obj || !cb) {
|
||||
return;
|
||||
}
|
||||
for (var key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
cb.call(as, obj[key], key);
|
||||
}
|
||||
}
|
||||
};
|
||||
module.exports = Client;
|
||||
})(require, './polyfill/request');
|
||||
|
||||
}());
|
||||
|
Loading…
x
Reference in New Issue
Block a user