IMPORTANT updates, please upgrade.

This commit is contained in:
Mark Nadal 2017-06-11 03:56:27 -07:00
parent b92a91b76a
commit d687170b90
8 changed files with 475 additions and 146 deletions

38
gun.js
View File

@ -864,28 +864,21 @@
}
function root(at){
//console.log("add to.next(at)"); // TODO: BUG!!!
var ev = this, cat = ev.as, coat;
var ev = this, cat = ev.as, coat, tmp;
if(!at.gun){ at.gun = cat.gun }
if(!at['#']){ at['#'] = Gun.text.random() } // TODO: Use what is used other places instead.
if(cat.dup.check(at['#'])){ return }
if(at['@']){
// TODO: BUG! For multi-instances, the "ack" system is globally shared, but it shouldn't be.
if(cat.ack(at['@'], at)){ return } // TODO: Consider not returning here, maybe, where this would let the "handshake" on sync occur for Holy Grail?
cat.dup.track(at['#']);
Gun.on('out', obj_to(at, {gun: cat.gun}));
return;
}
cat.dup.track(at['#']);
//if(cat.ack(at['@'], at)){ return }
//cat.ack(at['@'], at);
if(!(tmp = at['#'])){ tmp = at['#'] = Gun.text.random() } // TODO: Use what is used other places instead.
if(cat.dup.check(tmp)){ return }
cat.dup.track(tmp);
coat = obj_to(at, {gun: cat.gun});
if(at.get){
//Gun.on.GET(coat);
Gun.on('get', coat);
}
if(at.put){
//Gun.on.PUT(coat);
Gun.on('put', coat);
if(!cat.ack(at['@'], at)){
if(at.get){
//Gun.on.GET(coat);
Gun.on('get', coat);
}
if(at.put){
//Gun.on.PUT(coat);
Gun.on('put', coat);
}
}
Gun.on('out', coat);
}
@ -894,7 +887,7 @@
;(function(){
Gun.on('put', function(at){
//Gun.on.PUT = function(at){
if(!at['#']){ return this.to.next(at) } // for tests.
if(!at['#']){ return this.to.next(at) } // for tests. // TODO: REMOVE THIS!
var ev = this, ctx = {gun: at.gun, graph: at.gun._.graph, put: {}, map: {}, machine: Gun.state()};
if(!Gun.graph.is(at.put, null, verify, ctx)){ ctx.err = "Error: Invalid graph!" }
if(ctx.err){ return ctx.gun.on('in', {'@': at['#'], err: Gun.log(ctx.err) }) }
@ -917,6 +910,7 @@
if(HAM.defer){ // pick the lowest
ctx.defer = (state < (ctx.defer || Infinity))? state : ctx.defer;
}
return;
}
ctx.put[soul] = Gun.state.to(node, key, ctx.put[soul]);
(ctx.diff || (ctx.diff = {}))[soul] = Gun.state.to(node, key, ctx.diff[soul]);
@ -2016,7 +2010,7 @@
async[soul] = async[soul] || graph[soul] || node;
});
count += 1;
check[at['#']] = root;
if(!at['@']){ check[at['#']] = root; } // only ack non-acks.
function save(){
clearTimeout(wait);
var ack = check;

2
gun.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,104 +1,66 @@
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);
var fs = require('fs');
var Gun = require('gun');
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;
while(!(at = t[k]) && i < l){
k += key[++i];
}
if(!at){
if(!gbm(t, function(r, s){
var ii = 0, kk = '';
while(s[ii] == key[ii]){
kk += s[ii++];
}
if(kk){
var _ = {};
_[s.slice(ii)] = r;
_[key.slice(ii)] = {$: val};
t[kk] = {_: _};
delete t[s];
return true;
}
})){
(t[k] || (t[k] = {})).$ = 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];
} else
if(i == l){
at.$ = val;
} else {
return radix.add(key.slice(++i), val, at._);
}
}
function set(p, val){
rebalance(match(p, r), val);
console.log('-------------------------');
return r;
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++);
}
//if(c % 1000 === 0){ console.log(radix._) }
}
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'});
*/
var it = setInterval(bench, 1);
}());

104
lib/radix_.js Normal file
View File

@ -0,0 +1,104 @@
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

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

View File

@ -15,7 +15,7 @@ Gun.on('put', function(at){ var err, id, opt, root = at.gun._.root;
async[soul] = async[soul] || graph[soul] || node;
});
count += 1;
check[at['#']] = root;
if(!at['@']){ check[at['#']] = root; } // only ack non-acks.
function save(){
clearTimeout(wait);
var ack = check;

View File

@ -50,28 +50,21 @@ Gun._ = { // some reserved key words, these are not the only ones.
}
function root(at){
//console.log("add to.next(at)"); // TODO: BUG!!!
var ev = this, cat = ev.as, coat;
var ev = this, cat = ev.as, coat, tmp;
if(!at.gun){ at.gun = cat.gun }
if(!at['#']){ at['#'] = Gun.text.random() } // TODO: Use what is used other places instead.
if(cat.dup.check(at['#'])){ return }
if(at['@']){
// TODO: BUG! For multi-instances, the "ack" system is globally shared, but it shouldn't be.
if(cat.ack(at['@'], at)){ return } // TODO: Consider not returning here, maybe, where this would let the "handshake" on sync occur for Holy Grail?
cat.dup.track(at['#']);
Gun.on('out', obj_to(at, {gun: cat.gun}));
return;
}
cat.dup.track(at['#']);
//if(cat.ack(at['@'], at)){ return }
//cat.ack(at['@'], at);
if(!(tmp = at['#'])){ tmp = at['#'] = Gun.text.random() } // TODO: Use what is used other places instead.
if(cat.dup.check(tmp)){ return }
cat.dup.track(tmp);
coat = obj_to(at, {gun: cat.gun});
if(at.get){
//Gun.on.GET(coat);
Gun.on('get', coat);
}
if(at.put){
//Gun.on.PUT(coat);
Gun.on('put', coat);
if(!cat.ack(at['@'], at)){
if(at.get){
//Gun.on.GET(coat);
Gun.on('get', coat);
}
if(at.put){
//Gun.on.PUT(coat);
Gun.on('put', coat);
}
}
Gun.on('out', coat);
}
@ -80,7 +73,7 @@ Gun._ = { // some reserved key words, these are not the only ones.
;(function(){
Gun.on('put', function(at){
//Gun.on.PUT = function(at){
if(!at['#']){ return this.to.next(at) } // for tests.
if(!at['#']){ return this.to.next(at) } // for tests. // TODO: REMOVE THIS!
var ev = this, ctx = {gun: at.gun, graph: at.gun._.graph, put: {}, map: {}, machine: Gun.state()};
if(!Gun.graph.is(at.put, null, verify, ctx)){ ctx.err = "Error: Invalid graph!" }
if(ctx.err){ return ctx.gun.on('in', {'@': at['#'], err: Gun.log(ctx.err) }) }
@ -103,6 +96,7 @@ Gun._ = { // some reserved key words, these are not the only ones.
if(HAM.defer){ // pick the lowest
ctx.defer = (state < (ctx.defer || Infinity))? state : ctx.defer;
}
return;
}
ctx.put[soul] = Gun.state.to(node, key, ctx.put[soul]);
(ctx.diff || (ctx.diff = {}))[soul] = Gun.state.to(node, key, ctx.diff[soul]);

275
test/panic/holy-grail.js Normal file
View File

@ -0,0 +1,275 @@
var config = {
IP: require('ip').address(),
port: 8080,
servers: 2,
browsers: 2,
route: {
'/': __dirname + '/index.html',
'/gun.js': __dirname + '/../../gun.js',
'/jquery.js': __dirname + '/../../examples/jquery.js'
}
}
var panic = require('panic-server');
panic.server().on('request', function(req, res){
config.route[req.url] && require('fs').createReadStream(config.route[req.url]).pipe(res);
}).listen(config.port);
var clients = panic.clients;
var manager = require('panic-manager')();
manager.start({
clients: Array(config.servers).fill().map(function(u, i){
return {
type: 'node',
port: config.port + (i + 1)
}
}),
panic: 'http://' + config.IP + ':' + config.port
});
var servers = clients.filter('Node.js');
var server = servers.pluck(1);
var spawn = servers.excluding(server).pluck(1);
var browsers = clients.excluding(servers);
var alice = browsers.pluck(1);
var bob = browsers.excluding(alice).pluck(1);
var again = {};
describe("The Holy Grail Test!", function(){
//this.timeout(5 * 60 * 1000);
this.timeout(10 * 60 * 1000);
it("Servers have joined!", function(){
return servers.atLeast(config.servers);
});
it("GUN started!", function(){
return server.run(function(test){
var env = test.props;
test.async();
try{ require('fs').unlinkSync(env.i+'data') }catch(e){}
try{ require('fs').unlinkSync((env.i+1)+'data') }catch(e){}
var port = env.config.port + env.i;
var server = require('http').createServer(function(req, res){
res.end("I am "+ env.i +"!");
});
var Gun = require('gun');
var gun = Gun({file: env.i+'data', web: server});
server.listen(port, function(){
test.done();
});
}, {i: 1, config: config});
});
it(config.browsers +" browser(s) have joined!", function(){
console.log("PLEASE OPEN http://"+ config.IP +":"+ config.port +" IN "+ config.browsers +" BROWSER(S)!");
return browsers.atLeast(config.browsers);
});
it("Browsers initialized gun!", function(){
var tests = [], i = 0;
browsers.each(function(client, id){
tests.push(client.run(function(test){
localStorage.clear();
var env = test.props;
var gun = Gun('http://'+ env.config.IP + ':' + (env.config.port + 1) + '/gun');
window.ref = gun.get('holy').get('grail');
}, {i: i += 1, config: config}));
});
return Promise.all(tests);
});
it("Write initial value", function(){
return alice.run(function(test){
console.log("I AM ALICE");
ref.put("value");
setTimeout(test.async(), 2000);
});
});
it("Read initial value", function(){
return bob.run(function(test){
console.log("I AM BOB");
test.async();
ref.on(function(data){
if("value" === data){
return test.done();
}
})
})
});
it("Server has crashed and been wiped!", function(){
return server.run(function(test){
console.log(3);
var env = test.props;
try{ require('fs').unlinkSync(env.i+'data'); }catch(e){}
process.exit(0);
}, {i: 1, config: config})
});
it("Wait...", function(done){
console.log(4);
setTimeout(done, 2000);
});
it("Alice conflicted.", function(){
return alice.run(function(test){
var env = test.props;
if(window.WebSocket){
var err;
try{ new WebSocket('http://'+ env.config.IP + ':' + (env.config.port + 2) + '/gun') }catch(e){ err = e }
if(!err){
test.fail("Server did not crash.");
}
}
ref.put("Alice");
setTimeout(test.async(), 100);
}, {config: config});
});
it("Bob conflicted.", function(){
return bob.run(function(test){
var env = test.props;
if(window.WebSocket){
var err;
try{ new WebSocket('http://'+ env.config.IP + ':' + (env.config.port + 2) + '/gun') }catch(e){ err = e }
if(!err){
test.fail("Server did not crash.");
}
}
ref.put("Bob");
setTimeout(test.async(), 2000);
}, {config: config});
});
it("Alice reloading.", function(){
return alice.run(function(test){
console.log(localStorage);
location.reload();
});
});
it("Got Alice.", function(){
again.alice = browsers.excluding(new panic.ClientList([alice, bob])).pluck(1);
return again.alice.atLeast(1);
});
it("Wait for Bob...", function(done){
setTimeout(done, 1000);
});
it("Bob reloading.", function(){
return bob.run(function(test){
location.reload();
});
});
it("Got Bob.", function(){
again.bob = browsers.excluding(new panic.ClientList([alice, bob, again.alice])).pluck(1);
return again.bob.atLeast(1);
});
it("GUN spawned!", function(){
return spawn.run(function(test){
var env = test.props;
test.async();
try{ require('fs').unlinkSync(env.i+'data') }catch(e){}
var port = env.config.port + env.i;
var server = require('http').createServer(function(req, res){
res.end("I am "+ env.i +"!");
});
var Gun = require('gun');
var gun = Gun({file: env.i+'data', web: server});
server.listen(port, function(){
test.done();
});
}, {i: 2, config: config});
});
it("Browsers re-initialized gun!", function(){
var tests = [], i = 0;
new panic.ClientList([again.alice, again.bob]).each(function(client, id){
tests.push(client.run(function(test){
// NOTE: WE DO NOT CLEAR localStorage!
console.log(localStorage['gun/holy']);
var env = test.props;
var gun = Gun('http://'+ env.config.IP + ':' + (env.config.port + 2) + '/gun');
window.ref = gun.get('holy').get('grail');
}, {i: i += 1, config: config}));
});
return Promise.all(tests);
});
it("Alice conflict.", function(){
return again.alice.run(function(test){
test.async();
var c = 0;
ref.on(function(data){
console.log("======", data);
window.stay = data;
if(!c){
c++;
if("Alice" == data){
setTimeout(function(){
window.ALICE = true;
test.done();
}, 2000);
}
return;
}
});
});
});
it("Bob converged.", function(){
return again.bob.run(function(test){
test.async();
var c = 0;
ref.on(function(data){
console.log("======", data);
//return;
window.stay = data;
if("Bob" != data){
test.fail("wrong local value!");
return;
}
setTimeout(function(){
if(c){ return }
c++;
if("Bob" === data){
test.done();
}
}, 2000);
});
});
});
it("Alice converged.", function(){
return again.alice.run(function(test){
//console.log(stay);return;
if("Bob" != stay){
test.fail("wrong local value!");
}
});
});
it("All finished!", function(done){
console.log("Done! Cleaning things up...");
setTimeout(function(){
done();
},1000);
});
after("Everything shut down.", function(){
browsers.run(function(){
//location.reload();
//setTimeout(function(){
//}, 15 * 1000);
});
return servers.run(function(){
process.exit();
});
});
});