mirror of
https://github.com/amark/gun.git
synced 2025-06-07 14:46:44 +00:00
commit
a3a9d76d42
322
gun.js
322
gun.js
@ -621,21 +621,25 @@
|
|||||||
function Dup(opt){
|
function Dup(opt){
|
||||||
var dup = {s:{}};
|
var dup = {s:{}};
|
||||||
opt = opt || {max: 1000, age: 1000 * 9};//1000 * 60 * 2};
|
opt = opt || {max: 1000, age: 1000 * 9};//1000 * 60 * 2};
|
||||||
dup.check = function(id){
|
dup.check = function(id){ var tmp;
|
||||||
return dup.s[id]? dup.track(id) : false;
|
if(!(tmp = dup.s[id])){ return false }
|
||||||
|
if(tmp.pass){ return tmp.pass = false }
|
||||||
|
return dup.track(id);
|
||||||
}
|
}
|
||||||
dup.track = function(id){
|
dup.track = function(id, pass){
|
||||||
dup.s[id] = time_is();
|
var it = dup.s[id] || (dup.s[id] = {});
|
||||||
|
it.was = time_is();
|
||||||
|
if(pass){ it.pass = true }
|
||||||
if(!dup.to){
|
if(!dup.to){
|
||||||
dup.to = setTimeout(function(){
|
dup.to = setTimeout(function(){
|
||||||
Type.obj.map(dup.s, function(time, id){
|
Type.obj.map(dup.s, function(it, id){
|
||||||
if(opt.age > (time_is() - time)){ return }
|
if(opt.age > (time_is() - it.was)){ return }
|
||||||
Type.obj.del(dup.s, id);
|
Type.obj.del(dup.s, id);
|
||||||
});
|
});
|
||||||
dup.to = null;
|
dup.to = null;
|
||||||
}, opt.age);
|
}, opt.age);
|
||||||
}
|
}
|
||||||
return id;
|
return it;
|
||||||
}
|
}
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
@ -685,13 +689,13 @@
|
|||||||
return gun;
|
return gun;
|
||||||
}
|
}
|
||||||
function root(msg){
|
function root(msg){
|
||||||
//console.log("add to.next(at)"); // TODO: BUG!!!
|
//console.log("add to.next(at)"); // TODO: MISSING FEATURE!!!
|
||||||
var ev = this, at = ev.as, gun = at.gun, tmp;
|
var ev = this, at = ev.as, gun = at.gun, dup, tmp;
|
||||||
//if(!msg.gun){ msg.gun = at.gun }
|
//if(!msg.gun){ msg.gun = at.gun }
|
||||||
if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) }
|
if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) }
|
||||||
if(at.dup.check(tmp)){ return }
|
if((dup = at.dup).check(tmp)){ return }
|
||||||
at.dup.track(tmp);
|
dup.track(tmp);
|
||||||
msg = obj_to(msg);//, {gun: at.gun});
|
//msg = obj_to(msg);//, {gun: at.gun}); // can we delete this now?
|
||||||
if(!at.ask(msg['@'], msg)){
|
if(!at.ask(msg['@'], msg)){
|
||||||
if(msg.get){
|
if(msg.get){
|
||||||
Gun.on.get(msg, gun);
|
Gun.on.get(msg, gun);
|
||||||
@ -804,7 +808,7 @@
|
|||||||
//tmp = at.ack;
|
//tmp = at.ack;
|
||||||
root.on('in', {
|
root.on('in', {
|
||||||
'@': msg['#'],
|
'@': msg['#'],
|
||||||
//how: 'mem',
|
how: 'mem',
|
||||||
put: node,
|
put: node,
|
||||||
gun: gun
|
gun: gun
|
||||||
});
|
});
|
||||||
@ -940,7 +944,7 @@
|
|||||||
}*/
|
}*/
|
||||||
if(get['#'] || at.soul){
|
if(get['#'] || at.soul){
|
||||||
get['#'] = get['#'] || at.soul;
|
get['#'] = get['#'] || at.soul;
|
||||||
msg['#'] || (msg['#'] = text_rand());
|
msg['#'] || (msg['#'] = text_rand(9));
|
||||||
back = (root.gun.get(get['#'])._);
|
back = (root.gun.get(get['#'])._);
|
||||||
if(!(get = get['.'])){
|
if(!(get = get['.'])){
|
||||||
if(obj_has(back, 'put')){
|
if(obj_has(back, 'put')){
|
||||||
@ -1555,6 +1559,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
Gun.chain.val = function(cb, opt){
|
Gun.chain.val = function(cb, opt){
|
||||||
|
Gun.log.once("onceval", "Future Breaking API Change: .val -> .once, apologies unexpected.");
|
||||||
|
return this.once(cb, opt);
|
||||||
|
}
|
||||||
|
Gun.chain.once = function(cb, opt){
|
||||||
var gun = this, at = gun._, data = at.put;
|
var gun = this, at = gun._, data = at.put;
|
||||||
if(0 < at.ack && u !== data){
|
if(0 < at.ack && u !== data){
|
||||||
(cb || noop).call(gun, data, at.get);
|
(cb || noop).call(gun, data, at.get);
|
||||||
@ -1569,7 +1577,7 @@
|
|||||||
} else {
|
} else {
|
||||||
Gun.log.once("valonce", "Chainable val is experimental, its behavior and API may change moving forward. Please play with it and report bugs and ideas on how to improve it.");
|
Gun.log.once("valonce", "Chainable val is experimental, its behavior and API may change moving forward. Please play with it and report bugs and ideas on how to improve it.");
|
||||||
var chain = gun.chain();
|
var chain = gun.chain();
|
||||||
chain._.val = gun.val(function(){
|
chain._.val = gun.once(function(){
|
||||||
chain._.on('in', gun._);
|
chain._.on('in', gun._);
|
||||||
});
|
});
|
||||||
return chain;
|
return chain;
|
||||||
@ -1793,105 +1801,249 @@
|
|||||||
})(USE, './adapters/localStorage');
|
})(USE, './adapters/localStorage');
|
||||||
|
|
||||||
;USE(function(module){
|
;USE(function(module){
|
||||||
var Gun = USE('./index');
|
var Type = USE('./type');
|
||||||
var websocket;
|
|
||||||
if(typeof WebSocket !== 'undefined'){
|
function Mesh(ctx){
|
||||||
websocket = WebSocket;
|
var mesh = function(){};
|
||||||
|
|
||||||
|
mesh.out = function(msg){ var tmp;
|
||||||
|
if(this.to){ this.to.next(msg) }
|
||||||
|
if((tmp = msg['@'])
|
||||||
|
&& (tmp = ctx.dup.s[tmp])
|
||||||
|
&& (tmp = tmp.it)){
|
||||||
|
mesh.say(msg, tmp.mesh.via);
|
||||||
|
tmp['##'] = msg['##'];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// add hook for AXE?
|
||||||
|
mesh.say(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh.hear = function(msg, peer){
|
||||||
|
if(!msg){ return }
|
||||||
|
var dup = ctx.dup, id, hash, tmp = msg[0];
|
||||||
|
try{msg = JSON.parse(msg);
|
||||||
|
}catch(e){}
|
||||||
|
if('{' === tmp){
|
||||||
|
|
||||||
|
if(dup.check(id = msg['#'])){ return }
|
||||||
|
dup.track(id, true).it = msg; // GUN core also dedups, so `true` is needed.
|
||||||
|
if((tmp = msg['@']) && msg.put){
|
||||||
|
hash = msg['##'] || (msg['##'] = mesh.hash(msg));
|
||||||
|
if((tmp = tmp + hash) != id){
|
||||||
|
if(dup.check(tmp)){ return }
|
||||||
|
(tmp = dup.s)[hash] = tmp[id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(msg.mesh = function(){}).via = peer;
|
||||||
|
if((tmp = msg['><'])){
|
||||||
|
msg.mesh.to = Type.obj.map(tmp.split(','), function(k,i,m){m(k,true)});
|
||||||
|
}
|
||||||
|
ctx.on('in', msg);
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
if('[' === tmp){
|
||||||
|
|
||||||
|
var i = 0, m;
|
||||||
|
while(m = msg[i++]){
|
||||||
|
mesh.hear(m, peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;(function(){
|
||||||
|
mesh.say = function(msg, peer){
|
||||||
|
/*
|
||||||
|
TODO: Plenty of performance optimizations
|
||||||
|
that can be made just based off of ordering,
|
||||||
|
and reducing function calls for cached writes.
|
||||||
|
*/
|
||||||
|
if(!peer){
|
||||||
|
Type.obj.map(ctx.opt.peers, function(peer){
|
||||||
|
mesh.say(msg, peer);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var tmp, wire = peer.wire || ((ctx.opt.wire) && ctx.opt.wire(peer)), msh, raw;// || open(peer, ctx); // TODO: Reopen!
|
||||||
|
if(!wire){ return }
|
||||||
|
msh = msg.mesh || empty;
|
||||||
|
if(peer === msh.via){ return }
|
||||||
|
if(!(raw = msh.raw)){ raw = mesh.raw(msg) }
|
||||||
|
if((tmp = msg['@'])
|
||||||
|
&& (tmp = ctx.dup.s[tmp])
|
||||||
|
&& (tmp = tmp.it)){
|
||||||
|
if(tmp.get && tmp['##'] && tmp['##'] === msg['##']){ // PERF: move this condition outside say?
|
||||||
|
return; // TODO: this still needs to be tested in the browser!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if((tmp = msh.to) && (tmp[peer.url] || tmp[peer.id])){ return } // TODO: still needs to be tested
|
||||||
|
if(peer.batch){
|
||||||
|
peer.batch.push(raw);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
peer.batch = [];
|
||||||
|
setTimeout(function(){
|
||||||
|
var tmp = peer.batch;
|
||||||
|
if(!tmp){ return }
|
||||||
|
peer.batch = null;
|
||||||
|
if(!tmp.length){ return }
|
||||||
|
send(JSON.stringify(tmp), peer);
|
||||||
|
}, ctx.opt.wait || 1);
|
||||||
|
send(raw, peer);
|
||||||
|
}
|
||||||
|
function send(raw, peer){
|
||||||
|
var wire = peer.wire;
|
||||||
|
try{
|
||||||
|
if(wire.send){
|
||||||
|
if(wire.readyState === wire.OPEN){
|
||||||
|
wire.send(raw);
|
||||||
} else {
|
} else {
|
||||||
if(typeof webkitWebSocket !== 'undefined'){
|
(peer.queue = peer.queue || []).push(raw);
|
||||||
websocket = webkitWebSocket;
|
|
||||||
}
|
}
|
||||||
if(typeof mozWebSocket !== 'undefined'){
|
} else
|
||||||
websocket = mozWebSocket;
|
if(peer.say){
|
||||||
|
peer.say(raw);
|
||||||
|
}
|
||||||
|
}catch(e){
|
||||||
|
(peer.queue = peer.queue || []).push(raw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}());
|
||||||
|
|
||||||
|
;(function(){
|
||||||
|
|
||||||
|
mesh.raw = function(msg){
|
||||||
|
if(!msg){ return '' }
|
||||||
|
var dup = ctx.dup, msh = msg.mesh || {}, put, hash, tmp;
|
||||||
|
if(tmp = msh.raw){ return tmp }
|
||||||
|
if(typeof msg === 'string'){ return msg }
|
||||||
|
if(msg['@'] && (tmp = msg.put)){
|
||||||
|
if(!(hash = msg['##'])){
|
||||||
|
put = $(tmp, sort) || '';
|
||||||
|
hash = mesh.hash(msg, put);
|
||||||
|
msg['##'] = hash;
|
||||||
|
}
|
||||||
|
(tmp = dup.s)[hash = msg['@']+hash] = tmp[msg['#']];
|
||||||
|
msg['#'] = hash;
|
||||||
|
if(put){ (msg = Type.obj.to(msg)).put = _ }
|
||||||
|
}
|
||||||
|
msg['><'] = (Type.obj.map(ctx.opt.peers, function(p,k,m){
|
||||||
|
m(p.url || p.id);
|
||||||
|
}) || []).join();
|
||||||
|
var raw = $(msg);
|
||||||
|
if(u !== put){
|
||||||
|
raw = raw.replace('"'+ _ +'"', put);
|
||||||
|
}
|
||||||
|
if(msh){
|
||||||
|
msh.raw = raw;
|
||||||
|
}
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh.hash = function(msg, hash){
|
||||||
|
return Mesh.hash(hash || $(msg.put, sort) || '') || msg['#'] || Type.text.random(9);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sort(k, v){ var tmp;
|
||||||
|
if(!(v instanceof Object)){ return v }
|
||||||
|
Type.obj.map(Object.keys(v).sort(), map, {to: tmp = {}, on: v});
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
function map(k){
|
||||||
|
this.to[k] = this.on[k];
|
||||||
|
}
|
||||||
|
var $ = JSON.stringify, _ = ':])([:'
|
||||||
|
|
||||||
|
}());
|
||||||
|
|
||||||
|
mesh.hi = function(peer){
|
||||||
|
ctx.on('hi', peer);
|
||||||
|
var queue = peer.queue;
|
||||||
|
peer.queue = [];
|
||||||
|
Type.obj.map(queue, function(msg){
|
||||||
|
mesh.say(msg, peer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mesh.hash = function(s){ // via SO
|
||||||
|
if(typeof s !== 'string'){ return {err: 1} }
|
||||||
|
var c = 0;
|
||||||
|
if(!s.length){ return c }
|
||||||
|
for(var i=0,l=s.length,n; i<l; ++i){
|
||||||
|
n = s.charCodeAt(i);
|
||||||
|
c = ((c<<5)-c)+n;
|
||||||
|
c |= 0;
|
||||||
|
}
|
||||||
|
return c; // Math.abs(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
var empty = {}, u;
|
||||||
|
Object.keys = Object.keys || function(o){ return map(o, function(v,k,t){t(k)}) }
|
||||||
|
|
||||||
|
try{ module.exports = Mesh }catch(e){}
|
||||||
|
|
||||||
|
})(USE, './adapters/mesh');
|
||||||
|
|
||||||
|
;USE(function(module){
|
||||||
|
var Gun = USE('../index');
|
||||||
|
Gun.Mesh = USE('./mesh');
|
||||||
|
|
||||||
Gun.on('opt', function(root){
|
Gun.on('opt', function(root){
|
||||||
this.to.next(root);
|
this.to.next(root);
|
||||||
var opt = root.opt;
|
var opt = root.opt;
|
||||||
if(root.once){ return }
|
if(root.once){ return }
|
||||||
if(!websocket || false === opt.WebSocket){ return }
|
if(false === opt.WebSocket){ return }
|
||||||
var ws = opt.ws || (opt.ws = {}); ws.who = 0;
|
|
||||||
Gun.obj.map(opt.peers, function(){ ++ws.who });
|
|
||||||
if(root.once){ return }
|
|
||||||
var batch;
|
|
||||||
|
|
||||||
root.on('out', function(at){
|
var env;
|
||||||
this.to.next(at);
|
if(typeof window !== "undefined"){ env = window }
|
||||||
if(at.ws && 1 == ws.who){ return } // performance hack for reducing echoes.
|
if(typeof global !== "undefined"){ env = global }
|
||||||
batch = JSON.stringify(at);
|
env = env || {};
|
||||||
if(ws.drain){
|
|
||||||
ws.drain.push(batch);
|
var websocket = opt.WebSocket || env.WebSocket || env.webkitWebSocket || env.mozWebSocket;
|
||||||
return;
|
if(!websocket){ return }
|
||||||
}
|
opt.WebSocket = websocket;
|
||||||
ws.drain = [];
|
|
||||||
setTimeout(function(){
|
var mesh = opt.mesh = opt.mesh || Gun.Mesh(root);
|
||||||
if(!ws.drain){ return }
|
root.on('out', mesh.out);
|
||||||
var tmp = ws.drain;
|
|
||||||
ws.drain = null;
|
opt.wire = opt.wire || open;
|
||||||
if(!tmp.length){ return }
|
function open(peer){
|
||||||
batch = JSON.stringify(tmp);
|
|
||||||
Gun.obj.map(opt.peers, send, root);
|
|
||||||
}, opt.wait || 1);
|
|
||||||
Gun.obj.map(opt.peers, send, root);
|
|
||||||
});
|
|
||||||
function send(peer){
|
|
||||||
var root = this, msg = batch;
|
|
||||||
var wire = peer.wire || open(peer, root);
|
|
||||||
if(!wire){ return }
|
|
||||||
if(wire.readyState === wire.OPEN){
|
|
||||||
wire.send(msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
(peer.queue = peer.queue || []).push(msg);
|
|
||||||
}
|
|
||||||
function receive(msg, peer, root){
|
|
||||||
if(!root || !msg){ return }
|
|
||||||
try{msg = JSON.parse(msg.data || msg);
|
|
||||||
}catch(e){}
|
|
||||||
if(msg instanceof Array){
|
|
||||||
var i = 0, m;
|
|
||||||
while(m = msg[i++]){
|
|
||||||
receive(m, peer, root);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(1 == ws.who){ msg.ws = noop } // If there is only 1 client, just use noop since it doesn't matter.
|
|
||||||
root.on('in', msg);
|
|
||||||
}
|
|
||||||
function open(peer, as){
|
|
||||||
if(!peer || !peer.url){ return }
|
if(!peer || !peer.url){ return }
|
||||||
var url = peer.url.replace('http', 'ws');
|
var url = peer.url.replace('http', 'ws');
|
||||||
var wire = peer.wire = new websocket(url);
|
var wire = peer.wire = new opt.WebSocket(url);
|
||||||
wire.onclose = function(){
|
wire.onclose = function(){
|
||||||
root.on('bye', peer);
|
root.on('bye', peer);
|
||||||
reconnect(peer, as);
|
reconnect(peer);
|
||||||
};
|
};
|
||||||
wire.onerror = function(error){
|
wire.onerror = function(error){
|
||||||
reconnect(peer, as); // placement?
|
reconnect(peer); // placement?
|
||||||
if(!error){ return }
|
if(!error){ return }
|
||||||
if(error.code === 'ECONNREFUSED'){
|
if(error.code === 'ECONNREFUSED'){
|
||||||
//reconnect(peer, as);
|
//reconnect(peer, as);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
wire.onopen = function(){
|
wire.onopen = function(){
|
||||||
root.on('hi', peer);
|
mesh.hi(peer);
|
||||||
var queue = peer.queue;
|
|
||||||
peer.queue = [];
|
|
||||||
Gun.obj.map(queue, function(msg){
|
|
||||||
batch = msg;
|
|
||||||
send.call(as, peer);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
wire.onmessage = function(msg){
|
wire.onmessage = function(msg){
|
||||||
receive(msg, peer, as); // diff: peer not wire!
|
if(!msg){ return }
|
||||||
|
mesh.hear(msg.data || msg, peer);
|
||||||
};
|
};
|
||||||
return wire;
|
return wire;
|
||||||
}
|
}
|
||||||
function reconnect(peer, as){
|
|
||||||
|
function reconnect(peer){
|
||||||
clearTimeout(peer.defer);
|
clearTimeout(peer.defer);
|
||||||
peer.defer = setTimeout(function(){
|
peer.defer = setTimeout(function(){
|
||||||
open(peer, as);
|
open(peer);
|
||||||
}, 2 * 1000);
|
}, 2 * 1000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
2
gun.min.js
vendored
2
gun.min.js
vendored
File diff suppressed because one or more lines are too long
@ -2,6 +2,7 @@
|
|||||||
if('debug' !== process.env.GUN_ENV){ return }
|
if('debug' !== process.env.GUN_ENV){ return }
|
||||||
|
|
||||||
console.log("start :)");
|
console.log("start :)");
|
||||||
|
global.DEBUG = 1;
|
||||||
setInterval(function(){
|
setInterval(function(){
|
||||||
var mem = process.memoryUsage();
|
var mem = process.memoryUsage();
|
||||||
var used = mem.heapUsed / 1024 / 1024;
|
var used = mem.heapUsed / 1024 / 1024;
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
require('../nts');
|
require('../nts');
|
||||||
require('./store');
|
require('./store');
|
||||||
require('./rs3');
|
require('./rs3');
|
||||||
try{require('./ws');}catch(e){require('./wsp/server');}
|
//try{require('./ws');}catch(e){require('./wsp/server');}
|
||||||
|
require('./wire');
|
||||||
require('./verify');
|
require('./verify');
|
||||||
require('./file');
|
require('./file');
|
||||||
require('./bye');
|
require('./bye');
|
||||||
|
@ -16,11 +16,11 @@ Gun.on('opt', function(ctx){
|
|||||||
|
|
||||||
ctx.on('put', function(at){
|
ctx.on('put', function(at){
|
||||||
this.to.next(at);
|
this.to.next(at);
|
||||||
var id = at['#'], acks = at['@']? u : 0; // only ack non-acks.
|
var id = at['#'], track = !at['@'], acks = track? 0 : u; // only ack non-acks.
|
||||||
Gun.graph.is(at.put, null, function(val, key, node, soul){
|
Gun.graph.is(at.put, null, function(val, key, node, soul){
|
||||||
++acks;
|
if(track){ ++acks }
|
||||||
val = Radisk.encode(val)+'>'+Radisk.encode(Gun.state.is(node, key));
|
val = Radisk.encode(val)+'>'+Radisk.encode(Gun.state.is(node, key));
|
||||||
rad(soul+'.'+key, val, (u === acks? u : ack));
|
rad(soul+'.'+key, val, (track? ack : u));
|
||||||
});
|
});
|
||||||
function ack(err, ok){
|
function ack(err, ok){
|
||||||
acks--;
|
acks--;
|
||||||
|
91
lib/wire.js
Normal file
91
lib/wire.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
var Gun = require('../gun');
|
||||||
|
|
||||||
|
/*
|
||||||
|
An Ad-Hoc Mesh-Network Daisy-Chain
|
||||||
|
should work even if humans are
|
||||||
|
communicating with each other blind.
|
||||||
|
|
||||||
|
To prevent infinite broadcast loops,
|
||||||
|
we use a deduplication process
|
||||||
|
based on the message's identifier.
|
||||||
|
This is currently implemented in core.
|
||||||
|
|
||||||
|
However, because this still creates a
|
||||||
|
N*2 (where N is the number of connections)
|
||||||
|
flood, it is not scalable for traditional
|
||||||
|
services that have a hub network topology.
|
||||||
|
|
||||||
|
Does this mean we have to abandon mesh
|
||||||
|
algorithms? No, we can simply layer more
|
||||||
|
efficient optimizations in based on constraints.
|
||||||
|
If these constraints exist, it automatically
|
||||||
|
upgrades, but if not, it falls back to the
|
||||||
|
brute-force mesh based robust algorithm.
|
||||||
|
A simple example is to limit peer connections
|
||||||
|
and rely upon daisy chaining to relay messages.
|
||||||
|
|
||||||
|
Another example, is if peers are willing to
|
||||||
|
identify themselves, then we can improve the
|
||||||
|
efficiency of the network by having each peer
|
||||||
|
include the names of peers it is connected in
|
||||||
|
each message. Then each subsequent peer will
|
||||||
|
not relay it to them, since it is unnecessary.
|
||||||
|
This should create N (where N is the number of
|
||||||
|
peers) messages (or possibly N+ if there is a
|
||||||
|
common peer of uncommon peers that receives it
|
||||||
|
and relays at exact latency timings), which is
|
||||||
|
optimal.
|
||||||
|
|
||||||
|
Since computer networks aren't actually blind,
|
||||||
|
we will implement the above method to improve
|
||||||
|
the performance of the ad-hoc mesh network.
|
||||||
|
|
||||||
|
But why not have every message contain the
|
||||||
|
whole history of peers that it relayed through?
|
||||||
|
Because in sufficiently large enough networks,
|
||||||
|
with extensive daisy chaining, this will cause
|
||||||
|
the message to become prohibitively slow and
|
||||||
|
increase indefinitely in size.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
var WebSocket = require('ws');
|
||||||
|
|
||||||
|
var url = require('url');
|
||||||
|
|
||||||
|
Gun.on('opt', function(ctx){
|
||||||
|
var opt = ctx.opt;
|
||||||
|
if(false === opt.ws){
|
||||||
|
this.to.next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
opt.WebSocket = opt.WebSocket || WebSocket;
|
||||||
|
|
||||||
|
if(!opt.ws || !opt.ws.web){
|
||||||
|
|
||||||
|
var ws = opt.ws = opt.ws || {};
|
||||||
|
ws.server = ws.server || opt.web;
|
||||||
|
ws.path = ws.path || '/gun';
|
||||||
|
ws.web = new opt.WebSocket.Server(ws);
|
||||||
|
ws.web.on('connection', function(wire){
|
||||||
|
wire.upgradeReq = wire.upgradeReq || {};
|
||||||
|
wire.url = url.parse(wire.upgradeReq.url||'', true);
|
||||||
|
wire.id = wire.id || Gun.text.random(6);
|
||||||
|
var peer = opt.peers[wire.id] = {id: wire.id, wire: wire};
|
||||||
|
wire.peer = function(){ return peer };
|
||||||
|
ctx.on('hi', peer);
|
||||||
|
wire.on('message', function(msg){
|
||||||
|
//console.log("MESSAGE", msg);
|
||||||
|
opt.mesh.hear(msg.data || msg, peer);
|
||||||
|
});
|
||||||
|
wire.on('close', function(){
|
||||||
|
ctx.on('bye', peer);
|
||||||
|
Gun.obj.del(opt.peers, wire.id);
|
||||||
|
});
|
||||||
|
wire.on('error', function(e){});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.to.next(ctx);
|
||||||
|
});
|
@ -12,6 +12,7 @@ Gun.on('opt', function mount(ctx){
|
|||||||
opt.peers = [opt];
|
opt.peers = [opt];
|
||||||
|
|
||||||
if(ctx.once){ return }
|
if(ctx.once){ return }
|
||||||
|
if(false === opt.ws){ return }
|
||||||
var ws = opt.ws || (opt.ws = {}), batch;
|
var ws = opt.ws || (opt.ws = {}), batch;
|
||||||
|
|
||||||
if(opt.web){
|
if(opt.web){
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gun",
|
"name": "gun",
|
||||||
"version": "0.9.96",
|
"version": "0.9.97",
|
||||||
"description": "A realtime, decentralized, offline-first, graph data synchronization engine.",
|
"description": "A realtime, decentralized, offline-first, graph data synchronization engine.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"browser": "gun.min.js",
|
"browser": "gun.min.js",
|
||||||
|
191
src/adapters/mesh.js
Normal file
191
src/adapters/mesh.js
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
|
||||||
|
var Type = require('./type');
|
||||||
|
|
||||||
|
function Mesh(ctx){
|
||||||
|
var mesh = function(){};
|
||||||
|
|
||||||
|
mesh.out = function(msg){ var tmp;
|
||||||
|
if(this.to){ this.to.next(msg) }
|
||||||
|
if((tmp = msg['@'])
|
||||||
|
&& (tmp = ctx.dup.s[tmp])
|
||||||
|
&& (tmp = tmp.it)){
|
||||||
|
mesh.say(msg, tmp.mesh.via);
|
||||||
|
tmp['##'] = msg['##'];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// add hook for AXE?
|
||||||
|
mesh.say(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh.hear = function(msg, peer){
|
||||||
|
if(!msg){ return }
|
||||||
|
var dup = ctx.dup, id, hash, tmp = msg[0];
|
||||||
|
try{msg = JSON.parse(msg);
|
||||||
|
}catch(e){}
|
||||||
|
if('{' === tmp){
|
||||||
|
|
||||||
|
if(dup.check(id = msg['#'])){ return }
|
||||||
|
dup.track(id, true).it = msg; // GUN core also dedups, so `true` is needed.
|
||||||
|
if((tmp = msg['@']) && msg.put){
|
||||||
|
hash = msg['##'] || (msg['##'] = mesh.hash(msg));
|
||||||
|
if((tmp = tmp + hash) != id){
|
||||||
|
if(dup.check(tmp)){ return }
|
||||||
|
(tmp = dup.s)[hash] = tmp[id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(msg.mesh = function(){}).via = peer;
|
||||||
|
if((tmp = msg['><'])){
|
||||||
|
msg.mesh.to = Type.obj.map(tmp.split(','), function(k,i,m){m(k,true)});
|
||||||
|
}
|
||||||
|
ctx.on('in', msg);
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
if('[' === tmp){
|
||||||
|
|
||||||
|
var i = 0, m;
|
||||||
|
while(m = msg[i++]){
|
||||||
|
mesh.hear(m, peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;(function(){
|
||||||
|
mesh.say = function(msg, peer){
|
||||||
|
/*
|
||||||
|
TODO: Plenty of performance optimizations
|
||||||
|
that can be made just based off of ordering,
|
||||||
|
and reducing function calls for cached writes.
|
||||||
|
*/
|
||||||
|
if(!peer){
|
||||||
|
Type.obj.map(ctx.opt.peers, function(peer){
|
||||||
|
mesh.say(msg, peer);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var tmp, wire = peer.wire || ((ctx.opt.wire) && ctx.opt.wire(peer)), msh, raw;// || open(peer, ctx); // TODO: Reopen!
|
||||||
|
if(!wire){ return }
|
||||||
|
msh = msg.mesh || empty;
|
||||||
|
if(peer === msh.via){ return }
|
||||||
|
if(!(raw = msh.raw)){ raw = mesh.raw(msg) }
|
||||||
|
if((tmp = msg['@'])
|
||||||
|
&& (tmp = ctx.dup.s[tmp])
|
||||||
|
&& (tmp = tmp.it)){
|
||||||
|
if(tmp.get && tmp['##'] && tmp['##'] === msg['##']){ // PERF: move this condition outside say?
|
||||||
|
return; // TODO: this still needs to be tested in the browser!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if((tmp = msh.to) && (tmp[peer.url] || tmp[peer.id])){ return } // TODO: still needs to be tested
|
||||||
|
if(peer.batch){
|
||||||
|
peer.batch.push(raw);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
peer.batch = [];
|
||||||
|
setTimeout(function(){
|
||||||
|
var tmp = peer.batch;
|
||||||
|
if(!tmp){ return }
|
||||||
|
peer.batch = null;
|
||||||
|
if(!tmp.length){ return }
|
||||||
|
send(JSON.stringify(tmp), peer);
|
||||||
|
}, ctx.opt.wait || 1);
|
||||||
|
send(raw, peer);
|
||||||
|
}
|
||||||
|
function send(raw, peer){
|
||||||
|
var wire = peer.wire;
|
||||||
|
try{
|
||||||
|
if(wire.send){
|
||||||
|
if(wire.readyState === wire.OPEN){
|
||||||
|
wire.send(raw);
|
||||||
|
} else {
|
||||||
|
(peer.queue = peer.queue || []).push(raw);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
if(peer.say){
|
||||||
|
peer.say(raw);
|
||||||
|
}
|
||||||
|
}catch(e){
|
||||||
|
(peer.queue = peer.queue || []).push(raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}());
|
||||||
|
|
||||||
|
;(function(){
|
||||||
|
|
||||||
|
mesh.raw = function(msg){
|
||||||
|
if(!msg){ return '' }
|
||||||
|
var dup = ctx.dup, msh = msg.mesh || {}, put, hash, tmp;
|
||||||
|
if(tmp = msh.raw){ return tmp }
|
||||||
|
if(typeof msg === 'string'){ return msg }
|
||||||
|
if(msg['@'] && (tmp = msg.put)){
|
||||||
|
if(!(hash = msg['##'])){
|
||||||
|
put = $(tmp, sort) || '';
|
||||||
|
hash = mesh.hash(msg, put);
|
||||||
|
msg['##'] = hash;
|
||||||
|
}
|
||||||
|
(tmp = dup.s)[hash = msg['@']+hash] = tmp[msg['#']];
|
||||||
|
msg['#'] = hash;
|
||||||
|
if(put){ (msg = Type.obj.to(msg)).put = _ }
|
||||||
|
}
|
||||||
|
msg['><'] = (Type.obj.map(ctx.opt.peers, function(p,k,m){
|
||||||
|
m(p.url || p.id);
|
||||||
|
}) || []).join();
|
||||||
|
var raw = $(msg);
|
||||||
|
if(u !== put){
|
||||||
|
raw = raw.replace('"'+ _ +'"', put);
|
||||||
|
}
|
||||||
|
if(msh){
|
||||||
|
msh.raw = raw;
|
||||||
|
}
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh.hash = function(msg, hash){
|
||||||
|
return Mesh.hash(hash || $(msg.put, sort) || '') || msg['#'] || Type.text.random(9);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sort(k, v){ var tmp;
|
||||||
|
if(!(v instanceof Object)){ return v }
|
||||||
|
Type.obj.map(Object.keys(v).sort(), map, {to: tmp = {}, on: v});
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
function map(k){
|
||||||
|
this.to[k] = this.on[k];
|
||||||
|
}
|
||||||
|
var $ = JSON.stringify, _ = ':])([:'
|
||||||
|
|
||||||
|
}());
|
||||||
|
|
||||||
|
mesh.hi = function(peer){
|
||||||
|
ctx.on('hi', peer);
|
||||||
|
var queue = peer.queue;
|
||||||
|
peer.queue = [];
|
||||||
|
Type.obj.map(queue, function(msg){
|
||||||
|
mesh.say(msg, peer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mesh.hash = function(s){ // via SO
|
||||||
|
if(typeof s !== 'string'){ return {err: 1} }
|
||||||
|
var c = 0;
|
||||||
|
if(!s.length){ return c }
|
||||||
|
for(var i=0,l=s.length,n; i<l; ++i){
|
||||||
|
n = s.charCodeAt(i);
|
||||||
|
c = ((c<<5)-c)+n;
|
||||||
|
c |= 0;
|
||||||
|
}
|
||||||
|
return c; // Math.abs(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
var empty = {}, u;
|
||||||
|
Object.keys = Object.keys || function(o){ return map(o, function(v,k,t){t(k)}) }
|
||||||
|
|
||||||
|
try{ module.exports = Mesh }catch(e){}
|
||||||
|
|
||||||
|
|
@ -1,103 +1,55 @@
|
|||||||
|
|
||||||
var Gun = require('./index');
|
var Gun = require('../index');
|
||||||
var websocket;
|
Gun.Mesh = require('./mesh');
|
||||||
if(typeof WebSocket !== 'undefined'){
|
|
||||||
websocket = WebSocket;
|
|
||||||
} else {
|
|
||||||
if(typeof webkitWebSocket !== 'undefined'){
|
|
||||||
websocket = webkitWebSocket;
|
|
||||||
}
|
|
||||||
if(typeof mozWebSocket !== 'undefined'){
|
|
||||||
websocket = mozWebSocket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Gun.on('opt', function(root){
|
Gun.on('opt', function(root){
|
||||||
this.to.next(root);
|
this.to.next(root);
|
||||||
var opt = root.opt;
|
var opt = root.opt;
|
||||||
if(root.once){ return }
|
if(root.once){ return }
|
||||||
if(!websocket || false === opt.WebSocket){ return }
|
if(false === opt.WebSocket){ return }
|
||||||
var ws = opt.ws || (opt.ws = {}); ws.who = 0;
|
|
||||||
Gun.obj.map(opt.peers, function(){ ++ws.who });
|
|
||||||
if(root.once){ return }
|
|
||||||
var batch;
|
|
||||||
|
|
||||||
root.on('out', function(at){
|
var env;
|
||||||
this.to.next(at);
|
if(typeof window !== "undefined"){ env = window }
|
||||||
if(at.ws && 1 == ws.who){ return } // performance hack for reducing echoes.
|
if(typeof global !== "undefined"){ env = global }
|
||||||
batch = JSON.stringify(at);
|
env = env || {};
|
||||||
if(ws.drain){
|
|
||||||
ws.drain.push(batch);
|
var websocket = opt.WebSocket || env.WebSocket || env.webkitWebSocket || env.mozWebSocket;
|
||||||
return;
|
if(!websocket){ return }
|
||||||
}
|
opt.WebSocket = websocket;
|
||||||
ws.drain = [];
|
|
||||||
setTimeout(function(){
|
var mesh = opt.mesh = opt.mesh || Gun.Mesh(root);
|
||||||
if(!ws.drain){ return }
|
root.on('out', mesh.out);
|
||||||
var tmp = ws.drain;
|
|
||||||
ws.drain = null;
|
opt.wire = opt.wire || open;
|
||||||
if(!tmp.length){ return }
|
function open(peer){
|
||||||
batch = JSON.stringify(tmp);
|
|
||||||
Gun.obj.map(opt.peers, send, root);
|
|
||||||
}, opt.wait || 1);
|
|
||||||
Gun.obj.map(opt.peers, send, root);
|
|
||||||
});
|
|
||||||
function send(peer){
|
|
||||||
var root = this, msg = batch;
|
|
||||||
var wire = peer.wire || open(peer, root);
|
|
||||||
if(!wire){ return }
|
|
||||||
if(wire.readyState === wire.OPEN){
|
|
||||||
wire.send(msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
(peer.queue = peer.queue || []).push(msg);
|
|
||||||
}
|
|
||||||
function receive(msg, peer, root){
|
|
||||||
if(!root || !msg){ return }
|
|
||||||
try{msg = JSON.parse(msg.data || msg);
|
|
||||||
}catch(e){}
|
|
||||||
if(msg instanceof Array){
|
|
||||||
var i = 0, m;
|
|
||||||
while(m = msg[i++]){
|
|
||||||
receive(m, peer, root);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(1 == ws.who){ msg.ws = noop } // If there is only 1 client, just use noop since it doesn't matter.
|
|
||||||
root.on('in', msg);
|
|
||||||
}
|
|
||||||
function open(peer, as){
|
|
||||||
if(!peer || !peer.url){ return }
|
if(!peer || !peer.url){ return }
|
||||||
var url = peer.url.replace('http', 'ws');
|
var url = peer.url.replace('http', 'ws');
|
||||||
var wire = peer.wire = new websocket(url);
|
var wire = peer.wire = new opt.WebSocket(url);
|
||||||
wire.onclose = function(){
|
wire.onclose = function(){
|
||||||
root.on('bye', peer);
|
root.on('bye', peer);
|
||||||
reconnect(peer, as);
|
reconnect(peer);
|
||||||
};
|
};
|
||||||
wire.onerror = function(error){
|
wire.onerror = function(error){
|
||||||
reconnect(peer, as); // placement?
|
reconnect(peer); // placement?
|
||||||
if(!error){ return }
|
if(!error){ return }
|
||||||
if(error.code === 'ECONNREFUSED'){
|
if(error.code === 'ECONNREFUSED'){
|
||||||
//reconnect(peer, as);
|
//reconnect(peer, as);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
wire.onopen = function(){
|
wire.onopen = function(){
|
||||||
root.on('hi', peer);
|
mesh.hi(peer);
|
||||||
var queue = peer.queue;
|
|
||||||
peer.queue = [];
|
|
||||||
Gun.obj.map(queue, function(msg){
|
|
||||||
batch = msg;
|
|
||||||
send.call(as, peer);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
wire.onmessage = function(msg){
|
wire.onmessage = function(msg){
|
||||||
receive(msg, peer, as); // diff: peer not wire!
|
if(!msg){ return }
|
||||||
|
mesh.hear(msg.data || msg, peer);
|
||||||
};
|
};
|
||||||
return wire;
|
return wire;
|
||||||
}
|
}
|
||||||
function reconnect(peer, as){
|
|
||||||
|
function reconnect(peer){
|
||||||
clearTimeout(peer.defer);
|
clearTimeout(peer.defer);
|
||||||
peer.defer = setTimeout(function(){
|
peer.defer = setTimeout(function(){
|
||||||
open(peer, as);
|
open(peer);
|
||||||
}, 2 * 1000);
|
}, 2 * 1000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -25,7 +25,7 @@ function output(msg){
|
|||||||
}*/
|
}*/
|
||||||
if(get['#'] || at.soul){
|
if(get['#'] || at.soul){
|
||||||
get['#'] = get['#'] || at.soul;
|
get['#'] = get['#'] || at.soul;
|
||||||
msg['#'] || (msg['#'] = text_rand());
|
msg['#'] || (msg['#'] = text_rand(9));
|
||||||
back = (root.gun.get(get['#'])._);
|
back = (root.gun.get(get['#'])._);
|
||||||
if(!(get = get['.'])){
|
if(!(get = get['.'])){
|
||||||
if(obj_has(back, 'put')){
|
if(obj_has(back, 'put')){
|
||||||
|
18
src/dup.js
18
src/dup.js
@ -3,21 +3,25 @@ var Type = require('./type');
|
|||||||
function Dup(opt){
|
function Dup(opt){
|
||||||
var dup = {s:{}};
|
var dup = {s:{}};
|
||||||
opt = opt || {max: 1000, age: 1000 * 9};//1000 * 60 * 2};
|
opt = opt || {max: 1000, age: 1000 * 9};//1000 * 60 * 2};
|
||||||
dup.check = function(id){
|
dup.check = function(id){ var tmp;
|
||||||
return dup.s[id]? dup.track(id) : false;
|
if(!(tmp = dup.s[id])){ return false }
|
||||||
|
if(tmp.pass){ return tmp.pass = false }
|
||||||
|
return dup.track(id);
|
||||||
}
|
}
|
||||||
dup.track = function(id){
|
dup.track = function(id, pass){
|
||||||
dup.s[id] = time_is();
|
var it = dup.s[id] || (dup.s[id] = {});
|
||||||
|
it.was = time_is();
|
||||||
|
if(pass){ it.pass = true }
|
||||||
if(!dup.to){
|
if(!dup.to){
|
||||||
dup.to = setTimeout(function(){
|
dup.to = setTimeout(function(){
|
||||||
Type.obj.map(dup.s, function(time, id){
|
Type.obj.map(dup.s, function(it, id){
|
||||||
if(opt.age > (time_is() - time)){ return }
|
if(opt.age > (time_is() - it.was)){ return }
|
||||||
Type.obj.del(dup.s, id);
|
Type.obj.del(dup.s, id);
|
||||||
});
|
});
|
||||||
dup.to = null;
|
dup.to = null;
|
||||||
}, opt.age);
|
}, opt.age);
|
||||||
}
|
}
|
||||||
return id;
|
return it;
|
||||||
}
|
}
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,10 @@ function ok(at, ev){ var opt = this;
|
|||||||
}
|
}
|
||||||
|
|
||||||
Gun.chain.val = function(cb, opt){
|
Gun.chain.val = function(cb, opt){
|
||||||
|
Gun.log.once("onceval", "Future Breaking API Change: .val -> .once, apologies unexpected.");
|
||||||
|
return this.once(cb, opt);
|
||||||
|
}
|
||||||
|
Gun.chain.once = function(cb, opt){
|
||||||
var gun = this, at = gun._, data = at.put;
|
var gun = this, at = gun._, data = at.put;
|
||||||
if(0 < at.ack && u !== data){
|
if(0 < at.ack && u !== data){
|
||||||
(cb || noop).call(gun, data, at.get);
|
(cb || noop).call(gun, data, at.get);
|
||||||
@ -67,7 +71,7 @@ Gun.chain.val = function(cb, opt){
|
|||||||
} else {
|
} else {
|
||||||
Gun.log.once("valonce", "Chainable val is experimental, its behavior and API may change moving forward. Please play with it and report bugs and ideas on how to improve it.");
|
Gun.log.once("valonce", "Chainable val is experimental, its behavior and API may change moving forward. Please play with it and report bugs and ideas on how to improve it.");
|
||||||
var chain = gun.chain();
|
var chain = gun.chain();
|
||||||
chain._.val = gun.val(function(){
|
chain._.val = gun.once(function(){
|
||||||
chain._.on('in', gun._);
|
chain._.on('in', gun._);
|
||||||
});
|
});
|
||||||
return chain;
|
return chain;
|
||||||
|
12
src/root.js
12
src/root.js
@ -40,13 +40,13 @@ Gun.dup = require('./dup');
|
|||||||
return gun;
|
return gun;
|
||||||
}
|
}
|
||||||
function root(msg){
|
function root(msg){
|
||||||
//console.log("add to.next(at)"); // TODO: BUG!!!
|
//console.log("add to.next(at)"); // TODO: MISSING FEATURE!!!
|
||||||
var ev = this, at = ev.as, gun = at.gun, tmp;
|
var ev = this, at = ev.as, gun = at.gun, dup, tmp;
|
||||||
//if(!msg.gun){ msg.gun = at.gun }
|
//if(!msg.gun){ msg.gun = at.gun }
|
||||||
if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) }
|
if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) }
|
||||||
if(at.dup.check(tmp)){ return }
|
if((dup = at.dup).check(tmp)){ return }
|
||||||
at.dup.track(tmp);
|
dup.track(tmp);
|
||||||
msg = obj_to(msg);//, {gun: at.gun});
|
//msg = obj_to(msg);//, {gun: at.gun}); // can we delete this now?
|
||||||
if(!at.ask(msg['@'], msg)){
|
if(!at.ask(msg['@'], msg)){
|
||||||
if(msg.get){
|
if(msg.get){
|
||||||
Gun.on.get(msg, gun);
|
Gun.on.get(msg, gun);
|
||||||
@ -159,7 +159,7 @@ Gun.dup = require('./dup');
|
|||||||
//tmp = at.ack;
|
//tmp = at.ack;
|
||||||
root.on('in', {
|
root.on('in', {
|
||||||
'@': msg['#'],
|
'@': msg['#'],
|
||||||
//how: 'mem',
|
how: 'mem',
|
||||||
put: node,
|
put: node,
|
||||||
gun: gun
|
gun: gun
|
||||||
});
|
});
|
||||||
|
5
test/gun.html
Normal file
5
test/gun.html
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<script src="../examples/jquery.js"></script>
|
||||||
|
<script src="../gun.js"></script>
|
||||||
|
<script>
|
||||||
|
var gun = Gun('http://localhost:8080/gun');
|
||||||
|
</script>
|
@ -3,8 +3,8 @@ var config = {
|
|||||||
port: 8080,
|
port: 8080,
|
||||||
servers: 2,
|
servers: 2,
|
||||||
browsers: 2,
|
browsers: 2,
|
||||||
each: 12000,
|
each: 10000,
|
||||||
burst: 1000,
|
burst: 100,
|
||||||
wait: 1,
|
wait: 1,
|
||||||
route: {
|
route: {
|
||||||
'/': __dirname + '/index.html',
|
'/': __dirname + '/index.html',
|
||||||
|
@ -88,7 +88,7 @@ describe("Load test "+ config.browsers +" browser(s) across "+ config.servers +"
|
|||||||
// Launch the server and start gun!
|
// Launch the server and start gun!
|
||||||
var Gun = require('gun');
|
var Gun = require('gun');
|
||||||
// Attach the server to gun.
|
// Attach the server to gun.
|
||||||
var gun = Gun({file: env.i+'data', web: server});
|
var gun = Gun({file: env.i+'data', web: server, localStorage: false});
|
||||||
server.listen(env.config.port + env.i, function(){
|
server.listen(env.config.port + env.i, function(){
|
||||||
// This server peer is now done with the test!
|
// This server peer is now done with the test!
|
||||||
// It has successfully launched.
|
// It has successfully launched.
|
||||||
|
@ -1,34 +1,21 @@
|
|||||||
;(function(){
|
;(function(){
|
||||||
window.SPAM = function(cb, opt){
|
window.SPAM = function(cb, opt){
|
||||||
opt = Gun.num.is(opt)? {each: opt} : opt || {};
|
opt = Gun.num.is(opt)? {each: opt} : opt || {};
|
||||||
|
opt.wait = opt.wait || 1;
|
||||||
setInterval(burst, opt.wait);
|
setInterval(burst, opt.wait);
|
||||||
|
|
||||||
var n = Gun.time.is(), i = 0, c = 0, b = opt.burst || 1, l = opt.each || 100;
|
var n = Gun.time.is(), i = 0, c = 0, b = opt.burst || 10, l = opt.each || 100;
|
||||||
var raw = "AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA AAAAA "
|
var r = Gun.text.random, raw;
|
||||||
|
|
||||||
function save(i){
|
function save(i){
|
||||||
if(!window.SPAM){ return }
|
if(!window.SPAM){ return }
|
||||||
if(i > l){
|
if(i > l){
|
||||||
return clearTimeout(t);
|
return clearTimeout(t);
|
||||||
}
|
}
|
||||||
cb(i, raw + i);
|
cb(i, i + raw + i);
|
||||||
return;
|
|
||||||
var d;
|
|
||||||
var ref = window.gun.get('asdf'+i);
|
|
||||||
ref.put({hello: raw + i}, function(ack){
|
|
||||||
if(d){ return } d = true;
|
|
||||||
c++;
|
|
||||||
!(i % b) && console.log(i+'/'+l);//, '@'+Math.floor(b/((-n + (n = Gun.time.is()))/1000))+'/sec');
|
|
||||||
//localStorage.clear();
|
|
||||||
ref.off();
|
|
||||||
//console.log("gl:", Object.keys(window.gun._.graph).length);
|
|
||||||
if(c < l){ return }
|
|
||||||
setTimeout(function(){
|
|
||||||
test.done();
|
|
||||||
}, 1000);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
function burst(){
|
function burst(){
|
||||||
|
raw = r(1000000);
|
||||||
for(var j = 0; j <= b; j++){
|
for(var j = 0; j <= b; j++){
|
||||||
save(++i);
|
save(++i);
|
||||||
}
|
}
|
||||||
@ -37,7 +24,29 @@ var t;
|
|||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
var gun = Gun({localStorage: false, peers: 'http://localhost:8080/gun'});
|
||||||
|
var g = gun.get('test');
|
||||||
|
var room = Gun.text.random(100);
|
||||||
|
var pub = Gun.text.random(1000);
|
||||||
SPAM(function(i, v){
|
SPAM(function(i, v){
|
||||||
$("#message-input").text(v);
|
//console.log(Gun.state(), i);return;
|
||||||
$('.say').trigger('click');
|
console.log(i);
|
||||||
}, 10000);
|
var ref = g.set({
|
||||||
|
a: v,
|
||||||
|
b: i,
|
||||||
|
c: room,
|
||||||
|
d: pub
|
||||||
|
}, function(ack){
|
||||||
|
ref.off();
|
||||||
|
});
|
||||||
|
}, 99999999999999);
|
||||||
|
|
||||||
|
/*
|
||||||
|
;(function(){
|
||||||
|
$("#say").on('submit', function(){
|
||||||
|
setTimeout(function(){
|
||||||
|
$("#say").find('input').first().val(Gun.text.random(1000));
|
||||||
|
},1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
*/
|
Loading…
x
Reference in New Issue
Block a user