timegraph experiment

This commit is contained in:
Mark Nadal 2018-05-03 23:23:46 -07:00
parent a173c04a3c
commit 71ccb5d37f
7 changed files with 197 additions and 17 deletions

11
gun.js
View File

@ -361,11 +361,11 @@
var Node = USE('./node'); var Node = USE('./node');
function State(){ function State(){
var t; var t;
if(perf){ /*if(perf){
t = start + perf.now(); t = start + perf.now(); // Danger: Accuracy decays significantly over time, even if precise.
} else { } else {*/
t = time(); t = time();
} //}
if(last < t){ if(last < t){
return N = 0, last = t + State.drift; return N = 0, last = t + State.drift;
} }
@ -500,7 +500,7 @@
if(!(is = valid(v,k,n, at,env))){ return } if(!(is = valid(v,k,n, at,env))){ return }
if(!k){ if(!k){
at.node = at.node || n || {}; at.node = at.node || n || {};
if(obj_has(v, Node._)){ if(obj_has(v, Node._)){ // && Node.soul(v) ? for safety ?
at.node._ = obj_copy(v._); at.node._ = obj_copy(v._);
} }
at.node = Node.soul.ify(at.node, Val.rel.is(at.rel)); at.node = Node.soul.ify(at.node, Val.rel.is(at.rel));
@ -1386,6 +1386,7 @@
} function no(v,k){ if(v){ return true } } } function no(v,k){ if(v){ return true } }
function map(v,k,n, at){ var as = this; function map(v,k,n, at){ var as = this;
//if(Gun.is(v)){} // TODO: HANDLE!
if(k || !at.path.length){ return } if(k || !at.path.length){ return }
(as.res||iife)(function(){ (as.res||iife)(function(){
var path = at.path, ref = as.ref, opt = as.opt; var path = at.path, ref = as.ref, opt = as.opt;

2
gun.min.js vendored

File diff suppressed because one or more lines are too long

123
lib/time.js Normal file
View File

@ -0,0 +1,123 @@
;(function(){
var ify = Gun.node.ify, u;
Gun.chain.time = function(data, cb, opt){
if(Gun.is(data)){
var soul = data._.soul;
if(!soul){ return cb({err: "Only root level node references supported currently, hopefully will change this in the future."}), this }
data = Gun.val.rel.ify(soul);
}
if(data instanceof Function){
return travel(data, cb, opt, this);
}
opt = opt || {};
var t = new Date(Gun.state()).toISOString().split(/[\-t\:\.z]/ig);
var gun = this, root = gun.back(-1);
var p, tmp = t.pop();
gun.get('_', function(msg, ev){ ev.off();
var id = (msg.put && msg.put['#']) || ((root.back('opt.uuid') || Gun.text.random)(6) + ':'); // TODO: BUG! THIS SHOULD NOT BE HARDCODED.
p = id;
// could shrink this into a loop. Do later?
var rid = (root.back('opt.uuid') || Gun.text.random)(9);
var milli = ify({}, p + t.join(':'));
milli[rid] = data;
tmp = t.pop();
var sec = ify({}, p + t.join(':'));
sec[tmp] = milli;
tmp = t.pop();
var min = ify({}, p + t.join(':'));
min[tmp] = sec;
tmp = t.pop();
var hour = ify({}, p + t.join(':'));
hour[tmp] = min;
tmp = t.pop();
var day = ify({}, p + t.join(':'));
day[tmp] = hour;
tmp = t.pop();
var month = ify({}, p + t.join(':'));
month[tmp] = day;
tmp = t.pop();
var year = ify({}, p + t.join(':'));
year[tmp] = month;
tmp = t.pop();
var time = ify({}, p + t.join(':'));
time[tmp] = year;
var ref = root.put(time);
gun.put(ref, cb);
})
return gun;
}
function travel(cb, opt, b, gun){
var root = gun.back(-1), tmp;
(opt = Gun.num.is(opt)? {start: opt} : opt || {}).seen = opt.seen || {};
var t = new Date(opt.start || Gun.state()).toISOString().split(/[\-t\:\.z]/ig).slice(0,-1);
gun.get('_', function(msg, ev){ ev.off();
var id = (msg.put && msg.put['#']);
if(':' == id[id.length-1]){
id = id.slice(0,-1);
} else {
id = null;
}
if(!id){ return Gun.log("Could not find time index.") }
opt.at = opt.start = [id].concat(t);
find(opt, cb, root);
})
return gun;
}
function find(o, cb, root){
var at = o.at, t = at.join(':');
if(1 == at.length){ t += ':' }
if(o.seen[t]){ return } o.seen[t] = true;
var next = o.start[at.length];
root.get(t).get(function(msg, ev){
var g = this;
if(/*true || */u === msg.put){
o.at = at.slice(0,-1);
console.debug(5, o.at);
console.debug(4, o.at);
console.debug(3, o.at);
console.debug(2, o.at);
console.debug(1, o.at);
find(o, cb, root);
}
if(7 < at.length){
Gun.node.is(msg.put, function(v, k){
cb(v, k, ev);
if(o.last){ --o.last }
})
if(!o.last){ return }
if(o.last <= 0){ return }
var tmp = {seen: {}};
tmp.last = o.last;
tmp.start = tmp.at = o.at;
tmp.at = tmp.at.slice(0,-1);
tmp.was = true;
find(tmp, cb, root);
return;
}
if(u === msg.put){ return }
if(o.last){
var keys = Object.keys(msg.put).sort().reverse();
var less = Gun.list.map(keys, function(k){
if(parseFloat(k) < parseFloat(next)){ return k }
})
if(!less){
o.at = at.slice(0,-1);
find(o, cb, root);
return;
}
o.at.push(less);
(o.start = o.at.slice()).push(Infinity);
o.at.length === 8 && (console.debug.i = console.debug.i || 1);
find(o, cb, root);
return;
}
Gun.node.is(msg.put, function(v, k){
if(k < o.start[at.length]){ return }
(o.at = at.slice()).push(k)
//console.log('>>>>>', o.at);
find(o, cb, root);
})
//console.log(o.at, msg.put, o.start[o.at.length]);
})
}
}());

View File

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

68
sea.js
View File

@ -1303,6 +1303,44 @@
}) })
} }
} }
User.prototype.grant = function(to, cb){
console.log("`.grant` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!");
var gun = this, user = gun.back(-1).user(), pair = user.pair(), path = '';
gun.back(function(at){ if(at.pub){ return } path += (at.get||'') });
(async function(){
var enc, sec = await user.get('trust').get(pair.pub).get(path).then();
sec = await SEA.decrypt(sec, pair);
if(!sec){
sec = SEA.random(16).toString();
enc = await SEA.encrypt(sec, pair);
user.get('trust').get(pair.pub).get(path).put(enc);
}
var pub = to.get('pub').then();
var epub = to.get('epub').then();
pub = await pub; epub = await epub;
var dh = await SEA.secret(epub, pair);
enc = await SEA.encrypt(sec, dh);
user.get('trust').get(pub).get(path).put(enc, cb);
}());
return gun;
}
User.prototype.secret = function(data, cb){
console.log("`.secret` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!");
var gun = this, user = gun.back(-1).user(), pair = user.pair(), path = '';
gun.back(function(at){ if(at.pub){ return } path += (at.get||'') });
(async function(){
var enc, sec = await user.get('trust').get(pair.pub).get(path).then();
sec = await SEA.decrypt(sec, pair);
if(!sec){
sec = SEA.random(16).toString();
enc = await SEA.encrypt(sec, pair);
user.get('trust').get(pair.pub).get(path).put(enc);
}
enc = await SEA.encrypt(data, sec);
gun.put(enc, cb);
}());
return gun;
}
module.exports = User module.exports = User
})(USE, './create'); })(USE, './create');
@ -1320,7 +1358,7 @@
var id = uuid(), pub = at.user; var id = uuid(), pub = at.user;
if(!pub || !(pub = at.user._.sea) || !(pub = pub.pub)){ return id } if(!pub || !(pub = at.user._.sea) || !(pub = pub.pub)){ return id }
id = id + '~' + pub; id = id + '~' + pub;
if(cb){ cb(null, id) } if(cb && cb.call){ cb(null, id) }
return id; return id;
} }
at.on('in', security, at); // now listen to all input data, acting as a firewall. at.on('in', security, at); // now listen to all input data, acting as a firewall.
@ -1428,7 +1466,8 @@
check['user'+soul+key] = 1; check['user'+soul+key] = 1;
if(user && (user = user._) && user.sea && pub === user.pub){ if(user && (user = user._) && user.sea && pub === user.pub){
//var id = Gun.text.random(3); //var id = Gun.text.random(3);
SEA.sign(val, user.sea).then(function(data){ var rel; SEA.sign(val, user.sea, function(data){ var rel;
if(u === data){ return each.end({err: SEA.err || 'Pub signature fail.'}) }
if(rel = Gun.val.rel.is(val)){ if(rel = Gun.val.rel.is(val)){
(at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true; (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true;
} }
@ -1440,7 +1479,7 @@
return; return;
} }
// TODO: consider async/await and drop callback pattern... // TODO: consider async/await and drop callback pattern...
SEA.verify(val, pub).then(function(data){ var rel, tmp; SEA.verify(val, pub, function(data){ var rel, tmp;
if(u === data){ // make sure the signature matches the account it claims to be on. if(u === data){ // make sure the signature matches the account it claims to be on.
return each.end({err: "Unverified data."}); // reject any updates that are signed with a mismatched account. return each.end({err: "Unverified data."}); // reject any updates that are signed with a mismatched account.
} }
@ -1457,7 +1496,7 @@
if(!user || !(user = user._) || !(user = user.sea)){ if(!user || !(user = user._) || !(user = user.sea)){
if((tmp = soul.split('~')) && 2 == tmp.length){ if((tmp = soul.split('~')) && 2 == tmp.length){
check['any'+soul+key] = 1; check['any'+soul+key] = 1;
SEA.verify(val, (pub = tmp[1])).then(function(data){ var rel; SEA.verify(val, (pub = tmp[1]), function(data){ var rel;
if(!data){ return each.end({err: "Mismatched owner on '" + key + "'."}) } if(!data){ return each.end({err: "Mismatched owner on '" + key + "'."}) }
if((rel = Gun.val.rel.is(data)) && (tmp = rel.split('~')) && 2 === tmp.length){ if((rel = Gun.val.rel.is(data)) && (tmp = rel.split('~')) && 2 === tmp.length){
if(pub === tmp[1]){ if(pub === tmp[1]){
@ -1472,13 +1511,29 @@
check['any'+soul+key] = 1; check['any'+soul+key] = 1;
at.on('secure', function(msg){ this.off(); at.on('secure', function(msg){ this.off();
check['any'+soul+key] = 0; check['any'+soul+key] = 0;
if(at.opt.secure){ msg = null }
each.end(msg || {err: "Data cannot be modified."}); each.end(msg || {err: "Data cannot be modified."});
}).on.on('secure', msg); }).on.on('secure', msg);
//each.end({err: "Data cannot be modified."}); //each.end({err: "Data cannot be modified."});
return; return;
} }
if(!(tmp = soul.split('~')) || 2 !== tmp.length){ if(!(tmp = soul.split('~')) || 2 !== tmp.length){
each.end({err: "Soul is missing public key at '" + key + "'."}); if(at.opt.secure){
each.end({err: "Soul is missing public key at '" + key + "'."});
return;
}
if(val && val.slice && 'SEA{' === (val).slice(0,4)){
check['any'+soul+key] = 0;
each.end({ok: 1});
return;
}
check['any'+soul+key] = 1;
SEA.sign(val, user, function(data){
if(u === data){ return each.end({err: 'Any signature failed.'}) }
node[key] = data;
check['any'+soul+key] = 0;
each.end({ok: 1});
});
return; return;
} }
var pub = tmp[1]; var pub = tmp[1];
@ -1494,7 +1549,8 @@
return; return;
}*/ }*/
check['any'+soul+key] = 1; check['any'+soul+key] = 1;
SEA.sign(val, user).then(function(data){ SEA.sign(val, user, function(data){
if(u === data){ return each.end({err: 'My signature fail.'}) }
node[key] = data; node[key] = data;
check['any'+soul+key] = 0; check['any'+soul+key] = 0;
each.end({ok: 1}); each.end({ok: 1});

View File

@ -3,11 +3,11 @@
// is complicated and was extremely hard to build. If you port GUN to another // is complicated and was extremely hard to build. If you port GUN to another
// language, consider implementing an easier API to build. // language, consider implementing an easier API to build.
var Gun = require('./root'); var Gun = require('./root');
Gun.chain.chain = function(){ Gun.chain.chain = function(sub){
var at = this._, chain = new this.constructor(this), cat = chain._, root; var gun = this, at = gun._, chain = new (sub || gun).constructor(gun), cat = chain._, root;
cat.root = root = at.root; cat.root = root = at.root;
cat.id = ++root.once; cat.id = ++root.once;
cat.back = this._; cat.back = gun._;
cat.on = Gun.on; cat.on = Gun.on;
cat.on('in', input, cat); // For 'in' if I add my own listeners to each then I MUST do it before in gets called. If I listen globally for all incoming data instead though, regardless of individual listeners, I can transform the data there and then as well. cat.on('in', input, cat); // For 'in' if I add my own listeners to each then I MUST do it before in gets called. If I listen globally for all incoming data instead though, regardless of individual listeners, I can transform the data there and then as well.
cat.on('out', output, cat); // However for output, there isn't really the global option. I must listen by adding my own listener individually BEFORE this one is ever called. cat.on('out', output, cat); // However for output, there isn't really the global option. I must listen by adding my own listener individually BEFORE this one is ever called.

View File

@ -6,7 +6,7 @@ function Gun(o){
return Gun.create(this._ = {gun: this, opt: o}); return Gun.create(this._ = {gun: this, opt: o});
} }
Gun.is = function(gun){ return (gun instanceof Gun) } Gun.is = function(gun){ return (gun instanceof Gun) || (gun && gun._ && gun._.gun && true) || false }
Gun.version = 0.9; Gun.version = 0.9;