Merge pull request #394 from amark/0.8

0.8
This commit is contained in:
Mark Nadal 2017-07-06 19:17:20 -06:00 committed by GitHub
commit 7925fc0982
16 changed files with 1045 additions and 1230 deletions

868
gun.js

File diff suppressed because it is too large Load Diff

View File

@ -2,151 +2,76 @@
// modified by Mark to be part of core for convenience
// twas not designed for production use
// only simple local development.
var Gun = require('../gun'),
fs = require('fs');
fs = require('fs');
var files = {};
Gun.on('opt', function(ctx){
this.to.next(ctx);
var opt = ctx.opt;
if(ctx.once){ return }
opt.file = String(opt.file || 'data.json');
var graph = ctx.graph, acks = {}, count = 0, to;
var disk = Gun.obj.ify((fs.existsSync || require('path').existsSync)(opt.file)?
fs.readFileSync(opt.file).toString()
: null) || {};
Gun.on('put', function(at){
//console.log("file write", Gun.obj.copy(at), at.gun.back(-1)._.opt.file);
this.to.next(at);
var root = at.gun.back(-1);
var f = at.gun.back('opt._file')
if(!f.use){ return }
var graph = at.put, opt = at.opt || {};
var Graph = f.gun._.graph;
var dg = f.disk.graph;
Gun.graph.is(graph, null, function(val, key, node, soul){
dg[soul] = Gun.state.to(node, key, dg[soul]);
});
f.count = (f.count || 0) + 1;
if(!at['@']){ // don't ack other acks!
(f.check || (f.check = {}))[at['#']] = root;
}
function save(){
clearTimeout(f.wait);
var ack = f.check;
f.count = 0;
f.wait = false;
f.check = {};
graph = JSON.stringify(f.disk, null, 2);
// TODO: Allow for a `fs.writeFile` compatible module, that is more reliable/safe, to be passed in through the options.
fs.writeFile(opt.file || f.file, graph, function(err){
Gun.obj.map(ack, function(root, id){
root.on('in', {
'@': id,
ok: err? undefined : 1,
err: err || undefined
});
});
});
}
if(f.count >= 10000){ // goal is to do 10K inserts/second.
return save();
}
if(f.wait){ return }
clearTimeout(f.wait);
f.wait = setTimeout(save, 1000);
});
Gun.on('get', function(at){
var fileOpt = at.gun.back('opt._file');
//if(at.cap && fileOpt.use){ at.cap-- }
this.to.next(at);
if(!fileOpt.use){ return }
var opt = at.opt || {};
var soul = at.get['#'];
if(!soul){ return }
if(Gun.obj.is(soul)){ return match(fileOpt, at) }
var node = fileOpt.disk.graph[soul];
if(Gun.obj.has(at.get, '.')){
node = field(node, at.get['.']);
}
fileOpt.gun.on('in', {
put: Gun.graph.node(node),
'@': at['#'],
how: 'file'
})
});
function field(node, field){
if(!node){ return }
node = Gun.obj.copy(node);
var tmp = node[field];
node = {_: node._};
if(undefined !== tmp){
node[field] = tmp;
}
tmp = node._;
if(tmp['>']){
tmp['>'] = Gun.obj.put({}, field, tmp['>'][field]);
}
return node;
}
Gun.on('opt', function(at){
this.to.next(at);
var gun = at.gun, opt = at.opt;
if ((opt.file === false) || (opt.s3 && opt.s3.key)) {
opt._file = {};
opt._file.use = false;
return; // don't use this plugin if S3 is being used.
}
Gun.log.once(
'file-warning',
'WARNING! This `file.js` module for gun is ' +
'intended for local development testing only!'
);
opt._file = {};
opt._file.use = true;
opt._file.file = String(opt.file || opt._file.file || 'data.json');
opt._file.raw = opt._file.raw || ((fs.existsSync || require('path').existsSync)(opt._file.file) ? fs.readFileSync(opt._file.file).toString() : null);
opt._file.disk = files[opt._file.file] = files[opt._file.file] || opt._file.disk || Gun.obj.ify(opt._file.raw || {graph: {}});
opt._file.disk.graph = opt._file.disk.graph || {};
opt._file.gun = gun;
});
function match(fileOpt, at){
var rgx = at.get['#'];
var graph = fileOpt.disk.graph, put;
Gun.obj.map(graph, function(node, soul){
if(!Gun.text.match(soul, rgx)){ return }
if(Gun.obj.has(at.get, '.')){
node = field(node, at.get['.']);
ctx.on('put', function(at){
this.to.next(at);
Gun.graph.is(at.put, null, map);
if(!at['@']){ acks[at['#']] = true; } // only ack non-acks.
count += 1;
if(count >= (opt.batch || 10000)){
return flush();
}
var put = {};
(put = put || {})[soul] = node;
fileOpt.gun.on('in', {
put: put,
'@': at['#'],
how: 'file'
})
if(to){ return }
to = setTimeout(flush, opt.wait || 1);
});
}
(function test(){
return;
try{
var graph = Gun.obj.ify(fs.readFileSync('data.json').toString()).graph;
var read;
Gun().get('test/5').path('index').val(function(data){
read = data;
});
console.log((5 === read)? "READ SUCCESS" : "FAIL");
}catch(e){
var gun = Gun(), i = 100, expect = 0;
while(--i){
expect += i;
gun.get('test/' + i).put({ index: i, test: true });
ctx.on('get', function(at){
this.to.next(at);
var gun = at.gun, lex = at.get, soul, data, opt, u;
//setTimeout(function(){
if(!lex || !(soul = lex[Gun._.soul])){ return }
//if(0 >= at.cap){ return }
var field = lex['.'];
data = disk[soul] || u;
if(data && field){
data = Gun.state.to(data, field);
}
setTimeout(function(){
var graph = Gun.obj.ify(fs.readFileSync('data.json').toString()).graph;
var count = 0;
Gun.obj.map(graph, function(node){
count += node.index;
gun.on('in', {'@': at['#'], put: Gun.graph.node(data)});
//},11);
});
var map = function(val, key, node, soul){
disk[soul] = Gun.state.to(node, key, disk[soul]);
}
var wait;
var flush = function(){
if(wait){ return }
clearTimeout(to);
to = false;
var ack = acks;
acks = {};
fs.writeFile(opt.file, JSON.stringify(disk), function(err, ok){
wait = false;
var tmp = count;
count = 0;
Gun.obj.map(ack, function(yes, id){
ctx.on('in', {
'@': id,
err: err,
ok: 1
});
});
console.log((expect && expect === count)? "WRITE SUCCESS! - RUN AGAIN" : "FAIL!");
},100);
};
}());
if(1 < tmp){ flush() }
});
}
});

17
lib/not.js Normal file
View File

@ -0,0 +1,17 @@
if(typeof window !== "undefined"){
var Gun = window.Gun;
} else {
var Gun = require('gun/gun');
}
var u;
Gun.chain.not = function(cb, opt, t){
return this.get(ought, {not: cb});
}
function ought(at, ev){ ev.off();
if(at.err || (u !== at.put)){ return }
if(!this.not){ return }
this.not.call(at.gun, at.get, function(){ console.log("Please report this bug on https://gitter.im/amark/gun and in the issues."); need.to.implement; });
}

40
lib/path.js Normal file
View File

@ -0,0 +1,40 @@
if(typeof window !== "undefined"){
var Gun = window.Gun;
} else {
var Gun = require('gun/gun');
}
Gun.chain.path = function(field, cb, opt){
var back = this, gun = back, tmp;
opt = opt || {}; opt.path = true;
if(gun === gun._.root){if(cb){cb({err: Gun.log("Can't do that on root instance.")})}return gun}
if(typeof field === 'string'){
tmp = field.split(opt.split || '.');
if(1 === tmp.length){
gun = back.get(field, cb, opt);
gun._.opt = opt;
return gun;
}
field = tmp;
}
if(field instanceof Array){
if(field.length > 1){
gun = back;
var i = 0, l = field.length;
for(i; i < l; i++){
gun = gun.get(field[i], (i+1 === l)? cb : null, opt);
}
//gun.back = back; // TODO: API change!
} else {
gun = back.get(field[0], cb, opt);
}
gun._.opt = opt;
return gun;
}
if(!field && 0 != field){
return back;
}
gun = back.get(''+field, cb, opt);
gun._.opt = opt;
return gun;
}

196
lib/radisk.js Normal file
View File

@ -0,0 +1,196 @@
var fs = require('fs');
var Gun = require('../gun');
var Radix = require('./radix');
function Radisk(opt){
/*
Any and all storage adapters should...
1. If not busy, write to disk immediately.
2. If busy, batch to disk. (Improves performance, reduces potential disk corruption)
3. If a batch exceeds a certain number of writes, force atomic batch to disk. (This caps total performance, but reduces potential loss)
*/
var radisk = function(key, val, cb){
if(val instanceof Function){
cb = val;
val = radisk.batch(key);
if(u !== val){
return cb(null, val);
}
if(radisk.was){
val = radisk.was(key);
if(u !== val){
return cb(null, val);
}
}
console.log("READ FROM DISK");
return cb(null, val);
}
radisk.batch(key, val);
if(cb){ radisk.batch.acks.push(cb) }
if(!count++){ return thrash() } // (1)
if(opt.batch <= count){ return thrash() } // (3)
clearTimeout(to); // (2)
to = setTimeout(thrash, opt.wait);
};
radisk.batch = Radix();
radisk.batch.acks = [];
var count = 0, wait, to, u;
opt = opt || {};
opt.file = String(opt.file || 'radata');
opt.size = opt.size || (1024 * 1024 * 10); // 10MB
opt.batch = opt.batch || 10 * 1000;
opt.wait = opt.wait || 1;
opt.nest = opt.nest || ' ';
console.log("Warning: Radix storage engine has not been tested with all types of values and keys yet.");
if(!fs.existsSync(opt.file)){ fs.mkdirSync(opt.file) }
var thrash = function(){
if(wait){ return }
clearTimeout(to);
wait = true;
var was = radisk.was = radisk.batch;
radisk.batch = null;
radisk.batch = Radix();
radisk.batch.acks = [];
chunk(radisk.was, function(err, ok){
radisk.was = null;
wait = false;
var tmp = count;
count = 0;
Gun.obj.map(was.acks, function(cb){cb(err, ok)});
if(1 < tmp){ thrash() }
});
}
/*
1. Find the first radix item in memory.
2. Use that as the starting index in the directory of files.
3. Find the first file that is lexically larger than it,
4. Read the previous file to that into memory
5. Scan through the in memory radix for all values lexically less than the limit.
6. Merge and write all of those to the in-memory file and back to disk.
7. If file to large, split. More details needed here.
*/
function chunk(radix, cb){
var step = {
check: function(tree, key){
if(key < step.start){ return }
step.start = key;
fs.readdir(opt.file, step.match);
return true;
},
match: function(err, dir){
step.dir = dir;
if(!dir.length){
step.file = '0';
return step.merge(null, Radix());
}
Gun.obj.map(dir, step.lex);
read(step.file, step.merge);
},
lex: function(file){
if(file > step.start){
return step.end = file;
}
step.file = file;
},
merge: function(err, disk){
if(err){ return console.log("ERROR!!!", err) }
step.disk = disk;
Radix.map(radix, step.add);
write(step.file, step.disk, step.done);
},
add: function(val, key){
if(key < step.start){ return }
if(step.end && step.end < key){ return step.next = key; }
step.disk(key, val);
},
done: function(err){
if(err){ console.log("ERROR!!!", err) }
if(!step.next){
return cb(err);
}
step.start = step.next;
step.end = step.next = step.file = u;
Radix.map(radix, step.check);
}
}
Radix.map(radix, step.check);
}
var write = function(file, radix, cb){
var step = {
rest: "",
count: 0,
file: file,
each: function(val, key, k, pre){
step.count++;
if(opt.size < step.rest.length){
step.rest = "";
step.limit = Math.ceil(step.count/2);
step.count = 0;
step.sub = Radix();
Radix.map(radix, step.slice);
return true;
}
var i = pre.length;
while(i--){ step.rest += opt.nest };
step.rest += k + (u === val? '' : '=' + val) + '\n';
},
dump: function(){
var rest = step.rest;
step.rest = "";
fs.writeFile(opt.file +'/'+ file, rest, cb);
},
slice: function(val, key){
if(key < step.file){ return }
if(step.limit < (++step.count)){
var name = step.file;
step.file = key;
step.count = 0;
write(name, step.sub, step.next);
return true;
}
step.sub(key, val);
},
next: function(err){
if(err){ console.log("ERR!!!!") }
step.sub = Radix();
if(!Radix.map(radix, step.slice)){
write(step.file, step.sub, cb);
}
}
};
if(!Radix.map(radix, step.each, true)){ step.dump() }
}
var read = function(file, cb){
var step = {
nest: 0,
rad: Radix(),
data: function(err, data){
if(err){ return console.log("ERROR READING FILE!", err) }
step.pre = [];
Gun.obj.map(data.toString().split('\n'), step.split); // TODO: Escape!
cb(null, step.rad);
},
split: function(line){ var LINE = line;
var nest = -1; while(opt.nest === line[++nest]){};
if(nest){ line = line.slice(nest) }
if(nest <= step.nest){ step.pre = step.pre.slice(0, nest - step.nest - 1) }
line = line.split('='); step.pre.push(line[0]);
if(1 < line.length){ step.rad(step.pre.join(''), line[1]) }
step.nest = nest;
}
}
fs.readFile(opt.file +'/'+ file, step.data);
}
radisk.read = read;
return radisk;
}
module.exports = Radisk;

View File

@ -1,13 +1,10 @@
var fs = require('fs');
var Gun = require('gun');
var Gun = require('../gun');
var gbm = Gun.obj.map, no = {}, u;
function Radix(){
var radix = {};
var tree = radix._ = {};
var gbm = Gun.obj.map;
radix.add = function(key, val, t){
t = t || tree;
var i = 0, l = key.length-1, k = key[i], at;
var radix = function(key, val, t){
t = t || radix._ || (radix._ = {});
var i = 0, l = key.length-1, k = key[i], at, tmp;
while(!(at = t[k]) && i < l){
k += key[++i];
}
@ -18,6 +15,7 @@ function Radix(){
kk += s[ii++];
}
if(kk){
if(u === val){ return (tmp || (tmp = {}))[s.slice(ii)] = r; }
var _ = {};
_[s.slice(ii)] = r;
_[key.slice(ii)] = {$: val};
@ -26,41 +24,42 @@ function Radix(){
return true;
}
})){
if(u === val){ return; }
(t[k] || (t[k] = {})).$ = val;
} else
if(u === val){
return tmp;
}
} else
if(i == l){
if(u === val){ return (u === (tmp = at.$))? at._ : tmp }
at.$ = val;
} else {
return radix.add(key.slice(++i), val, at._);
return radix(key.slice(++i), val, at._ || (at._ = {}));
}
}
return radix;
}
(function(){
var radix = Radix();
radix.add('user/marknadal', 'asdf');
radix.add('user/ambercazzell', 'dafs');
radix.add('user/taitforrest', 'sadf');
radix.add('user/taitveronika', 'fdsa');
radix.add('user/marknadal', 'foo');
console.log("__________________");
console.log(radix._);
fs.writeFileSync('radix-data.json', JSON.stringify(radix._, null, 2));
}());
(function(){return;
var radix = Radix();
var gtr = Gun.text.random;
var c = 0, l = 10;
function bench(){
if(c > 1000){ return clearInterval(it), console.log(radix._, Object.keys(radix._).length), fs.writeFileSync('radix-data.json', JSON.stringify(radix._, null, 2)); }
for(var i = 0; i < l; i++){
radix.add(gtr(7), c++);
};
;(function(){
Radix.map = function map(radix, cb, opt, pre){ pre = pre || [];
var _ = radix._ || radix, keys = Object.keys(_).sort(), i = 0, l = keys.length;
for(;i < l; i++){ var key = keys[i], tree = _[key], tmp;
if(u !== (tmp = tree.$)){
tmp = cb(tmp, pre.join('') + key, key, pre);
if(u !== tmp){ return tmp }
} else
if(opt){
cb(u, pre.join(''), key, pre);
}
if(tmp = tree._){
pre.push(key);
tmp = map(tmp, cb, opt, pre);
if(u !== tmp){ return tmp }
pre.pop();
}
}
//if(c % 1000 === 0){ console.log(radix._) }
}
var it = setInterval(bench, 1);
}());
};
Object.keys = Object.keys || function(o){ return gbm(o, function(v,k,t){t(k)}) }
}());
module.exports = Radix;

View File

@ -1,104 +0,0 @@
function radix(r){
r = r || {};
var u, n = null, c = 0;
function get(p){
var v = match(p, r);
return v;
}
function match(path, tree, v){
if(!Gun.obj.map(tree, function(val, key){
if(key[0] !== path[0]){ return }
var i = 1;
while(key[i] === path[i] && path[i]){ i++ }
if(key = key.slice(i)){ // recurse
console.log("match", key, i)
v = {sub: tree, pre: path.slice(0, i), val: val, post: key, path: path.slice(i) };
} else { // replace
console.log("matching", path, key, i);
v = match(path.slice(i), val);
}
return true;
})){ console.log("matched", tree, path); v = {sub: tree, path: path} } // insert
return v;
}
function rebalance(ctx, val){
console.log("rebalance", ctx, val);
if(!ctx.post){ return ctx.sub[ctx.path] = val }
ctx.sub[ctx.pre] = ctx.sub[ctx.pre] || (ctx.post? {} : ctx.val || {});
ctx.sub[ctx.pre][ctx.path] = val;
if(ctx.post){
ctx.sub[ctx.pre][ctx.post] = ctx.val;
delete ctx.sub[ctx.pre + ctx.post];
}
}
function set(p, val){
rebalance(match(p, r), val);
console.log('-------------------------');
return r;
}
return function(p, val){
return (1 < arguments.length)? set(p, val) : get(p || '');
}
} // IT WORKS!!!!!!
var rad = radix({});
rad('user/marknadal', {'#': 'asdf'});
rad('user/ambercazzell', {'#': 'dafs'});
rad('user/taitforrest', {'#': 'sadf'});
rad('user/taitveronika', {'#': 'fdsa'});
rad('user/marknadal', {'#': 'foo'});
/*
function radix(r){
var u, n = null, c = 0;
r = r || {};
function get(){
}
function match(p, l, cb){
cb = cb || function(){};
console.log("LETS DO THIS", p, l);
if(!Gun.obj.map(l, function(v, k){
if(k[0] === p[0]){
var i = 1;
while(k[i] === p[i] && p[i]){ i++ }
k = k.slice(i);
if(k){
cb(p.slice(0, i), v, k, l, p.slice(i));
} else {
match(p.slice(i), v, cb);
}
return 1;
}
})){ cb(p, l, null, l) }
}
function set(p, val){
match(p, r, function(pre, data, f, rr, pp){
if(f === null){
rr[pre] = val;
return;
}
console.log("Match?", c, pre, data, f);
rr[pre] = r[pre] || (f? {} : data || {});
rr[pre][pp] = val;
if(f){
rr[pre][f] = data;
delete rr[pre + f];
}
});
return r;
}
return function(p, val){
return (1 < arguments.length)? set(p, val) : get(p || '');
}
} // IT WORKS!!!!!!
var rad = radix({});
rad('user/marknadal', {'#': 'asdf'});
//rad('user/ambercazzell', {'#': 'dafs'});
//rad('user/taitforrest', {'#': 'sadf'});
//rad('user/taitveronika', {'#': 'fdsa'});
*/

View File

@ -4,7 +4,7 @@
require('../nts');
require('./s3');
try{require('./ws');}catch(e){require('./wsp/server');}
require('./verify');
require('./verify');
require('./file');
module.exports = Gun;
}());

View File

@ -6,116 +6,106 @@ var url = require('url');
console.log("Experimental high performance uWS server is being used.");
Gun.on('opt', function mount(at){
this.to.next(at);
if(at.once){ return }
if(!at.opt.web){ return }
var opt = at.opt.uws || at.opt.ws || (at.opt.uws = {});
var cat = (at.gun.back(-1)._);
Gun.on('opt', function mount(ctx){
this.to.next(ctx);
var opt = ctx.opt;
if(ctx.once){ return }
if(!opt.web){ return }
var ws = opt.uws || opt.ws || (opt.uws = {}), batch;
opt.server = opt.server || at.opt.web;
opt.path = opt.path || at.opt.path || '/gun';
ws.server = ws.server || opt.web;
ws.path = ws.path || '/gun';
opt.web = new WebSocket.Server(opt);
var peers = cat.opt.peers;
ws.web = new WebSocket.Server(ws);
opt.web.on('connection', function(ws){
ws.upgradeReq = ws.upgradeReq || {};
ws.url = url.parse(ws.upgradeReq.url||'', true);
ws.id = ws.id || Gun.text.random(6);
peers[ws.id] = {wire: ws};
ws.on('message', function(msg){
ws.web.on('connection', function(peer){
peer.upgradeReq = peer.upgradeReq || {};
peer.url = url.parse(peer.upgradeReq.url||'', true);
peer.id = peer.id || Gun.text.random(6);
opt.peers[peer.id] = {wire: peer};
peer.on('message', function(msg){
//console.log("MESSAGE", msg);
receive(msg, ws, cat);
receive(msg, peer, ctx); // diff: peer is wire.
});
ws.on('close', function(){
Gun.obj.del(peers, ws.id);
peer.on('close', function(){
Gun.obj.del(opt.peers, peer.id);
});
});
});
});
var message;
Gun.on('out', function(at){
this.to.next(at);
var cat = at.gun._.root._;
message = JSON.stringify(at);
if(cat.udrain){
cat.udrain.push(message);
return;
}
cat.udrain = [];
setTimeout(function(){
if(!cat.udrain){ return }
//if(count += cat.udrain.length){ console.log("msg out:", count) }
var tmp = cat.udrain;
cat.udrain = null;
message = JSON.stringify(tmp);
Gun.obj.map(cat.opt.peers, send, cat);
},1);
Gun.obj.map(cat.opt.peers, send, cat);
});
var count = 0;
function receive(msg, wire, cat){
if(!cat){ return }
try{msg = JSON.parse(msg);
}catch(e){}
if(msg instanceof Array){
var i = 0, m; while(m = msg[i++]){
receive(m, wire, cat);
ctx.on('out', function(at){
this.to.next(at);
batch = JSON.stringify(at);
if(ws.drain){
ws.drain.push(batch);
return;
}
return;
}
//if(++count){ console.log("msg in:", count) }
//msg.url = wire.url;
cat.gun.on('in', msg.body || msg);
}
// EVERY message taken care of. The "extra" ones are from in-memory not having "asked" for it yet - which we won't want it to do for foreign requests. Likewise, lots of chattyness because the put/ack replies happen before the `get` syncs so everybody now has it in-memory already to reply with.
function send(peer){
var msg = message, cat = this;
var wire = peer.wire || open(peer, cat);
if(!wire){ return }
if(wire.readyState === wire.OPEN){
wire.send(msg);
return;
}
(peer.queue = peer.queue || []).push(msg);
}
function open(peer, as){
if(!peer || !peer.url){ return }
var url = peer.url.replace('http', 'ws');
var wire = peer.wire = new WebSocket(url);
wire.on('close', function(){
reconnect(peer, as);
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, ctx);
}, opt.wait || 1);
Gun.obj.map(opt.peers, send, ctx);
});
wire.on('error', function(error){
if(!error){ return }
if(error.code === 'ECONNREFUSED'){
// EVERY message taken care of. The "extra" ones are from in-memory not having "asked" for it yet - which we won't want it to do for foreign requests. Likewise, lots of chattyness because the put/ack replies happen before the `get` syncs so everybody now has it in-memory already to reply with.
function send(peer){
var ctx = this, msg = batch;
var wire = peer.wire || open(peer, ctx);
if(!wire){ return }
if(wire.readyState === wire.OPEN){
wire.send(msg);
return;
}
(peer.queue = peer.queue || []).push(msg);
}
function receive(msg, wire, ctx){
if(!ctx){ return }
try{msg = JSON.parse(msg.data || msg);
}catch(e){}
if(msg instanceof Array){
var i = 0, m;
while(m = msg[i++]){
receive(m, wire, ctx); // wire not peer!
}
return;
}
ctx.on('in', msg);
}
function open(peer, as){
if(!peer || !peer.url){ return }
var url = peer.url.replace('http', 'ws');
var wire = peer.wire = new WebSocket(url);
wire.on('close', function(){
reconnect(peer, as);
}
});
wire.on('open', function(){
var queue = peer.queue;
peer.queue = [];
Gun.obj.map(queue, function(msg){
message = msg;
send.call(as, peer);
});
});
wire.on('message', function(msg){
receive(msg, wire, as);
});
return wire;
}
wire.on('error', function(error){
if(!error){ return }
if(error.code === 'ECONNREFUSED'){
reconnect(peer, as); // placement?
}
});
wire.on('open', function(){
var queue = peer.queue;
peer.queue = [];
Gun.obj.map(queue, function(msg){
batch = msg;
send.call(as, peer);
});
});
wire.on('message', function(msg){
receive(msg, wire, as); // diff: wire not peer!
});
return wire;
}
function reconnect(peer, as){
clearTimeout(peer.defer);
peer.defer = setTimeout(function(){
open(peer, as);
}, 2 * 1000);
}
function reconnect(peer, as){
clearTimeout(peer.defer);
peer.defer = setTimeout(function(){
open(peer, as);
}, 2 * 1000);
}
});

192
lib/ws.js
View File

@ -4,116 +4,106 @@ var WebSocket = require('ws');
var url = require('url');
Gun.on('opt', function mount(at){
this.to.next(at);
if(at.once){ return }
if(!at.opt.web){ return }
var opt = at.opt.ws || (at.opt.ws = {});
var cat = (at.gun.back(-1)._);
Gun.on('opt', function mount(ctx){
this.to.next(ctx);
var opt = ctx.opt;
if(ctx.once){ return }
if(!opt.web){ return }
var ws = opt.ws || (opt.ws = {}), batch;
opt.server = opt.server || at.opt.web;
opt.path = opt.path || at.opt.path || '/gun';
ws.server = ws.server || opt.web;
ws.path = ws.path || '/gun';
opt.web = new WebSocket.Server(opt);
var peers = cat.opt.peers;
ws.web = new WebSocket.Server(ws);
opt.web.on('connection', function(ws){
ws.upgradeReq = ws.upgradeReq || {};
ws.url = url.parse(ws.upgradeReq.url||'', true);
ws.id = ws.id || Gun.text.random(6);
peers[ws.id] = {wire: ws};
ws.on('message', function(msg){
ws.web.on('connection', function(peer){
peer.upgradeReq = peer.upgradeReq || {};
peer.url = url.parse(peer.upgradeReq.url||'', true);
peer.id = peer.id || Gun.text.random(6);
opt.peers[peer.id] = {wire: peer};
peer.on('message', function(msg){
//console.log("MESSAGE", msg);
receive(msg, ws, cat);
receive(msg, peer, ctx); // diff: peer is wire.
});
ws.on('close', function(){
Gun.obj.del(peers, ws.id);
peer.on('close', function(){
Gun.obj.del(opt.peers, peer.id);
});
});
});
});
var message;
Gun.on('out', function(at){
this.to.next(at);
var cat = at.gun._.root._;
message = JSON.stringify(at);
if(cat.udrain){
cat.udrain.push(message);
return;
}
cat.udrain = [];
setTimeout(function(){
if(!cat.udrain){ return }
//if(count += cat.udrain.length){ console.log("msg out:", count) }
var tmp = cat.udrain;
cat.udrain = null;
message = JSON.stringify(tmp);
Gun.obj.map(cat.opt.peers, send, cat);
},1);
Gun.obj.map(cat.opt.peers, send, cat);
});
var count = 0;
function receive(msg, wire, cat){
if(!cat){ return }
try{msg = JSON.parse(msg);
}catch(e){}
if(msg instanceof Array){
var i = 0, m; while(m = msg[i++]){
receive(m, wire, cat);
ctx.on('out', function(at){
this.to.next(at);
batch = JSON.stringify(at);
if(ws.drain){
ws.drain.push(batch);
return;
}
return;
}
//if(++count){ console.log("msg in:", count) }
//msg.url = wire.url;
cat.gun.on('in', msg.body || msg);
}
// EVERY message taken care of. The "extra" ones are from in-memory not having "asked" for it yet - which we won't want it to do for foreign requests. Likewise, lots of chattyness because the put/ack replies happen before the `get` syncs so everybody now has it in-memory already to reply with.
function send(peer){
var msg = message, cat = this;
var wire = peer.wire || open(peer, cat);
if(!wire){ return }
if(wire.readyState === wire.OPEN){
wire.send(msg);
return;
}
(peer.queue = peer.queue || []).push(msg);
}
function open(peer, as){
if(!peer || !peer.url){ return }
var url = peer.url.replace('http', 'ws');
var wire = peer.wire = new WebSocket(url);
wire.on('close', function(){
reconnect(peer, as);
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, ctx);
}, opt.wait || 1);
Gun.obj.map(opt.peers, send, ctx);
});
wire.on('error', function(error){
if(!error){ return }
if(error.code === 'ECONNREFUSED'){
// EVERY message taken care of. The "extra" ones are from in-memory not having "asked" for it yet - which we won't want it to do for foreign requests. Likewise, lots of chattyness because the put/ack replies happen before the `get` syncs so everybody now has it in-memory already to reply with.
function send(peer){
var ctx = this, msg = batch;
var wire = peer.wire || open(peer, ctx);
if(!wire){ return }
if(wire.readyState === wire.OPEN){
wire.send(msg);
return;
}
(peer.queue = peer.queue || []).push(msg);
}
function receive(msg, wire, ctx){
if(!ctx){ return }
try{msg = JSON.parse(msg.data || msg);
}catch(e){}
if(msg instanceof Array){
var i = 0, m;
while(m = msg[i++]){
receive(m, wire, ctx); // wire not peer!
}
return;
}
ctx.on('in', msg);
}
function open(peer, as){
if(!peer || !peer.url){ return }
var url = peer.url.replace('http', 'ws');
var wire = peer.wire = new WebSocket(url);
wire.on('close', function(){
reconnect(peer, as);
}
});
wire.on('open', function(){
var queue = peer.queue;
peer.queue = [];
Gun.obj.map(queue, function(msg){
message = msg;
send.call(as, peer);
});
});
wire.on('message', function(msg){
receive(msg, wire, as);
});
return wire;
}
wire.on('error', function(error){
if(!error){ return }
if(error.code === 'ECONNREFUSED'){
reconnect(peer, as); // placement?
}
});
wire.on('open', function(){
var queue = peer.queue;
peer.queue = [];
Gun.obj.map(queue, function(msg){
batch = msg;
send.call(as, peer);
});
});
wire.on('message', function(msg){
receive(msg, wire, as); // diff: wire not peer!
});
return wire;
}
function reconnect(peer, as){
clearTimeout(peer.defer);
peer.defer = setTimeout(function(){
open(peer, as);
}, 2 * 1000);
}
function reconnect(peer, as){
clearTimeout(peer.defer);
peer.defer = setTimeout(function(){
open(peer, as);
}, 2 * 1000);
}
});

104
lib/wsproto.js Normal file
View File

@ -0,0 +1,104 @@
;(function(){
/*
HOW TO USE:
1. On your HTML include gun and this file:
<script src="gun.js"></script>
<script src="lib/wsproto.js"></script>
2. Initiate GUN with default WebSocket turned off:
var gun = Gun({WebSocket: false});
*/
var WebSocket;
if(typeof window !== 'undefined'){
WebSocket = window.WebSocket || window.webkitWebSocket || window.mozWebSocket;
} else {
return;
}
Gun.on('opt', function(ctx){
this.to.next(ctx);
var opt = ctx.opt;
if(ctx.once){ return }
opt.wsc = opt.wsc || {protocols:[]}; // for d3x0r!
var ws = opt.ws || (opt.ws = {}); ws.who = 0;
Gun.obj.map(opt.peers, function(){ ++ws.who });
if(ctx.once){ return }
var batch;
ctx.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, ctx);
}, opt.wait || 1);
Gun.obj.map(opt.peers, send, ctx);
});
function send(peer){
var ctx = this, msg = batch;
var wire = peer.wire || open(peer, ctx);
if(!wire){ return }
if(wire.readyState === wire.OPEN){
wire.send(msg);
return;
}
(peer.queue = peer.queue || []).push(msg);
}
function receive(msg, peer, ctx){
if(!ctx || !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, ctx);
}
return;
}
if(1 == ws.who){ msg.ws = noop } // If there is only 1 client, just use noop since it doesn't matter.
ctx.on('in', msg);
}
function open(peer, as){
if(!peer || !peer.url){ return }
var url = peer.url.replace('http', 'ws');
var wire = peer.wire = new WebSocket(url, as.opt.wsc.protocols, as.opt.wsc);
wire.onclose = function(){
reconnect(peer, as);
};
wire.onerror = function(error){
reconnect(peer, as); // placement?
if(!error){ return }
if(error.code === 'ECONNREFUSED'){
//reconnect(peer, as);
}
};
wire.onopen = function(){
var queue = peer.queue;
peer.queue = [];
Gun.obj.map(queue, function(msg){
batch = msg;
send.call(as, peer);
});
}
wire.onmessage = function(msg){
receive(msg, peer, as); // diff: peer not wire!
};
return wire;
}
function reconnect(peer, as){
clearTimeout(peer.defer);
peer.defer = setTimeout(function(){
open(peer, as);
}, 2 * 1000);
}
});
var noop = function(){};
}());

View File

@ -1,6 +1,6 @@
{
"name": "gun",
"version": "0.7.9",
"version": "0.8.0",
"description": "Graph engine",
"main": "index.js",
"browser": "gun.min.js",

15
sea.js
View File

@ -27,10 +27,10 @@
var gun = Gun();
var user = gun.user();
Gun.on('auth', function(at){
gun.on('auth', function(at){
// do something once logged in.
});
Gun.on('secure', function(at){
gun.on('secure', function(at){
// enforce some rules about shared app level data
var no;
if(no){ return }
@ -116,7 +116,7 @@
// callbacks success with the user data credentials.
cb(user._);
// emit an auth event, useful for page redirects and stuff.
Gun.on('auth', user._);
root.on('auth', user._);
return;
}
// Or else we failed to log in...
@ -135,6 +135,7 @@
at.sea = {own: {}};
at.gun.on('in', security, at); // now listen to all input data, acting as a firewall.
at.gun.on('out', signature, at); // and output listeners, to encrypt outgoing data.
at.gun.on('node', every, at);
}
this.to.next(at); // make sure to call the "next" middleware adapter.
});
@ -152,7 +153,7 @@
// Here is a problem: Multiple public keys can "claim" any node's ID, so this is dangerous!
// This means we should ONLY trust our "friends" (our key ring) public keys, not any ones.
// I have not yet added that to SEA yet in this alpha release. That is coming soon, but beware in the meanwhile!
Gun.on('node', function(at){ // TODO: Warning: Need to switch to `gun.on('node')`! Do not use `Gun.on('node'` in your apps!
function every(at){
var own = (at.gun.back(-1)._).sea.own, soul = at.get, pub = own[soul] || soul.slice(4), vertex = (at.gun._).put;
Gun.node.is(at.put, function(val, key, node){ // for each property on the node.
vertex[key] = node[key] = val = SEA.read(val, pub); // verify signature and get plain value.
@ -161,7 +162,7 @@
own[key] = pub; // associate the public key with a node
}
});
})
};
// signature handles data output, it is a proxy to the security function.
function signature(at){
@ -248,12 +249,12 @@
});
if(no){ // if we got a rejection then...
if(!at || !Gun.tag.secure){ return }
Gun.on('secure', function(at){ // (below) emit a special event for the developer to handle security.
cat.on('secure', function(at){ // (below) emit a special event for the developer to handle security.
this.off();
if(!at){ return }
to.next(at); // and if they went ahead and explicitly called "next" (to us) with data, then approve.
});
Gun.on('secure', at);
cat.on('secure', at);
return; // else wise, reject.
}
//console.log("SEA put", at.put);

View File

@ -1516,7 +1516,7 @@ describe('Gun', function(){
- Proxying event across maps.
*/
var s = Gun.state.map();s.soul = 'u/m';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
alice: {
age: 26,
name: "Alice",
@ -1550,9 +1550,9 @@ describe('Gun', function(){
});
});
it('uncached synchronous map path on', function(done){
it('uncached synchronous map get on', function(done){
var s = Gun.state.map();s.soul = 'u/m/p';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
alice: {
age: 26,
name: "alice",
@ -1565,7 +1565,7 @@ describe('Gun', function(){
}
}, s)});
var check = {}, count = {};
gun.get('u/m/p').map().path('name').on(function(v,f){
gun.get('u/m/p').map().get('name').on(function(v,f){
//console.log("*****************", f, v);
check[v] = f;
count[v] = (count[v] || 0) + 1;
@ -1582,9 +1582,9 @@ describe('Gun', function(){
});
});
it('uncached synchronous map path on node', function(done){
it('uncached synchronous map get on node', function(done){
var s = Gun.state.map();s.soul = 'u/m/p/n';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
alice: {
age: 26,
name: "alice",
@ -1597,7 +1597,7 @@ describe('Gun', function(){
}
}, s)});
var check = {}, count = {};
gun.get('u/m/p/n').map().path('pet').on(function(v,f){
gun.get('u/m/p/n').map().get('pet').on(function(v,f){
//console.log("********************", f,v);
check[v.name] = v;
count[v.name] = (count[v.name] || 0) + 1;
@ -1616,10 +1616,10 @@ describe('Gun', function(){
});
});
it('uncached synchronous map path on node path', function(done){
it('uncached synchronous map get on node get', function(done){
var gun = Gun();
var s = Gun.state.map();s.soul = 'u/m/p/n/p';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
alice: {
age: 26,
name: "alice",
@ -1633,7 +1633,7 @@ describe('Gun', function(){
}, s)});
var check = {}, count = {};
//console.debug.i=1;console.log('-------------------');
gun.get('u/m/p/n/p').map().path('pet').path('name').on(function(v,f){
gun.get('u/m/p/n/p').map().get('pet').get('name').on(function(v,f){
check[v] = f;
count[v] = (count[v] || 0) + 1;
//console.log("*****************", f, v);
@ -1657,7 +1657,7 @@ describe('Gun', function(){
it('uncached synchronous map on mutate', function(done){
var s = Gun.state.map();s.soul = 'u/m/mutate';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
alice: {
age: 26,
name: "Alice",
@ -1670,7 +1670,7 @@ describe('Gun', function(){
}
}, s)});
var check = {}, count = {};
gun.get('u/m/mutate').map().path('name').get(function(at,ev){
gun.get('u/m/mutate').map().get('name').get(function(at,ev){
var e = at.err, v = at.put, f = at.get;
//console.log("****************", f,v);
check[v] = f;
@ -1686,13 +1686,13 @@ describe('Gun', function(){
}
});
setTimeout(function(){
gun.get('u/m/mutate').path('alice').put(7);
gun.get('u/m/mutate').get('alice').put(7);
}, 300);
});
it('uncached synchronous map on mutate node', function(done){
var s = Gun.state.map();s.soul = 'u/m/mutate/n';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
alice: {_:{'#':'umaliceo'},
age: 26,
name: "Alice",
@ -1705,7 +1705,7 @@ describe('Gun', function(){
}
}, s)});
var check = {}, count = {};
gun.get('u/m/mutate/n').map().path('name').get(function(at,ev){
gun.get('u/m/mutate/n').map().get('name').get(function(at,ev){
var e = at.err, v = at.put, f = at.get;
check[v] = f;
count[v] = (count[v] || 0) + 1;
@ -1725,7 +1725,7 @@ describe('Gun', function(){
});
setTimeout(function(){
//console.debug.i=1;console.log("-----------------------");
gun.get('u/m/mutate/n').path('alice').put({
gun.get('u/m/mutate/n').get('alice').put({
_:{'#':'u/m/m/n/soul'},
name: 'Alice Zzxyz'
});
@ -1740,7 +1740,7 @@ describe('Gun', function(){
it('uncached synchronous map on mutate node uncached', function(done){
var s = Gun.state.map();s.soul = 'u/m/mutate/n/u';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
alice: {_:{'#':'umaliceo1'},
age: 26,
name: "Alice",
@ -1772,7 +1772,7 @@ describe('Gun', function(){
});
setTimeout(function(){
var s = Gun.state.map();s.soul = 'u/m/m/n/u/soul';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
name: 'Alice Zzxyz'
}, s)});
//console.debug.i=1;console.log("---------------");
@ -1795,9 +1795,9 @@ describe('Gun', function(){
}, 300);
});
it('uncached synchronous map on path mutate node uncached', function(done){
it('uncached synchronous map on get mutate node uncached', function(done){
var s = Gun.state.map();s.soul = 'u/m/p/mutate/n/u';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
alice: {_:{'#':'umaliceo2'},
age: 26,
name: "Alice",
@ -1810,7 +1810,7 @@ describe('Gun', function(){
}
}, s)});
var check = {}, count = {};
gun.get('u/m/p/mutate/n/u').map().path('name').on(function(v,f){
gun.get('u/m/p/mutate/n/u').map().get('name').on(function(v,f){
check[v] = f;
count[v] = (count[v] || 0) + 1;
//console.log("*************", f,v);
@ -1830,7 +1830,7 @@ describe('Gun', function(){
});
setTimeout(function(){
var s = Gun.state.map();s.soul = 'u/m/p/m/n/u/soul';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
name: 'Alice Zzxyz', age: 34
}, s)});
gun.get('u/m/p/mutate/n/u').put({
@ -1845,9 +1845,9 @@ describe('Gun', function(){
}, 300);
});
it('uncached synchronous map on path node mutate node uncached', function(done){
it('uncached synchronous map on get node mutate node uncached', function(done){
var s = Gun.state.map();s.soul = 'u/m/p/n/mutate/n/u';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
alice: {_:{'#':'umaliceo3'},
age: 26,
name: "Alice",
@ -1860,7 +1860,7 @@ describe('Gun', function(){
}
}, s)});
var check = {}, count = {};
gun.get('u/m/p/n/mutate/n/u').map().path('pet').on(function(v,f){
gun.get('u/m/p/n/mutate/n/u').map().get('pet').on(function(v,f){
check[v.name] = f;
count[v.name] = (count[v.name] || 0) + 1;
//console.log("*****************", f,v);
@ -1878,7 +1878,7 @@ describe('Gun', function(){
});
setTimeout(function(){
var s = Gun.state.map();s.soul = 'alice/fuzz/soul';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
name: 'Alice Zzxyz', age: 34,
pet: {c:3, name: "Fuzzball"}
}, s)});
@ -1973,7 +1973,7 @@ describe('Gun', function(){
}
});
var check = {};
//gun.get('g/n/m/f/l/n').path('bob.spouse.work').on(function(v,f){ console.log("!!!!!!!!!", f, v);});return;
//gun.get('g/n/m/f/l/n').get('bob.spouse.work').on(function(v,f){ console.log("!!!!!!!!!", f, v);});return;
gun.get('g/n/m/f/l/n').map().on(function(v,f){
check[f] = v;
//console.log("*******************", f, v);
@ -1992,10 +1992,10 @@ describe('Gun', function(){
},300);
});
it("in memory get before map path", function(done){
it("in memory get before map get", function(done){
var gun = Gun();
var check = {};
gun.get('g/n/m/f/l/n/b/p').map().path('name').on(function(v,f){
gun.get('g/n/m/f/l/n/b/p').map().get('name').on(function(v,f){
check[v] = f;
//console.log("****************", f,v);
if(check.alice && check.bob && check.Alice){
@ -2039,7 +2039,7 @@ describe('Gun', function(){
},300);
});
it("in memory get after map path", function(done){
it("in memory get after map get", function(done){
var gun = Gun();
gun.put({_:{'#':'g/n/m/f/l/n/m/p'},
alice: {_:{'#':'GALICE4'},
@ -2067,7 +2067,7 @@ describe('Gun', function(){
}
});
var check = {};
gun.get('g/n/m/f/l/n/m/p').map().path('name').on(function(v,f){
gun.get('g/n/m/f/l/n/m/p').map().get('name').on(function(v,f){
check[v] = f;
//console.log("*****************", f,v);
if(check.alice && check.bob && check.Alice){
@ -2085,10 +2085,10 @@ describe('Gun', function(){
},300);
});
it("in memory get before map path path", function(done){
it("in memory get before map get get", function(done){
var gun = Gun();
var check = {};
gun.get('g/n/m/f/l/n/b/p/p/p').map().path('spouse').path('work').on(function(v,f){
gun.get('g/n/m/f/l/n/b/p/p/p').map().get('spouse').get('work').on(function(v,f){
check[v.name] = f;
if(check['GUN INC'] && check['ACME INC'] && check['ACME INC.']){
clearTimeout(done.to);
@ -2131,7 +2131,7 @@ describe('Gun', function(){
},300);
});
it("in memory get after map path path", function(done){
it("in memory get after map get get", function(done){
var gun = Gun();
gun.put({_:{'#':'g/n/m/f/l/n/b/p/p/p/a'},
alice: {
@ -2159,7 +2159,7 @@ describe('Gun', function(){
}
});
var check = {};
gun.get('g/n/m/f/l/n/b/p/p/p/a').map().path('spouse').path('work').on(function(v,f){
gun.get('g/n/m/f/l/n/b/p/p/p/a').map().get('spouse').get('work').on(function(v,f){
check[v.name] = f;
if(check['GUN INC'] && check['ACME INC'] && check['ACME INC.']){
clearTimeout(done.to);
@ -2290,10 +2290,10 @@ describe('Gun', function(){
},300);
});
it("in memory get before map map path", function(done){
it("in memory get before map map get", function(done){
var gun = Gun();
var check = {};
gun.get('g/n/m/f/l/n/b/m/m/p').map().map().path('name').on(function(v,f){
gun.get('g/n/m/f/l/n/b/m/m/p').map().map().get('name').on(function(v,f){
check[v] = f;
//console.log("***********", f,v);
if(check.alice && check.bob && check.GUN && check.ACME && check.ACMEINC){
@ -2343,7 +2343,7 @@ describe('Gun', function(){
},300);
});
it("in memory get after map map path", function(done){
it("in memory get after map map get", function(done){
var gun = Gun();
var check = {};
gun.put({_:{'#':'g/n/m/f/l/n/b/a/m/m/p'},
@ -2375,7 +2375,7 @@ describe('Gun', function(){
}
}
});
gun.get('g/n/m/f/l/n/b/a/m/m/p').map().map().path('name').on(function(v,f){
gun.get('g/n/m/f/l/n/b/a/m/m/p').map().map().get('name').on(function(v,f){
check[v] = f;
//console.log("************", f,v);
if(check.alice && check.bob && check.GUN && check.ACME && check.ACMEINC){
@ -2395,10 +2395,10 @@ describe('Gun', function(){
},300);
});
it("in memory get before map map path path", function(done){
it("in memory get before map map get get", function(done){
var gun = Gun();
var check = {};
gun.get('g/n/m/f/l/n/b/m/m/p/p').map().map().path('address').path('state').on(function(v,f){
gun.get('g/n/m/f/l/n/b/m/m/p/p').map().map().get('address').get('state').on(function(v,f){
check[v] = f;
if(check.QR && check.NY && check.CA && check.TX && check.MA){
clearTimeout(done.to);
@ -2459,7 +2459,7 @@ describe('Gun', function(){
},300);
});
it("in memory get after map map path path", function(done){
it("in memory get after map map get get", function(done){
var gun = Gun();
gun.put({_:{'#':'g/n/m/f/l/n/b/a/m/m/p/p'},
users: {
@ -2503,7 +2503,7 @@ describe('Gun', function(){
}
});
var check = {};
gun.get('g/n/m/f/l/n/b/a/m/m/p/p').map().map().path('address').path('state').on(function(v,f){
gun.get('g/n/m/f/l/n/b/a/m/m/p/p').map().map().get('address').get('state').on(function(v,f){
check[v] = f;
if(check.QR && check.NY && check.CA && check.TX && check.MA){
clearTimeout(done.to);
@ -2522,11 +2522,11 @@ describe('Gun', function(){
},300);
});
it("in memory get before map map path path path", function(done){
it("in memory get before map map get get get", function(done){
var gun = Gun();
var check = {};
gun.get('g/n/m/f/l/n/b/m/m/p/p/p').map().map().path('address').path('state')
.path('code')
gun.get('g/n/m/f/l/n/b/m/m/p/p/p').map().map().get('address').get('state')
.get('code')
.on(function(v,f){
check[v] = f;
if(check.QR && check.NY && check.CA && check.TX && check.MA){
@ -2608,7 +2608,7 @@ describe('Gun', function(){
},300);
});
it("in memory get before after map map path path path", function(done){
it("in memory get before after map map get get get", function(done){
var gun = Gun();
var check = {};
gun.put({_:{'#':'g/n/m/f/l/n/b/a/m/m/p/p/p'},
@ -2672,8 +2672,8 @@ describe('Gun', function(){
}
}
});
gun.get('g/n/m/f/l/n/b/a/m/m/p/p/p').map().map().path('address').path('state')
.path('code')
gun.get('g/n/m/f/l/n/b/a/m/m/p/p/p').map().map().get('address').get('state')
.get('code')
.on(function(v,f){
check[v] = f;
//console.log("***********", f,v);
@ -2694,10 +2694,10 @@ describe('Gun', function(){
},300);
});
it("in memory get before map map path path node", function(done){
it("in memory get before map map get get node", function(done){
var gun = Gun();
var check = {};
gun.get('g/n/m/f/l/n/b/m/m/p/p/n').map().map().path('address').path('state').on(function(v,f){
gun.get('g/n/m/f/l/n/b/m/m/p/p/n').map().map().get('address').get('state').on(function(v,f){
check[v.code] = f;
//console.log("************", f, v);
if(check.QR && check.NY && check.CA && check.TX && check.MA){
@ -2779,7 +2779,7 @@ describe('Gun', function(){
},300);
});
it("in memory get before after map map path path node", function(done){
it("in memory get before after map map get get node", function(done){
var gun = Gun();
var check = {};
gun.put({_:{'#':'g/n/m/f/l/n/b/a/m/m/p/p/n'},
@ -2843,7 +2843,7 @@ describe('Gun', function(){
}
}
});
gun.get('g/n/m/f/l/n/b/a/m/m/p/p/n').map().map().path('address').path('state').on(function(v,f){
gun.get('g/n/m/f/l/n/b/a/m/m/p/p/n').map().map().get('address').get('state').on(function(v,f){
check[v.code] = f;
//console.log("**********", f, v);
if(check.QR && check.NY && check.CA && check.TX && check.MA){
@ -2863,7 +2863,7 @@ describe('Gun', function(){
},300);
});
it("in memory get after map map path path path map", function(done){
it("in memory get after map map get get get map", function(done){
var gun = Gun();
var check = {};
gun.put({_:{'#':'g/n/m/f/l/n/b/a/m/m/p/p/p/n'},
@ -2931,7 +2931,7 @@ describe('Gun', function(){
}
}
});
gun.get('g/n/m/f/l/n/b/a/m/m/p/p/p/n').map().map().path('address').path('state').path('county').map().on(function(v,f){
gun.get('g/n/m/f/l/n/b/a/m/m/p/p/p/n').map().map().get('address').get('state').get('county').map().on(function(v,f){
check[f] = v;
//console.log("****************", f,v);
if(check.MA1 && check.MA2 && check.TX1 && check.TX2 && check.CA1 && check.CA2 && check.NY1 && check.NY2 && check.NY3){
@ -2963,8 +2963,8 @@ describe('Gun', function(){
var user = {bob: bob};
bob.pet = cat;
cat.slave = bob;
Gun.on('put', {gun: gun, put: Gun.graph.ify(user, s)});
gun.get(s.soul).path('bob').path('pet').path('slave').val(function(data){
gun.on('put', {gun: gun, put: Gun.graph.ify(user, s)});
gun.get(s.soul).get('bob').get('pet').get('slave').val(function(data){
//clearTimeout(done.to);
//setTimeout(function(){
//console.log("*****************", data);
@ -2987,9 +2987,9 @@ describe('Gun', function(){
way: 'down'
});
parent.path('sub').put(child);
parent.get('sub').put(child);
parent.path('sub').on(function(data){
parent.get('sub').on(function(data){
//console.log("sub", data);
done.sub = data;
});
@ -3017,7 +3017,7 @@ describe('Gun', function(){
});
it('map val path put', function(done){
it('map val get put', function(done){
var gun = Gun().get('chat/asdf');
@ -3038,9 +3038,9 @@ describe('Gun', function(){
});
setTimeout(function(){
gun.path('1_1').put({what: "hi"});
gun.get('1_1').put({what: "hi"});
setTimeout(function(){
gun.path('2_2').put({what: "you."});
gun.get('2_2').put({what: "you."});
},40);
},40);
});
@ -3121,9 +3121,9 @@ describe('Gun', function(){
*/
});
it('get path path set root get put', function(done){
it('get get get set root get put', function(done){
var gun = Gun().get('app');
gun.path('alias').path('mark').set(
gun.get('alias').get('mark').set(
gun.back(-1).get('pub').put({
alias: 'mark',
auth: 'encrypt', // oops
@ -3141,10 +3141,10 @@ describe('Gun', function(){
//console.log("**", at.put);
done.pub = done.pub || at.put.auth;
});
gun.path('alias').get(function(at){
gun.get('alias').get(function(at){
//console.log("***", at.put);
done.alias = done.alias || at.put.mark;
}).path('mark').get(function(at){
}).get('mark').get(function(at){
//console.log("************", at.put);return;
setTimeout(function(){
done.mark = done.mark || at.put.pub;
@ -3159,7 +3159,7 @@ describe('Gun', function(){
},100);
});
it('get put get path put reload get path then get', function(done){
it('get put get get put reload get get then get', function(done){
var gun = Gun();
gun.get('stef').put({name:'Stef'});
@ -3167,12 +3167,12 @@ describe('Gun', function(){
country: 'Netherlands',
zip:'999999'
};
gun.get('stef').path('address').put(address);
gun.get('stef').get('address').put(address);
// reload
setTimeout(function(){
var gun2 = Gun();
gun2.get('stef').path('address').val(function(data){ // Object {_: Object, country: "Netherlands", zip: "1766KP"} "adress"
gun2.get('stef').get('address').val(function(data){ // Object {_: Object, country: "Netherlands", zip: "1766KP"} "adress"
done.a = true;
expect(data.country).to.be('Netherlands');
expect(data.zip).to.be('999999');
@ -3193,20 +3193,20 @@ describe('Gun', function(){
it('get get get any parallel', function(done){
var s = Gun.state.map();s.soul = 'parallel';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
bob: {
age: 29,
name: "Bob!"
}
}, s)});
gun.get('parallel').path('bob').path('age').get(function(at, ev){
gun.get('parallel').get('bob').get('age').get(function(at, ev){
var err = at.err, data = at.put, field = at.get;
//console.log("***** age", data, at.gun._.ack);return;
expect(data).to.be(29);
expect(field).to.be('age');
done.age = true;
});
gun.get('parallel').path('bob').path('name').get(function(at, ev){
gun.get('parallel').get('bob').get('name').get(function(at, ev){
var err = at.err, data = at.put, field = at.get;
//console.log("*********** name", data, at.gun._.ack);return;
expect(data).to.be('Bob!');
@ -3220,13 +3220,13 @@ describe('Gun', function(){
it('get get get any later', function(done){
var s = Gun.state.map();s.soul = 'parallel/later';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
bob: {
gun.on('put', {gun: gun, put: Gun.graph.ify({
bob: {_:{'#':'ddfsa'},
age: 29,
name: "Bob!"
}
}, s)});
gun.get('parallel/later').path('bob').path('age').get(function(at, ev){
gun.get('parallel/later').get('bob').get('age').get(function(at, ev){
var err = at.err, data = at.put, field = at.get;
//console.log("***** age", data);
expect(data).to.be(29);
@ -3234,7 +3234,7 @@ describe('Gun', function(){
done.age = true;
});
setTimeout(function(){
gun.get('parallel/later').path('bob').path('name').get(function(at, ev){
gun.get('parallel/later').get('bob').get('name').get(function(at, ev){
var err = at.err, data = at.put, field = at.get;
//console.log("*********** name", data);
expect(data).to.be('Bob!');
@ -3248,14 +3248,14 @@ describe('Gun', function(){
});
it('get get get any not', function(done){
gun.get('parallel/not').path('bob').path('age').get(function(at, ev){
gun.get('parallel/not').get('bob').get('age').get(function(at, ev){
var err = at.err, data = at.put, field = at.get;
//console.log("***** age", data);
expect(data).to.be(undefined);
expect(field).to.be('age');
done.age = true;
});
gun.get('parallel/not').path('bob').path('name').get(function(at, ev){
gun.get('parallel/not').get('bob').get('name').get(function(at, ev){
var err = at.err, data = at.put, field = at.get;
//console.log("*********** name", data);
expect(data).to.be(undefined);
@ -3268,7 +3268,7 @@ describe('Gun', function(){
});
it('get get get any not later', function(done){
gun.get('parallel/not/later').path('bob').path('age').get(function(at, ev){
gun.get('parallel/not/later').get('bob').get('age').get(function(at, ev){
var err = at.err, data = at.put, field = at.get;
//console.log("***** age", data);
expect(data).to.be(undefined);
@ -3276,7 +3276,7 @@ describe('Gun', function(){
done.age = true;
});
setTimeout(function(){
gun.get('parallel/not/later').path('bob').path('name').get(function(at, ev){
gun.get('parallel/not/later').get('bob').get('name').get(function(at, ev){
var err = at.err, data = at.put, field = at.get;
//console.log("*********** name", field, data);
expect(data).to.be(undefined);
@ -3291,7 +3291,7 @@ describe('Gun', function(){
it('get any any', function(done){
var s = Gun.state.map();s.soul = 'full';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
hello: 'world',
goodbye: 'mars'
}, s)});
@ -3313,7 +3313,7 @@ describe('Gun', function(){
it('get any any later', function(done){
var s = Gun.state.map();s.soul = 'full/later';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
hello: 'world',
goodbye: 'mars'
}, s)});
@ -3340,19 +3340,19 @@ describe('Gun', function(){
var app = gun.get('mult/times');
app.path('alias').path('mark').set(gun.get('ASDF').put({
app.get('alias').get('mark').set(gun.get('ASDF').put({
pub: 'ASDF',
alias: 'mark',
born: 1
}));
app.path('alias').map().map().path('pub').on(function(data){
app.get('alias').map().map().get('pub').on(function(data){
done.one = data;
//console.log("pub 1!", data);
});
setTimeout(function(){
app.path('alias').map().map().path('alias').on(function(data){
app.get('alias').map().map().get('alias').on(function(data){
done.two = data;
//console.log("alias 2!", data);
expect(done.one).to.be("ASDF");
@ -3367,7 +3367,7 @@ describe('Gun', function(){
var gun = Gun();
var s = Gun.state.map();s.soul = 'mult/times/part';
Gun.on('put', {gun: gun, put: Gun.graph.ify({
gun.on('put', {gun: gun, put: Gun.graph.ify({
alias: {
mark: {
pub: {_:{'#':'PUB'},
@ -3381,12 +3381,12 @@ describe('Gun', function(){
var app = gun.get(s.soul);
app.path('alias').path('mark').map().val(function(alias){
app.get('alias').get('mark').map().val(function(alias){
done.alias = alias;
});
setTimeout(function(){
app.path('alias').map().map().path('born').on(function(data){
app.get('alias').map().map().get('born').on(function(data){
expect(data).to.be(1);
expect(done.alias.pub).to.be("asdf");
expect(done.alias.alias).to.be("mark");
@ -3445,7 +3445,7 @@ describe('Gun', function(){
});
setTimeout(function(){
list.set(gun.get('eve').put({name: 'eve', age: 30}));
gun.get('bob').path('age').put(28);
gun.get('bob').get('age').put(28);
done.last = true;
},300);
});
@ -3464,25 +3464,27 @@ describe('Gun', function(){
done();
}
});
list.path('message').put('hello world'); // outputs "message: hello world"
list.path('message').put(null); // throws Uncaught TypeError: Cannot read property '#' of null
list.get('message').put('hello world'); // outputs "message: hello world"
list.get('message').put(null); // throws Uncaught TypeError: Cannot read property '#' of null
});
it('Check multi instance message passing', function(done){
try{ require('fs').unlinkSync('bdata') }catch(e){}
try{ require('fs').unlinkSync('ddata') }catch(e){}
Gun.on('out', function(msg){
this.to.next(msg);
var onGun = msg.gun.back(-1);
if(onGun === b) {
if(d){
//console.log("b can send to d....", Gun.obj.copy(msg));
d.on("in", msg);
Gun.on('opt', function(ctx){
ctx.on('out', function(msg){
this.to.next(msg);
var onGun = msg.gun.back(-1);
if(onGun === b) {
if(d){
//console.log("b can send to d....", Gun.obj.copy(msg));
d.on("in", msg);
}
} else if(onGun === d){
//console.log("d sends to b....", Gun.obj.copy(msg));
b.on("in", msg);
}
} else if(onGun === d){
//console.log("d sends to b....", Gun.obj.copy(msg));
b.on("in", msg);
}
});
});
var b = Gun({file: "bdata"});

71
test/ptsd/radisk.js Normal file
View File

@ -0,0 +1,71 @@
var Radix = require('../../lib/radix');
var Radisk = require('../../lib/radisk');
var Gun = require('../../gun');
var fs = require('fs');
var TOTAL = 1000000;
var c = 0;
var acked = 0;
var start;
var diff;
(function(){//return;
var radix = Radisk();
var gtr = Gun()._.opt.uuid;
var l = 500000;
var last = start;
var t = Gun.time.is;
var at = c;
var toc, alldone = function(){
acked++;
if(acked < TOTAL){ return }
diff = (Gun.time.is() - start) / 1000;
clearTimeout(toc);
toc = setTimeout(CHECK,1000);
}
function bench(){
if(c >= (TOTAL)){ return clearInterval(it); }
for(var i = 0; i < l; i++){
radix(gtr(), ++c, alldone);
if(c % 50000 === 0){
var now = t();
console.log(c);//, (now - last)/1000);
at = c;
last = now;
}
}
}
start = Gun.time.is();
var it = setInterval(bench, 1);
}());
function CHECK(){
console.log(Math.floor(c / diff), 'disk writes per second');
var disk = Radisk();
var all = {};
var to;
var i = TOTAL;
/*while(--i){
all[i] = true;
}*/
var dir = fs.readdirSync('radata');
dir.forEach(function(file){
disk.read(file, function(err, rad){
Radix.map(rad, function(val, key){
all[key] = false;
clearTimeout(to);
to = setTimeout(function(){
var len = Object.keys(all).length;
console.log("how many?", len);
if(len < TOTAL){ return }
var missing = [];
var fail = Gun.obj.map(all, function(val, key){
if(val){ missing.push(key); return true }
});
//console.log(all);
console.log("DONE!", 'Verify ALL writes:', fail? '!!!FAIL!!!!' : 'YES');// '. Missing:', missing);
},1000);
})
})
})
}