Merge pull request #518 from amark/debug

Debug
This commit is contained in:
Mark Nadal 2018-03-13 10:31:17 -07:00 committed by GitHub
commit a3a9d76d42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 616 additions and 205 deletions

324
gun.js
View File

@ -621,21 +621,25 @@
function Dup(opt){
var dup = {s:{}};
opt = opt || {max: 1000, age: 1000 * 9};//1000 * 60 * 2};
dup.check = function(id){
return dup.s[id]? dup.track(id) : false;
dup.check = function(id){ var tmp;
if(!(tmp = dup.s[id])){ return false }
if(tmp.pass){ return tmp.pass = false }
return dup.track(id);
}
dup.track = function(id){
dup.s[id] = time_is();
dup.track = function(id, pass){
var it = dup.s[id] || (dup.s[id] = {});
it.was = time_is();
if(pass){ it.pass = true }
if(!dup.to){
dup.to = setTimeout(function(){
Type.obj.map(dup.s, function(time, id){
if(opt.age > (time_is() - time)){ return }
Type.obj.map(dup.s, function(it, id){
if(opt.age > (time_is() - it.was)){ return }
Type.obj.del(dup.s, id);
});
dup.to = null;
}, opt.age);
}
return id;
return it;
}
return dup;
}
@ -685,13 +689,13 @@
return gun;
}
function root(msg){
//console.log("add to.next(at)"); // TODO: BUG!!!
var ev = this, at = ev.as, gun = at.gun, tmp;
//console.log("add to.next(at)"); // TODO: MISSING FEATURE!!!
var ev = this, at = ev.as, gun = at.gun, dup, tmp;
//if(!msg.gun){ msg.gun = at.gun }
if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) }
if(at.dup.check(tmp)){ return }
at.dup.track(tmp);
msg = obj_to(msg);//, {gun: at.gun});
if((dup = at.dup).check(tmp)){ return }
dup.track(tmp);
//msg = obj_to(msg);//, {gun: at.gun}); // can we delete this now?
if(!at.ask(msg['@'], msg)){
if(msg.get){
Gun.on.get(msg, gun);
@ -804,7 +808,7 @@
//tmp = at.ack;
root.on('in', {
'@': msg['#'],
//how: 'mem',
how: 'mem',
put: node,
gun: gun
});
@ -940,7 +944,7 @@
}*/
if(get['#'] || at.soul){
get['#'] = get['#'] || at.soul;
msg['#'] || (msg['#'] = text_rand());
msg['#'] || (msg['#'] = text_rand(9));
back = (root.gun.get(get['#'])._);
if(!(get = get['.'])){
if(obj_has(back, 'put')){
@ -1555,6 +1559,10 @@
}
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;
if(0 < at.ack && u !== data){
(cb || noop).call(gun, data, at.get);
@ -1569,7 +1577,7 @@
} 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.");
var chain = gun.chain();
chain._.val = gun.val(function(){
chain._.val = gun.once(function(){
chain._.on('in', gun._);
});
return chain;
@ -1793,105 +1801,249 @@
})(USE, './adapters/localStorage');
;USE(function(module){
var Gun = USE('./index');
var websocket;
if(typeof WebSocket !== 'undefined'){
websocket = WebSocket;
} else {
if(typeof webkitWebSocket !== 'undefined'){
websocket = webkitWebSocket;
var Type = USE('./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);
}
if(typeof mozWebSocket !== 'undefined'){
websocket = mozWebSocket;
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){}
})(USE, './adapters/mesh');
;USE(function(module){
var Gun = USE('../index');
Gun.Mesh = USE('./mesh');
Gun.on('opt', function(root){
this.to.next(root);
var opt = root.opt;
if(root.once){ return }
if(!websocket || 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;
if(false === opt.WebSocket){ return }
root.on('out', function(at){
this.to.next(at);
if(at.ws && 1 == ws.who){ return } // performance hack for reducing echoes.
batch = JSON.stringify(at);
if(ws.drain){
ws.drain.push(batch);
return;
}
ws.drain = [];
setTimeout(function(){
if(!ws.drain){ return }
var tmp = ws.drain;
ws.drain = null;
if(!tmp.length){ return }
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){
var env;
if(typeof window !== "undefined"){ env = window }
if(typeof global !== "undefined"){ env = global }
env = env || {};
var websocket = opt.WebSocket || env.WebSocket || env.webkitWebSocket || env.mozWebSocket;
if(!websocket){ return }
opt.WebSocket = websocket;
var mesh = opt.mesh = opt.mesh || Gun.Mesh(root);
root.on('out', mesh.out);
opt.wire = opt.wire || open;
function open(peer){
if(!peer || !peer.url){ return }
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(){
root.on('bye', peer);
reconnect(peer, as);
reconnect(peer);
};
wire.onerror = function(error){
reconnect(peer, as); // placement?
reconnect(peer); // placement?
if(!error){ return }
if(error.code === 'ECONNREFUSED'){
//reconnect(peer, as);
}
};
wire.onopen = function(){
root.on('hi', peer);
var queue = peer.queue;
peer.queue = [];
Gun.obj.map(queue, function(msg){
batch = msg;
send.call(as, peer);
});
mesh.hi(peer);
}
wire.onmessage = function(msg){
receive(msg, peer, as); // diff: peer not wire!
if(!msg){ return }
mesh.hear(msg.data || msg, peer);
};
return wire;
}
function reconnect(peer, as){
function reconnect(peer){
clearTimeout(peer.defer);
peer.defer = setTimeout(function(){
open(peer, as);
open(peer);
}, 2 * 1000);
}
});

2
gun.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -2,6 +2,7 @@
if('debug' !== process.env.GUN_ENV){ return }
console.log("start :)");
global.DEBUG = 1;
setInterval(function(){
var mem = process.memoryUsage();
var used = mem.heapUsed / 1024 / 1024;

View File

@ -4,7 +4,8 @@
require('../nts');
require('./store');
require('./rs3');
try{require('./ws');}catch(e){require('./wsp/server');}
//try{require('./ws');}catch(e){require('./wsp/server');}
require('./wire');
require('./verify');
require('./file');
require('./bye');

View File

@ -16,11 +16,11 @@ Gun.on('opt', function(ctx){
ctx.on('put', function(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){
++acks;
if(track){ ++acks }
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){
acks--;

91
lib/wire.js Normal file
View 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);
});

View File

@ -12,6 +12,7 @@ Gun.on('opt', function mount(ctx){
opt.peers = [opt];
if(ctx.once){ return }
if(false === opt.ws){ return }
var ws = opt.ws || (opt.ws = {}), batch;
if(opt.web){

View File

@ -1,6 +1,6 @@
{
"name": "gun",
"version": "0.9.96",
"version": "0.9.97",
"description": "A realtime, decentralized, offline-first, graph data synchronization engine.",
"main": "index.js",
"browser": "gun.min.js",

191
src/adapters/mesh.js Normal file
View 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){}

View File

@ -1,103 +1,55 @@
var Gun = require('./index');
var websocket;
if(typeof WebSocket !== 'undefined'){
websocket = WebSocket;
} else {
if(typeof webkitWebSocket !== 'undefined'){
websocket = webkitWebSocket;
}
if(typeof mozWebSocket !== 'undefined'){
websocket = mozWebSocket;
}
}
var Gun = require('../index');
Gun.Mesh = require('./mesh');
Gun.on('opt', function(root){
this.to.next(root);
var opt = root.opt;
if(root.once){ return }
if(!websocket || 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;
if(false === opt.WebSocket){ return }
root.on('out', function(at){
this.to.next(at);
if(at.ws && 1 == ws.who){ return } // performance hack for reducing echoes.
batch = JSON.stringify(at);
if(ws.drain){
ws.drain.push(batch);
return;
}
ws.drain = [];
setTimeout(function(){
if(!ws.drain){ return }
var tmp = ws.drain;
ws.drain = null;
if(!tmp.length){ return }
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){
var env;
if(typeof window !== "undefined"){ env = window }
if(typeof global !== "undefined"){ env = global }
env = env || {};
var websocket = opt.WebSocket || env.WebSocket || env.webkitWebSocket || env.mozWebSocket;
if(!websocket){ return }
opt.WebSocket = websocket;
var mesh = opt.mesh = opt.mesh || Gun.Mesh(root);
root.on('out', mesh.out);
opt.wire = opt.wire || open;
function open(peer){
if(!peer || !peer.url){ return }
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(){
root.on('bye', peer);
reconnect(peer, as);
reconnect(peer);
};
wire.onerror = function(error){
reconnect(peer, as); // placement?
reconnect(peer); // placement?
if(!error){ return }
if(error.code === 'ECONNREFUSED'){
//reconnect(peer, as);
}
};
wire.onopen = function(){
root.on('hi', peer);
var queue = peer.queue;
peer.queue = [];
Gun.obj.map(queue, function(msg){
batch = msg;
send.call(as, peer);
});
mesh.hi(peer);
}
wire.onmessage = function(msg){
receive(msg, peer, as); // diff: peer not wire!
if(!msg){ return }
mesh.hear(msg.data || msg, peer);
};
return wire;
}
function reconnect(peer, as){
function reconnect(peer){
clearTimeout(peer.defer);
peer.defer = setTimeout(function(){
open(peer, as);
open(peer);
}, 2 * 1000);
}
});

View File

@ -25,7 +25,7 @@ function output(msg){
}*/
if(get['#'] || at.soul){
get['#'] = get['#'] || at.soul;
msg['#'] || (msg['#'] = text_rand());
msg['#'] || (msg['#'] = text_rand(9));
back = (root.gun.get(get['#'])._);
if(!(get = get['.'])){
if(obj_has(back, 'put')){

View File

@ -3,21 +3,25 @@ var Type = require('./type');
function Dup(opt){
var dup = {s:{}};
opt = opt || {max: 1000, age: 1000 * 9};//1000 * 60 * 2};
dup.check = function(id){
return dup.s[id]? dup.track(id) : false;
dup.check = function(id){ var tmp;
if(!(tmp = dup.s[id])){ return false }
if(tmp.pass){ return tmp.pass = false }
return dup.track(id);
}
dup.track = function(id){
dup.s[id] = time_is();
dup.track = function(id, pass){
var it = dup.s[id] || (dup.s[id] = {});
it.was = time_is();
if(pass){ it.pass = true }
if(!dup.to){
dup.to = setTimeout(function(){
Type.obj.map(dup.s, function(time, id){
if(opt.age > (time_is() - time)){ return }
Type.obj.map(dup.s, function(it, id){
if(opt.age > (time_is() - it.was)){ return }
Type.obj.del(dup.s, id);
});
dup.to = null;
}, opt.age);
}
return id;
return it;
}
return dup;
}

View File

@ -53,6 +53,10 @@ function ok(at, ev){ var opt = this;
}
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;
if(0 < at.ack && u !== data){
(cb || noop).call(gun, data, at.get);
@ -67,7 +71,7 @@ Gun.chain.val = function(cb, opt){
} 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.");
var chain = gun.chain();
chain._.val = gun.val(function(){
chain._.val = gun.once(function(){
chain._.on('in', gun._);
});
return chain;

View File

@ -40,13 +40,13 @@ Gun.dup = require('./dup');
return gun;
}
function root(msg){
//console.log("add to.next(at)"); // TODO: BUG!!!
var ev = this, at = ev.as, gun = at.gun, tmp;
//console.log("add to.next(at)"); // TODO: MISSING FEATURE!!!
var ev = this, at = ev.as, gun = at.gun, dup, tmp;
//if(!msg.gun){ msg.gun = at.gun }
if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) }
if(at.dup.check(tmp)){ return }
at.dup.track(tmp);
msg = obj_to(msg);//, {gun: at.gun});
if((dup = at.dup).check(tmp)){ return }
dup.track(tmp);
//msg = obj_to(msg);//, {gun: at.gun}); // can we delete this now?
if(!at.ask(msg['@'], msg)){
if(msg.get){
Gun.on.get(msg, gun);
@ -159,7 +159,7 @@ Gun.dup = require('./dup');
//tmp = at.ack;
root.on('in', {
'@': msg['#'],
//how: 'mem',
how: 'mem',
put: node,
gun: gun
});

5
test/gun.html Normal file
View 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>

View File

@ -3,8 +3,8 @@ var config = {
port: 8080,
servers: 2,
browsers: 2,
each: 12000,
burst: 1000,
each: 10000,
burst: 100,
wait: 1,
route: {
'/': __dirname + '/index.html',

View File

@ -88,7 +88,7 @@ describe("Load test "+ config.browsers +" browser(s) across "+ config.servers +"
// Launch the server and start gun!
var Gun = require('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(){
// This server peer is now done with the test!
// It has successfully launched.

View File

@ -1,34 +1,21 @@
;(function(){
window.SPAM = function(cb, opt){
opt = Gun.num.is(opt)? {each: opt} : opt || {};
opt.wait = opt.wait || 1;
setInterval(burst, opt.wait);
var n = Gun.time.is(), i = 0, c = 0, b = opt.burst || 1, 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 n = Gun.time.is(), i = 0, c = 0, b = opt.burst || 10, l = opt.each || 100;
var r = Gun.text.random, raw;
function save(i){
if(!window.SPAM){ return }
if(i > l){
return clearTimeout(t);
}
cb(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);
});
cb(i, i + raw + i);
}
function burst(){
raw = r(1000000);
for(var j = 0; j <= b; j++){
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){
$("#message-input").text(v);
$('.say').trigger('click');
}, 10000);
//console.log(Gun.state(), i);return;
console.log(i);
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);
});
});
*/