mirror of
https://github.com/amark/gun.git
synced 2025-03-30 15:08:33 +00:00
build/unbuild
This commit is contained in:
parent
51be588a74
commit
985cfa2b4d
2
gun.min.js
vendored
2
gun.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,9 +1,9 @@
|
||||
|
||||
if(typeof btoa === "undefined"){
|
||||
if(typeof Buffer === "undefined") {
|
||||
root.Buffer = require("buffer").Buffer
|
||||
global.Buffer = require("buffer").Buffer
|
||||
}
|
||||
root.btoa = function (data) { return Buffer.from(data, "binary").toString("base64"); };
|
||||
root.atob = function (data) { return Buffer.from(data, "base64").toString("binary"); };
|
||||
global.btoa = function (data) { return Buffer.from(data, "binary").toString("base64"); };
|
||||
global.atob = function (data) { return Buffer.from(data, "base64").toString("binary"); };
|
||||
}
|
||||
|
@ -226,6 +226,7 @@
|
||||
}
|
||||
// If authenticated user wants to delete his/her account, let's support it!
|
||||
User.prototype.delete = async function(alias, pass, cb){
|
||||
console.log("user.delete() IS DEPRECATED AND WILL BE MOVED TO A MODULE!!!");
|
||||
var gun = this, root = gun.back(-1), user = gun.back('user');
|
||||
try {
|
||||
user.auth(alias, pass, function(ack){
|
||||
@ -267,6 +268,7 @@
|
||||
return gun;
|
||||
}
|
||||
User.prototype.alive = async function(){
|
||||
console.log("user.alive() IS DEPRECATED!!!");
|
||||
const gunRoot = this.back(-1)
|
||||
try {
|
||||
// All is good. Should we do something more with actual recalled data?
|
||||
@ -286,25 +288,32 @@
|
||||
console.log(ctx, ev)
|
||||
})
|
||||
}
|
||||
user.get('trust').get(path).put(theirPubkey);
|
||||
|
||||
// do a lookup on this gun chain directly (that gets bob's copy of the data)
|
||||
// do a lookup on the metadata trust table for this path (that gets all the pubkeys allowed to write on this path)
|
||||
// do a lookup on each of those pubKeys ON the path (to get the collab data "layers")
|
||||
// THEN you perform Jachen's mix operation
|
||||
// and return the result of that to...
|
||||
}
|
||||
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 = '';
|
||||
var gun = this, user = gun.back(-1).user(), pair = user._.sea, path = '';
|
||||
gun.back(function(at){ if(at.is){ return } path += (at.get||'') });
|
||||
(async function(){
|
||||
var enc, sec = await user.get('trust').get(pair.pub).get(path).then();
|
||||
var enc, sec = await user.get('grant').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);
|
||||
user.get('grant').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);
|
||||
user.get('grant').get(pub).get(path).put(enc, cb);
|
||||
}());
|
||||
return gun;
|
||||
}
|
||||
|
118
sea/index.js
118
sea/index.js
@ -1,15 +1,15 @@
|
||||
|
||||
const SEA = require('./sea')
|
||||
const Gun = SEA.Gun;
|
||||
var SEA = require('./sea')
|
||||
var Gun = SEA.Gun;
|
||||
// After we have a GUN extension to make user registration/login easy, we then need to handle everything else.
|
||||
|
||||
// We do this with a GUN adapter, we first listen to when a gun instance is created (and when its options change)
|
||||
Gun.on('opt', function(at){
|
||||
if(!at.sea){ // only add SEA once per instance, on the "at" context.
|
||||
at.sea = {own: {}};
|
||||
at.on('in', security, at); // now listen to all input data, acting as a firewall.
|
||||
at.on('out', signature, at); // and output listeners, to encrypt outgoing data.
|
||||
at.on('node', each, at);
|
||||
//at.on('in', security, at); // now listen to all input data, acting as a firewall.
|
||||
//at.on('out', signature, at); // and output listeners, to encrypt outgoing data.
|
||||
at.on('put', check, at);
|
||||
}
|
||||
this.to.next(at); // make sure to call the "next" middleware adapter.
|
||||
});
|
||||
@ -58,6 +58,94 @@
|
||||
security.call(this, msg);
|
||||
}
|
||||
|
||||
var u;
|
||||
function check(msg){ // REVISE / IMPROVE, NO NEED TO PASS MSG/EVE EACH SUB?
|
||||
var eve = this, at = eve.as, put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>'], id = msg['#'], tmp;
|
||||
if(!soul || !key){ return }
|
||||
if((msg._||'').faith && (at.opt||'').faith && 'function' == typeof msg._){
|
||||
SEA.verify(SEA.opt.pack(put), false, function(data){ // this is synchronous if false
|
||||
put['='] = SEA.opt.unpack(data);
|
||||
eve.to.next(msg);
|
||||
});
|
||||
return
|
||||
}
|
||||
var no = function(why){ at.on('in', {'@': id, err: why}) };
|
||||
//var no = function(why){ msg.ack(why) };
|
||||
(msg._||'').DBG && ((msg._||'').DBG.c = +new Date);
|
||||
if(0 <= soul.indexOf('<?')){ // special case for "do not sync data X old"
|
||||
// 'a~pub.key/b<?9'
|
||||
tmp = parseFloat(soul.split('<?')[1]||'');
|
||||
if(tmp && (state < (Gun.state() - (tmp * 1000)))){ // sec to ms
|
||||
(tmp = msg._) && (tmp = tmp.lot) && (tmp.more--); // THIS IS BAD CODE! It assumes GUN internals do something that will probably change in future, but hacking in now.
|
||||
return; // omit!
|
||||
}
|
||||
}
|
||||
if('~@' === soul){ // special case for shared system data, the list of aliases.
|
||||
check.alias(eve, msg, val, key, soul, at, no); return;
|
||||
}
|
||||
if('~@' === soul.slice(0,2)){ // special case for shared system data, the list of public keys for an alias.
|
||||
check.pubs(eve, msg, val, key, soul, at, no); return;
|
||||
}
|
||||
//if('~' === soul.slice(0,1) && 2 === (tmp = soul.slice(1)).split('.').length){ // special case, account data for a public key.
|
||||
if(tmp = SEA.opt.pub(soul)){ // special case, account data for a public key.
|
||||
check.pub(eve, msg, val, key, soul, at, no, at.user||'', tmp); return;
|
||||
}
|
||||
if(0 <= soul.indexOf('#')){ // special case for content addressing immutable hashed data.
|
||||
check.hash(eve, msg, val, key, soul, at, no); return;
|
||||
}
|
||||
check.any(eve, msg, val, key, soul, at, no, at.user||''); return;
|
||||
eve.to.next(msg); // not handled
|
||||
}
|
||||
check.hash = function(eve, msg, val, key, soul, at, no){
|
||||
SEA.work(val, null, function(data){
|
||||
if(data && data === key.split('#').slice(-1)[0]){ return eve.to.next(msg) }
|
||||
no("Data hash not same as hash!");
|
||||
}, {name: 'SHA-256'});
|
||||
}
|
||||
check.alias = function(eve, msg, val, key, soul, at, no){ // Example: {_:#~@, ~@alice: {#~@alice}}
|
||||
if(!val){ return no("Data must exist!") } // data MUST exist
|
||||
if('~@'+key === link_is(val)){ return eve.to.next(msg) } // in fact, it must be EXACTLY equal to itself
|
||||
no("Alias not same!"); // if it isn't, reject.
|
||||
};
|
||||
check.pubs = function(eve, msg, val, key, soul, at, no){ // Example: {_:#~@alice, ~asdf: {#~asdf}}
|
||||
if(!val){ return no("Alias must exist!") } // data MUST exist
|
||||
if(key === link_is(val)){ return eve.to.next(msg) } // and the ID must be EXACTLY equal to its property
|
||||
no("Alias not same!"); // that way nobody can tamper with the list of public keys.
|
||||
};
|
||||
check.pub = function(eve, msg, val, key, soul, at, no, user, pub){ var tmp; // Example: {_:#~asdf, hello:'world'~fdsa}}
|
||||
if('pub' === key && '~'+pub === soul){
|
||||
if(val === pub){ return eve.to.next(msg) } // the account MUST match `pub` property that equals the ID of the public key.
|
||||
return no("Account not same!");
|
||||
}
|
||||
if((tmp = user.is) && pub === tmp.pub){
|
||||
SEA.sign(SEA.opt.pack(msg.put), (user._).sea, function(data){
|
||||
if(u === data){ return no(SEA.err || 'Signature fail.') }
|
||||
if(tmp = link_is(val)){ (at.sea.own[tmp] = at.sea.own[tmp] || {})[pub] = 1 }
|
||||
msg.put[':'] = JSON.stringify({':': tmp = SEA.opt.unpack(data.m), '~': data.s});
|
||||
msg.put['='] = tmp;
|
||||
eve.to.next(msg);
|
||||
}, {raw: 1});
|
||||
return;
|
||||
}
|
||||
SEA.verify(SEA.opt.pack(msg.put), pub, function(data){ var tmp;
|
||||
data = SEA.opt.unpack(data);
|
||||
if(u === data){ return no("Unverified data.") } // make sure the signature matches the account it claims to be on. // reject any updates that are signed with a mismatched account.
|
||||
if((tmp = link_is(data)) && pub === SEA.opt.pub(tmp)){ (at.sea.own[tmp] = at.sea.own[tmp] || {})[pub] = 1 }
|
||||
msg.put['='] = data;
|
||||
eve.to.next(msg);
|
||||
});
|
||||
};
|
||||
check.any = function(eve, msg, val, key, soul, at, no, user){ var tmp, pub;
|
||||
if(at.opt.secure){ return no("Soul missing public key at '" + key + "'.") }
|
||||
// TODO: Ask community if should auto-sign non user-graph data.
|
||||
at.on('secure', function(msg){ this.off();
|
||||
if(!at.opt.secure){ return eve.to.next(msg) }
|
||||
no("Data cannot be changed.");
|
||||
}).on.on('secure', msg);
|
||||
return;
|
||||
}
|
||||
var link_is = Gun.val.link.is, state_ify = Gun.state.ify;
|
||||
|
||||
// okay! The security function handles all the heavy lifting.
|
||||
// It needs to deal read and write of input and output of system data, account/public key data, and regular data.
|
||||
// This is broken down into some pretty clear edge cases, let's go over them:
|
||||
@ -83,6 +171,11 @@
|
||||
}
|
||||
}
|
||||
if(msg.put){
|
||||
/*
|
||||
NOTICE: THIS IS OLD AND GETTING DEPRECATED.
|
||||
ANY SECURITY CHANGES SHOULD HAPPEN ABOVE FIRST
|
||||
THEN PORTED TO HERE.
|
||||
*/
|
||||
// potentially parallel async operations!!!
|
||||
var check = {}, each = {}, u;
|
||||
each.node = function(node, soul){
|
||||
@ -207,12 +300,14 @@
|
||||
}
|
||||
to.next(msg); // pass forward any data we do not know how to handle or process (this allows custom security protocols).
|
||||
}
|
||||
var pubcut = /[^\w_-]/; // anything not alphanumeric or _ -
|
||||
SEA.opt.pub = function(s){
|
||||
if(!s){ return }
|
||||
s = s.split('~');
|
||||
if(!s || !(s = s[1])){ return }
|
||||
s = s.split('.');
|
||||
if(!s || 2 > s.length){ return }
|
||||
s = s.split(pubcut).slice(0,2);
|
||||
if(!s || 2 != s.length){ return }
|
||||
if('@' === (s[0]||'')[0]){ return }
|
||||
s = s.slice(0,2).join('.');
|
||||
return s;
|
||||
}
|
||||
@ -221,16 +316,18 @@
|
||||
}
|
||||
SEA.opt.pack = function(d,k, n,s){ // pack for verifying
|
||||
if(SEA.opt.check(d)){ return d }
|
||||
var meta = (Gun.obj.ify(d)||noop), sig = meta['~'];
|
||||
return sig? {m: {'#':s,'.':k,':':meta[':'],'>':Gun.state.is(n, k)}, s: sig} : d;
|
||||
var meta = (Gun.obj.ify((d && d[':'])||d)||''), sig = meta['~'];
|
||||
return sig? {m: {'#':s||d['#'],'.':k||d['.'],':':meta[':'],'>':d['>']||Gun.state.is(n, k)}, s: sig} : d;
|
||||
}
|
||||
var O = SEA.opt;
|
||||
SEA.opt.unpack = function(d, k, n){ var tmp;
|
||||
if(u === d){ return }
|
||||
if(d && (u !== (tmp = d[':']))){ return tmp }
|
||||
k = k || O.fall_key; if(!n && O.fall_val){ n = {}; n[k] = O.fall_val }
|
||||
if(!k || !n){ return }
|
||||
if(d === n[k]){ return d }
|
||||
if(!SEA.opt.check(n[k])){ return d }
|
||||
var soul = Gun.node.soul(n), s = Gun.state.is(n, k);
|
||||
var soul = Gun.node.soul(n) || O.fall_soul, s = Gun.state.is(n, k) || O.fall_state;
|
||||
if(d && 4 === d.length && soul === d[0] && k === d[1] && fl(s) === fl(d[3])){
|
||||
return d[2];
|
||||
}
|
||||
@ -242,6 +339,7 @@
|
||||
var noop = function(){}, u;
|
||||
var fl = Math.floor; // TODO: Still need to fix inconsistent state issue.
|
||||
var rel_is = Gun.val.rel.is;
|
||||
var obj_ify = Gun.obj.ify;
|
||||
// TODO: Potential bug? If pub/priv key starts with `-`? IDK how possible.
|
||||
|
||||
|
@ -11,6 +11,6 @@
|
||||
|
||||
if(SEA.window = module.window){ SEA.window.SEA = SEA }
|
||||
|
||||
try{ if(typeof common !== "undefined"){ common.exports = SEA } }catch(e){}
|
||||
try{ if(typeof MODULE !== "undefined"){ MODULE.exports = SEA } }catch(e){}
|
||||
module.exports = SEA;
|
||||
|
@ -1,13 +1,13 @@
|
||||
|
||||
var shim = require('./shim');
|
||||
// Practical examples about usage found from ./test/common.js
|
||||
// Practical examples about usage found in tests.
|
||||
var SEA = require('./root');
|
||||
SEA.work = require('./work');
|
||||
SEA.sign = require('./sign');
|
||||
SEA.verify = require('./verify');
|
||||
SEA.encrypt = require('./encrypt');
|
||||
SEA.decrypt = require('./decrypt');
|
||||
SEA.aeskey = require('./aeskey');
|
||||
SEA.opt.aeskey = require('./aeskey'); // not official!
|
||||
|
||||
SEA.random = SEA.random || shim.random;
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
// But all other behavior needs to be equally easy, like opinionated ways of
|
||||
// Adding friends (trusted public keys), sending private messages, etc.
|
||||
// Cheers! Tell me what you think.
|
||||
var Gun = (SEA.window||{}).Gun || require((typeof common == "undefined"?'.':'')+'./gun', 1);
|
||||
var Gun = (SEA.window||{}).Gun || require((typeof MODULE == "undefined"?'.':'')+'./gun', 1);
|
||||
Gun.SEA = SEA;
|
||||
SEA.GUN = SEA.Gun = Gun;
|
||||
|
||||
|
@ -26,8 +26,8 @@
|
||||
const isocrypto = require('isomorphic-webcrypto');
|
||||
api.ossl = api.subtle = isocrypto.subtle;
|
||||
}catch(e){
|
||||
console.log("node-webcrypto-ossl and text-encoding may not be included by default, please add it to your package.json!");
|
||||
OSSL_WEBCRYPTO_OR_TEXT_ENCODING_NOT_INSTALLED;
|
||||
console.log("text-encoding and @peculiar/webcrypto may not be included by default, please add it to your package.json!");
|
||||
TEXT_ENCODING_OR_PECULIAR_WEBCRYPTO_NOT_INSTALLED;
|
||||
}}
|
||||
|
||||
module.exports = api
|
||||
|
@ -20,7 +20,7 @@
|
||||
at.opt.uuid = function(cb){
|
||||
var id = uuid(), pub = root.user;
|
||||
if(!pub || !(pub = pub.is) || !(pub = pub.pub)){ return id }
|
||||
id = id + '~' + pub + '.';
|
||||
id = id + '~' + pub + '/';
|
||||
if(cb && cb.call){ cb(null, id) }
|
||||
return id;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
opt = opt || {};
|
||||
// SEA.I // verify is free! Requires no user permission.
|
||||
var pub = pair.pub || pair;
|
||||
var key = SEA.opt.slow_leak? await SEA.opt.slow_leak(pub) : await (shim.ossl || shim.subtle).importKey('jwk', jwk, {name: 'ECDSA', namedCurve: 'P-256'}, false, ['verify']);
|
||||
var key = SEA.opt.slow_leak? await SEA.opt.slow_leak(pub) : await (shim.ossl || shim.subtle).importKey('jwk', S.jwk(pub), {name: 'ECDSA', namedCurve: 'P-256'}, false, ['verify']);
|
||||
var hash = await sha(json.m);
|
||||
var buf, sig, check, tmp; try{
|
||||
buf = shim.Buffer.from(json.s, opt.encode || 'base64'); // NEW DEFAULT!
|
||||
@ -50,9 +50,11 @@
|
||||
return knownKeys[pair];
|
||||
};
|
||||
|
||||
|
||||
var O = SEA.opt;
|
||||
SEA.opt.fall_verify = async function(data, pair, cb, opt, f){
|
||||
if(f === SEA.opt.fallback){ throw "Signature did not match" } f = f || 1;
|
||||
var tmp = data||'';
|
||||
data = SEA.opt.unpack(data) || data;
|
||||
var json = S.parse(data), pub = pair.pub || pair, key = await SEA.opt.slow_leak(pub);
|
||||
var hash = (f <= SEA.opt.fallback)? shim.Buffer.from(await shim.subtle.digest({name: 'SHA-256'}, new shim.TextEncoder().encode(S.parse(json.m)))) : await sha(json.m); // this line is old bad buggy code but necessary for old compatibility.
|
||||
var buf; var sig; var check; try{
|
||||
@ -67,6 +69,7 @@
|
||||
if(!check){ throw "Signature did not match." }
|
||||
}
|
||||
var r = check? S.parse(json.m) : u;
|
||||
O.fall_soul = tmp['#']; O.fall_key = tmp['.']; O.fall_val = data; O.fall_state = tmp['>'];
|
||||
if(cb){ try{ cb(r) }catch(e){console.log(e)} }
|
||||
return r;
|
||||
}
|
||||
|
@ -12,13 +12,13 @@
|
||||
cb = salt;
|
||||
salt = u;
|
||||
}
|
||||
salt = salt || shim.random(9);
|
||||
data = (typeof data == 'string')? data : JSON.stringify(data);
|
||||
if('sha' === (opt.name||'').toLowerCase().slice(0,3)){
|
||||
var rsha = shim.Buffer.from(await sha(data, opt.name), 'binary').toString(opt.encode || 'base64')
|
||||
if(cb){ try{ cb(rsha) }catch(e){console.log(e)} }
|
||||
return rsha;
|
||||
}
|
||||
salt = salt || shim.random(9);
|
||||
var key = await (shim.ossl || shim.subtle).importKey('raw', new shim.TextEncoder().encode(data), {name: opt.name || 'PBKDF2'}, false, ['deriveBits']);
|
||||
var work = await (shim.ossl || shim.subtle).deriveBits({
|
||||
name: opt.name || 'PBKDF2',
|
||||
|
@ -36,7 +36,7 @@ Gun.on('create', function(root){
|
||||
}
|
||||
|
||||
root.on('out', function(msg){
|
||||
if(msg.lS){ return } // TODO: for IndexedDB and others, shouldn't send to peers ACKs to our own GETs.
|
||||
if(msg.lS){ return } // TODO: for IndexedDB and others, shouldn't send to peers ACKs to our own GETs. // THIS IS BLOCKING BROWSERS REPLYING TO REQUESTS, NO??? CHANGE THIS SOON!! UNDER CONTROLLED CIRCUMSTANCES!! Or maybe in-memory already doe sit?
|
||||
if(Gun.is(msg.$) && msg.put && !msg['@']){
|
||||
id = msg['#'];
|
||||
Gun.graph.is(msg.put, null, map);
|
||||
@ -86,10 +86,11 @@ Gun.on('create', function(root){
|
||||
var lS = function(){}, u;
|
||||
root.on('localStorage', disk); // NON-STANDARD EVENT!
|
||||
|
||||
root.on('put', function(at){
|
||||
this.to.next(at);
|
||||
Gun.graph.is(at.put, null, map);
|
||||
if(!at['@']){ acks[at['#']] = true; } // only ack non-acks.
|
||||
root.on('put', function(msg){
|
||||
this.to.next(msg);
|
||||
var put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>'], tmp;
|
||||
disk[soul] = Gun.state.ify(disk[soul], key, state, val, soul);
|
||||
if(!msg['@']){ (acks[msg['#']] = (tmp = (msg._||'').lot || {})).lS = (tmp.lS||0)+1; } // only ack non-acks.
|
||||
count += 1;
|
||||
if(count >= (opt.batch || 1000)){
|
||||
return flush();
|
||||
@ -110,7 +111,7 @@ Gun.on('create', function(root){
|
||||
data = Gun.state.to(data, has);
|
||||
}
|
||||
//if(!data && !Gun.obj.empty(opt.peers)){ return } // if data not found, don't ack if there are peers. // Hmm, what if we have peers but we are disconnected?
|
||||
root.on('in', {'@': msg['#'], put: Gun.graph.node(data), how: 'lS', lS: msg.$});// || root.$});
|
||||
root.on('in', {'@': msg['#'], put: Gun.graph.node(data), lS:1});// || root.$});
|
||||
};
|
||||
Gun.debug? setTimeout(to,1) : to();
|
||||
});
|
||||
@ -134,6 +135,10 @@ Gun.on('create', function(root){
|
||||
}
|
||||
if(!err && !Gun.obj.empty(opt.peers)){ return } // only ack if there are no peers.
|
||||
Gun.obj.map(ack, function(yes, id){
|
||||
if(yes){
|
||||
if(yes.more){ acks[id] = yes; return }
|
||||
if(yes.s !== yes.lS){ err = "localStorage batch not same." }
|
||||
}
|
||||
root.on('in', {
|
||||
'@': id,
|
||||
err: err,
|
||||
|
@ -1,147 +1,175 @@
|
||||
|
||||
var Type = require('../type');
|
||||
var puff = (typeof setImmediate !== "undefined")? setImmediate : setTimeout;
|
||||
|
||||
function Mesh(root){
|
||||
var mesh = function(){};
|
||||
var opt = root.opt || {};
|
||||
opt.log = opt.log || console.log;
|
||||
opt.gap = opt.gap || opt.wait || 1;
|
||||
opt.gap = opt.gap || opt.wait || 0;
|
||||
opt.pack = opt.pack || (opt.memory? (opt.memory * 1000 * 1000) : 1399000000) * 0.3; // max_old_space_size defaults to 1400 MB.
|
||||
opt.puff = opt.puff || 9; // IDEA: do a start/end benchmark, divide ops/result.
|
||||
var puff = setTimeout.puff || setTimeout;
|
||||
|
||||
var dup = root.dup;
|
||||
var dup = root.dup, dup_check = dup.check, dup_track = dup.track;
|
||||
|
||||
// TODO: somewhere in here caused a out-of-memory crash! How? It is inbound!
|
||||
mesh.hear = function(raw, peer){
|
||||
var hear = mesh.hear = function(raw, peer){
|
||||
if(!raw){ return }
|
||||
var msg, id, hash, tmp = raw[0];
|
||||
if(opt.pack <= raw.length){ return mesh.say({dam: '!', err: "Message too big!"}, peer) }
|
||||
if('{' != raw[2]){ mesh.hear.d += raw.length||0; ++mesh.hear.c; } // STATS! // ugh, stupid double JSON encoding
|
||||
var msg, id, hash, tmp = raw[0], DBG;
|
||||
if(mesh === this){ hear.d += raw.length||0 ; ++hear.c } // STATS!
|
||||
if('[' === tmp){
|
||||
try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)}
|
||||
try{msg = JSON.parse(raw)}catch(e){opt.log('DAM JSON parse error', e)}
|
||||
raw = '';
|
||||
if(!msg){ return }
|
||||
LOG && opt.log(+new Date, msg.length, 'in hear batch');
|
||||
console.STAT && console.STAT(+new Date, msg.length, '# on hear batch');
|
||||
var P = opt.puff;
|
||||
(function go(){
|
||||
var S; LOG && (S = +new Date); // STATS!
|
||||
var m, c = 100; // hardcoded for now?
|
||||
while(c-- && (m = msg.shift())){
|
||||
mesh.hear(m, peer);
|
||||
}
|
||||
LOG && opt.log(S, +new Date - S, 'batch heard');
|
||||
var S = +new Date;
|
||||
//var P = peer.puff || opt.puff, s = +new Date; // TODO: For future, but in mix?
|
||||
var i = 0, m; while(i < P && (m = msg[i++])){ hear(m, peer) }
|
||||
//peer.puff = Math.ceil((+new Date - s)? P * 1.1 : P * 0.9);
|
||||
msg = msg.slice(i); // slicing after is faster than shifting during.
|
||||
console.STAT && console.STAT(S, +new Date - S, 'hear loop');
|
||||
flush(peer); // force send all synchronously batched acks.
|
||||
if(!msg.length){ return }
|
||||
puff(go, 0);
|
||||
}());
|
||||
return;
|
||||
}
|
||||
if('{' === tmp || (Type.obj.is(raw) && (msg = raw))){
|
||||
if('{' === tmp || ((raw['#'] || obj_is(raw)) && (msg = raw))){
|
||||
try{msg = msg || JSON.parse(raw);
|
||||
}catch(e){return opt.log('DAM JSON parse error', e)}
|
||||
if(!msg){ return }
|
||||
if(msg.DBG){ msg.DBG = DBG = {DBG: msg.DBG} }
|
||||
DBG && (DBG.hp = +new Date);
|
||||
if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) }
|
||||
if(msg.DBG_s){ opt.log(+new Date - msg.DBG_s, 'to hear', id) }
|
||||
if(dup.check(id)){ return }
|
||||
dup.track(id, true).it = it(msg); // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore?
|
||||
if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) }
|
||||
if(tmp = dup_check(id)){ return }
|
||||
/*if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) }
|
||||
if(hash && (tmp = msg['@'] || (msg.get && id))){ // Reduces backward daisy in case varying hashes at different daisy depths are the same.
|
||||
if(dup.check(tmp+hash)){ return }
|
||||
dup.track(tmp+hash, true).it = it(msg); // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore?
|
||||
}
|
||||
(msg._ = function(){}).via = peer;
|
||||
if(tmp = msg['><']){ (msg._).to = Type.obj.map(tmp.split(','), tomap) }
|
||||
if(msg.dam){
|
||||
if(tmp = mesh.hear[msg.dam]){
|
||||
*/ // TOOD: COME BACK TO THIS LATER!!! IMPORTANT MESH STUFF!!
|
||||
(msg._ = function(){}).via = mesh.leap = peer;
|
||||
if(tmp = msg.dam){
|
||||
if(tmp = mesh.hear[tmp]){
|
||||
tmp(msg, peer, root);
|
||||
}
|
||||
dup_track(id);
|
||||
return;
|
||||
}
|
||||
var S, ST; LOG && (S = +new Date);
|
||||
var S = +new Date, ST;
|
||||
DBG && (DBG.is = S);
|
||||
root.on('in', msg);
|
||||
LOG && !msg.nts && (ST = +new Date - S) > 9 && opt.log(S, ST, 'msg', msg['#']);
|
||||
return;
|
||||
//ECHO = msg.put || ECHO; !(msg.ok !== -3740) && mesh.say({ok: -3740, put: ECHO, '@': msg['#']}, peer);
|
||||
DBG && (DBG.hd = +new Date);
|
||||
console.STAT && (ST = +new Date - S) > 9 && console.STAT(S, ST, 'msg'); // TODO: PERF: caught one > 1.5s on tgif
|
||||
dup_track(id).via = peer;
|
||||
mesh.leap = null; // warning! mesh.leap could be buggy.
|
||||
}
|
||||
}
|
||||
var tomap = function(k,i,m){m(k,true)};
|
||||
mesh.hear.c = mesh.hear.d = 0;
|
||||
var noop = function(){};
|
||||
hear.c = hear.d = 0;
|
||||
|
||||
;(function(){
|
||||
var SMIA = 0;
|
||||
var message;
|
||||
var message, loop;
|
||||
function each(peer){ mesh.say(message, peer) }
|
||||
mesh.say = function(msg, peer){
|
||||
if(this.to){ this.to.next(msg) } // compatible with middleware adapters.
|
||||
var say = mesh.say = function(msg, peer){
|
||||
if(this && this.to){ this.to.next(msg) } // compatible with middleware adapters.
|
||||
if(!msg){ return false }
|
||||
var id, hash, tmp, raw;
|
||||
var S; LOG && (S = +new Date); //msg.DBG_s = msg.DBG_s || +new Date;
|
||||
var DBG = msg.DBG, S; if(!peer){ S = +new Date ; DBG && (DBG.y = S) }
|
||||
var meta = msg._||(msg._=function(){});
|
||||
if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) }
|
||||
if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) }
|
||||
//if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) }
|
||||
if(!(raw = meta.raw)){
|
||||
raw = mesh.raw(msg);
|
||||
if(hash && (tmp = msg['@'])){
|
||||
/*if(hash && (tmp = msg['@'])){
|
||||
dup.track(tmp+hash).it = it(msg);
|
||||
if(tmp = (dup.s[tmp]||ok).it){
|
||||
if(hash === tmp['##']){ return false }
|
||||
tmp['##'] = hash;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
//LOG && opt.log(S, +new Date - S, 'say prep');
|
||||
dup.track(id).it = it(msg); // track for 9 seconds, default. Earth<->Mars would need more!
|
||||
if(!peer){ peer = (tmp = dup.s[msg['@']]) && (tmp = tmp.it) && (tmp = tmp._) && (tmp = tmp.via) }
|
||||
S && console.STAT && console.STAT(S, +new Date - S, 'say prep');
|
||||
!loop && dup_track(id);//.it = it(msg); // track for 9 seconds, default. Earth<->Mars would need more! // always track, maybe move this to the 'after' logic if we split function.
|
||||
//console.log("SEND!", JSON.parse(JSON.stringify(msg)));
|
||||
if(!peer && (tmp = msg['@'])){ peer = ((tmp = dup.s[tmp]) && (tmp.via || ((tmp = tmp.it) && (tmp = tmp._) && tmp.via))) || mesh.leap } // warning! mesh.leap could be buggy!
|
||||
if(!peer && msg['@']){
|
||||
LOG && opt.log(+new Date, ++SMIA, 'total no peer to ack to');
|
||||
console.STAT && console.STAT(+new Date, ++SMIA, 'total no peer to ack to');
|
||||
return false;
|
||||
} // TODO: Temporary? If ack via trace has been lost, acks will go to all peers, which trashes browser bandwidth. Not relaying the ack will force sender to ask for ack again. Note, this is technically wrong for mesh behavior.
|
||||
if(!peer && mesh.way){ return mesh.way(msg) }
|
||||
if(!peer || !peer.id){ message = msg;
|
||||
if(!Type.obj.is(peer || opt.peers)){ return false }
|
||||
//var S; LOG && (S = +new Date);
|
||||
Type.obj.map(peer || opt.peers, each); // in case peer is a peer list.
|
||||
//LOG && opt.log(S, +new Date - S, 'say loop');
|
||||
var P = opt.puff, ps = opt.peers, pl = Object.keys(peer || opt.peers || {}); // TODO: BETTER PERF? No object.keys? It is polyfilled by Type.js tho.
|
||||
;(function go(){
|
||||
var S = +new Date;
|
||||
//Type.obj.map(peer || opt.peers, each); // in case peer is a peer list.
|
||||
loop = 1; var wr = meta.raw; meta.raw = raw; // quick perf hack
|
||||
var i = 0, p; while(i < 9 && (p = (pl||'')[i++])){
|
||||
if(!(p = ps[p])){ continue }
|
||||
say(msg, p);
|
||||
}
|
||||
meta.raw = wr; loop = 0;
|
||||
pl = pl.slice(i); // slicing after is faster than shifting during.
|
||||
console.STAT && console.STAT(S, +new Date - S, 'say loop');
|
||||
if(!pl.length){ return }
|
||||
puff(go, 0);
|
||||
dup_track(msg['@']); // keep for later
|
||||
}());
|
||||
return;
|
||||
}
|
||||
// TODO: PERF: consider splitting function here, so say loops do less work.
|
||||
if(!peer.wire && mesh.wire){ mesh.wire(peer) }
|
||||
if(id === peer.last){ return } peer.last = id; // was it just sent?
|
||||
if(peer === meta.via){ return false }
|
||||
if(peer === meta.via){ return false } // don't send back to self.
|
||||
if((tmp = meta.to) && (tmp[peer.url] || tmp[peer.pid] || tmp[peer.id]) /*&& !o*/){ return false }
|
||||
if(peer.batch){
|
||||
peer.tail = (tmp = peer.tail || 0) + raw.length;
|
||||
if(peer.tail <= opt.pack){
|
||||
peer.batch.push(raw); // peer.batch += (tmp?'':',')+raw; // TODO: Prevent double JSON! // FOR v1.0 !?
|
||||
//peer.batch.push(raw);
|
||||
peer.batch += (tmp?',':'')+raw; // TODO: Prevent double JSON! // FOR v1.0 !?
|
||||
return;
|
||||
}
|
||||
flush(peer);
|
||||
}
|
||||
peer.batch = []; // peer.batch = '['; // TODO: Prevent double JSON!
|
||||
setTimeout(function(){flush(peer)}, opt.gap);
|
||||
//peer.batch = [];
|
||||
peer.batch = '['; // TODO: Prevent double JSON!
|
||||
var S = +new Date, ST;
|
||||
setTimeout(function(){
|
||||
console.STAT && (ST = +new Date - S) > 9 && console.STAT(S, ST, '0ms TO', id, peer.id);
|
||||
flush(peer);
|
||||
}, opt.gap);
|
||||
send(raw, peer);
|
||||
}
|
||||
function flush(peer){
|
||||
var tmp = peer.batch; // var tmp = peer.batch + ']'; // TODO: Prevent double JSON!
|
||||
peer.batch = peer.tail = null;
|
||||
if(!tmp){ return }
|
||||
if(!tmp.length){ return } // if(3 > tmp.length){ return } // TODO: ^
|
||||
var S; LOG && (S = +new Date);
|
||||
try{tmp = (1 === tmp.length? tmp[0] : JSON.stringify(tmp));
|
||||
}catch(e){return opt.log('DAM JSON stringify error', e)}
|
||||
LOG && opt.log(S, +new Date - S, 'say stringify', tmp.length);
|
||||
if(!tmp){ return }
|
||||
send(tmp, peer);
|
||||
}
|
||||
mesh.say.c = mesh.say.d = 0;
|
||||
}());
|
||||
|
||||
|
||||
function flush(peer){
|
||||
var tmp = peer.batch, t = 'string' == typeof tmp, l;
|
||||
if(t){ tmp += ']' }// TODO: Prevent double JSON!
|
||||
peer.batch = peer.tail = null;
|
||||
if(!tmp){ return }
|
||||
if(t? 3 > tmp.length : !tmp.length){ return } // TODO: ^
|
||||
if(!t){try{tmp = (1 === tmp.length? tmp[0] : JSON.stringify(tmp));
|
||||
}catch(e){return opt.log('DAM JSON stringify error', e)}}
|
||||
if(!tmp){ return }
|
||||
send(tmp, peer);
|
||||
}
|
||||
// for now - find better place later.
|
||||
function send(raw, peer){ try{
|
||||
var wire = peer.wire;
|
||||
var S, ST; LOG && (S = +new Date);
|
||||
if(peer.say){
|
||||
peer.say(raw);
|
||||
} else
|
||||
if(wire.send){
|
||||
wire.send(raw);
|
||||
}
|
||||
LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'wire send', raw.length);
|
||||
mesh.say.d += raw.length||0; ++mesh.say.c; // STATS!
|
||||
}catch(e){
|
||||
(peer.queue = peer.queue || []).push(raw);
|
||||
@ -153,18 +181,22 @@ function Mesh(root){
|
||||
if(!msg){ return '' }
|
||||
var meta = (msg._) || {}, put, hash, tmp;
|
||||
if(tmp = meta.raw){ return tmp }
|
||||
if(typeof msg === 'string'){ return msg }
|
||||
if(!msg.dam){
|
||||
if('string' == typeof msg){ return msg }
|
||||
/*if(!msg.dam){ // TOOD: COME BACK TO THIS LATER!!! IMPORTANT MESH STUFF!!
|
||||
var i = 0, to = []; Type.obj.map(opt.peers, function(p){
|
||||
to.push(p.url || p.pid || p.id); if(++i > 3){ return true } // limit server, fast fix, improve later! // For "tower" peer, MUST include 6 surrounding ids. // REDUCED THIS TO 3 for temporary relay peer performance, towers still should list neighbors.
|
||||
}); if(i > 1){ msg['><'] = to.join() }
|
||||
}
|
||||
}*/ // TOOD: COME BACK TO THIS LATER!!! IMPORTANT MESH STUFF!!
|
||||
var raw = $(msg); // optimize by reusing put = the JSON.stringify from .hash?
|
||||
/*if(u !== put){
|
||||
tmp = raw.indexOf(_, raw.indexOf('put'));
|
||||
raw = raw.slice(0, tmp-1) + put + raw.slice(tmp + _.length + 1);
|
||||
//raw = raw.replace('"'+ _ +'"', put); // NEVER USE THIS! ALSO NEVER DELETE IT TO NOT MAKE SAME MISTAKE! https://github.com/amark/gun/wiki/@$$ Heisenbug
|
||||
}*/
|
||||
// TODO: PERF: tgif, CPU way too much on re-JSONifying ^ it.
|
||||
/*
|
||||
// NOTE TO SELF: Switch NTS to DAM now.
|
||||
*/
|
||||
if(meta && (raw||'').length < (1000 * 100)){ meta.raw = raw } // HNPERF: If string too big, don't keep in memory.
|
||||
return raw;
|
||||
}
|
||||
@ -188,12 +220,12 @@ function Mesh(root){
|
||||
Type.obj.map(tmp, function(msg){
|
||||
send(msg, peer);
|
||||
});
|
||||
Type.obj.native && Type.obj.native(); // dirty place to check if other JS polluted.
|
||||
}
|
||||
mesh.bye = function(peer){
|
||||
root.on('bye', peer);
|
||||
var tmp = +(new Date); tmp = (tmp - (peer.met||tmp));
|
||||
mesh.bye.time = ((mesh.bye.time || tmp) + tmp) / 2;
|
||||
LOG = console.LOG; // dirty place to cheaply update LOG settings over time.
|
||||
}
|
||||
mesh.hear['!'] = function(msg, peer){ opt.log('Error:', msg.err) }
|
||||
mesh.hear['?'] = function(msg, peer){
|
||||
@ -212,7 +244,7 @@ function Mesh(root){
|
||||
});
|
||||
|
||||
root.on('bye', function(peer, tmp){
|
||||
peer = opt.peers[peer.id || peer] || peer;
|
||||
peer = opt.peers[peer.id || peer] || peer;
|
||||
this.to.next(peer);
|
||||
peer.bye? peer.bye() : (tmp = peer.wire) && tmp.close && tmp.close();
|
||||
Type.obj.del(opt.peers, peer.id);
|
||||
@ -226,6 +258,7 @@ function Mesh(root){
|
||||
});
|
||||
root.on('hi', function(peer, tmp){ this.to.next(peer);
|
||||
if(!(tmp = peer.url) || !gets[tmp]){ return } delete gets[tmp];
|
||||
if(opt.super){ return } // temporary (?) until we have better fix/solution?
|
||||
Type.obj.map(root.next, function(node, soul){
|
||||
tmp = {}; tmp[soul] = root.graph[soul];
|
||||
mesh.say({'##': Type.obj.hash(tmp), get: {'#': soul}}, peer);
|
||||
@ -236,18 +269,6 @@ function Mesh(root){
|
||||
}
|
||||
|
||||
;(function(){
|
||||
Type.text.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 $ = JSON.stringify, u;
|
||||
|
||||
Type.obj.hash = function(obj, hash){
|
||||
@ -257,7 +278,9 @@ function Mesh(root){
|
||||
|
||||
function sort(k, v){ var tmp;
|
||||
if(!(v instanceof Object)){ return v }
|
||||
var S = +new Date;
|
||||
Type.obj.map(Object.keys(v).sort(), map, {to: tmp = {}, on: v});
|
||||
console.STAT && console.STAT(S, +new Date - S, 'sort');
|
||||
return tmp;
|
||||
}
|
||||
Type.obj.hash.sort = sort;
|
||||
@ -270,7 +293,7 @@ function Mesh(root){
|
||||
function it(msg){ return msg || {_: msg._, '##': msg['##']} } // HNPERF: Only need some meta data, not full reference (took up too much memory). // HNPERF: Garrrgh! We add meta data to msg over time, copying the object happens to early.
|
||||
|
||||
var empty = {}, ok = true, u;
|
||||
var LOG = console.LOG;
|
||||
var obj_is = Type.obj.is, obj_map = Type.obj.map;
|
||||
|
||||
try{ module.exports = Mesh }catch(e){}
|
||||
|
||||
|
@ -3,9 +3,9 @@
|
||||
require('./onto'); // depends upon onto!
|
||||
module.exports = function ask(cb, as){
|
||||
if(!this.on){ return }
|
||||
if(!(cb instanceof Function)){
|
||||
if(!('function' == typeof cb)){
|
||||
if(!cb || !as){ return }
|
||||
var id = cb['#'] || cb, tmp = (this.tag||empty)[id];
|
||||
var id = cb['#'] || cb, tmp = (this.tag||'')[id];
|
||||
if(!tmp){ return }
|
||||
tmp = this.on(id, as);
|
||||
clearTimeout(tmp.err);
|
||||
@ -15,7 +15,7 @@ module.exports = function ask(cb, as){
|
||||
if(!cb){ return id }
|
||||
var to = this.on(id, cb, as);
|
||||
to.err = to.err || setTimeout(function(){
|
||||
to.next({err: "Error: No ACK received yet.", lack: true});
|
||||
to.next({err: "Error: No ACK yet.", lack: true});
|
||||
to.off();
|
||||
}, (this.opt||{}).lack || 9000);
|
||||
return id;
|
||||
|
@ -25,7 +25,7 @@ Gun.chain.back = function(n, opt){ var tmp;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(n instanceof Function){
|
||||
if('function' == typeof n){
|
||||
var yes, tmp = {back: at};
|
||||
while((tmp = tmp.back)
|
||||
&& u === (yes = n(tmp, opt))){}
|
||||
|
10
src/chain.js
10
src/chain.js
@ -57,6 +57,12 @@ function output(msg){
|
||||
put._ = meta;
|
||||
back.on('in', {$: back.$, put: put, get: back.get})
|
||||
}
|
||||
if(tmp = at.lex){
|
||||
tmp = (tmp._) || (tmp._ = function(){});
|
||||
if(back.ack < tmp.ask){ tmp.ask = back.ack }
|
||||
if(tmp.ask){ return }
|
||||
tmp.ask = 1;
|
||||
}
|
||||
}
|
||||
root.ask(ack, msg);
|
||||
return root.on('in', msg);
|
||||
@ -271,7 +277,7 @@ function ask(at, soul){
|
||||
Gun.obj.del(at, 'ask'); // TODO: PERFORMANCE? More elegant way?
|
||||
}
|
||||
function ack(msg, ev){
|
||||
var as = this.as, get = as.get || empty, at = as.$._, tmp = (msg.put||empty)[get['#']];
|
||||
var as = this.as, get = as.get||'', at = as.$._, tmp = (msg.put||'')[get['#']];
|
||||
if(at.ack){ at.ack = (at.ack + 1) || 1; }
|
||||
if(!msg.put || ('string' == typeof get['.'] && !obj_has(tmp, at.get))){
|
||||
if(at.put !== u){ return }
|
||||
@ -287,7 +293,7 @@ function ack(msg, ev){
|
||||
at.on('in', {get: at.get, put: Gun.val.link.ify(get['#']), $: at.$, '@': msg['@']});
|
||||
return;
|
||||
}
|
||||
Gun.on.put(msg, at.root.$);
|
||||
Gun.on.put(msg);
|
||||
}
|
||||
var empty = {}, u;
|
||||
var obj = Gun.obj, obj_has = obj.has, obj_put = obj.put, obj_del = obj.del, obj_to = obj.to, obj_map = obj.map;
|
||||
|
24
src/dup.js
24
src/dup.js
@ -1,30 +1,28 @@
|
||||
|
||||
var Type = require('./type');
|
||||
function Dup(opt){
|
||||
var dup = {s:{}};
|
||||
var dup = {s:{}}, s = dup.s;
|
||||
opt = opt || {max: 1000, age: /*1000 * 9};//*/ 1000 * 9 * 3};
|
||||
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.check = function(id){
|
||||
if(!s[id]){ return false }
|
||||
return dt(id);
|
||||
}
|
||||
dup.track = function(id, pass){
|
||||
var it = dup.s[id] || (dup.s[id] = {});
|
||||
it.was = time_is();
|
||||
if(pass){ it.pass = true }
|
||||
var dt = dup.track = function(id){
|
||||
var it = s[id] || (s[id] = {});
|
||||
it.was = +new Date;
|
||||
if(!dup.to){ dup.to = setTimeout(dup.drop, opt.age + 9) }
|
||||
return it;
|
||||
}
|
||||
dup.drop = function(age){
|
||||
var now = time_is();
|
||||
Type.obj.map(dup.s, function(it, id){
|
||||
var now = +new Date;
|
||||
Type.obj.map(s, function(it, id){
|
||||
if(it && (age || opt.age) > (now - it.was)){ return }
|
||||
Type.obj.del(dup.s, id);
|
||||
delete s[id];
|
||||
});
|
||||
dup.to = null;
|
||||
console.STAT && (age = +new Date - now) > 9 && console.STAT(now, age, 'dup drop');
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
var time_is = Type.time.is;
|
||||
module.exports = Dup;
|
||||
|
@ -10,7 +10,7 @@ Gun.chain.get = function(key, cb, as){
|
||||
}
|
||||
gun = gun.$;
|
||||
} else
|
||||
if(key instanceof Function){
|
||||
if('function' == typeof key){
|
||||
if(true === cb){ return soul(this, key, cb, as), this }
|
||||
gun = this;
|
||||
var at = gun._, root = at.root, tmp = root.now, ev;
|
||||
@ -46,7 +46,7 @@ Gun.chain.get = function(key, cb, as){
|
||||
if(tmp = this._.stun){ // TODO: Refactor?
|
||||
gun._.stun = gun._.stun || tmp;
|
||||
}
|
||||
if(cb && cb instanceof Function){
|
||||
if(cb && 'function' == typeof cb){
|
||||
gun.get(cb, as);
|
||||
}
|
||||
return gun;
|
||||
@ -72,7 +72,7 @@ function soul(gun, cb, opt, as){
|
||||
if(cat.jam){ return cat.jam.push([cb, as]) }
|
||||
cat.jam = [[cb,as]];
|
||||
gun.get(function go(msg, eve){
|
||||
if(u === msg.put && (tmp = Object.keys(cat.root.opt.peers).length) && ++acks < tmp){
|
||||
if(u === msg.put && (tmp = Object.keys(cat.root.opt.peers).length) && ++acks <= tmp){
|
||||
return;
|
||||
}
|
||||
eve.rid(msg);
|
||||
@ -101,7 +101,7 @@ function use(msg){
|
||||
if(eve.seen && at.id && eve.seen[at.id]){ return eve.to.next(msg) }
|
||||
//if((tmp = root.stop)){ if(tmp[at.id]){ return } tmp[at.id] = msg.root; } // temporary fix till a better solution?
|
||||
if((tmp = data) && tmp[rel._] && (tmp = rel.is(tmp))){
|
||||
tmp = ((msg.$$ = at.root.gun.get(tmp))._);
|
||||
tmp = ((msg.$$ = at.root.$.get(tmp))._);
|
||||
if(u !== tmp.put){
|
||||
msg = obj_to(msg, {put: data = tmp.put});
|
||||
}
|
||||
|
@ -27,9 +27,13 @@ var Graph = {};
|
||||
if(typeof env === 'string'){
|
||||
env = {soul: env};
|
||||
} else
|
||||
if(env instanceof Function){
|
||||
if('function' == typeof env){
|
||||
env.map = env;
|
||||
}
|
||||
if(typeof as === 'string'){
|
||||
env.soul = env.soul || as;
|
||||
as = u;
|
||||
}
|
||||
if(env.soul){
|
||||
at.link = Val.link.ify(env.soul);
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ Node.soul._ = Val.link._;
|
||||
Node.ify = function(obj, o, as){ // returns a node from a shallow object.
|
||||
if(!o){ o = {} }
|
||||
else if(typeof o === 'string'){ o = {soul: o} }
|
||||
else if(o instanceof Function){ o = {map: o} }
|
||||
else if('function' == typeof o){ o = {map: o} }
|
||||
if(o.map){ o.node = o.map.call(as, obj, u, o.node || {}) }
|
||||
if(o.node = Node.soul.ify(o.node || {}, o)){
|
||||
obj_map(obj, map, {o:o,as:as});
|
||||
|
@ -9,7 +9,7 @@ module.exports = function onto(tag, arg, as){
|
||||
tmp.next(arg);
|
||||
}}
|
||||
}});
|
||||
if(arg instanceof Function){
|
||||
if('function' == typeof arg){
|
||||
var be = {
|
||||
off: onto.off ||
|
||||
(onto.off = function(){
|
||||
|
@ -1,9 +1,4 @@
|
||||
|
||||
var root;
|
||||
if(typeof window !== "undefined"){ root = window }
|
||||
if(typeof global !== "undefined"){ root = global }
|
||||
root = root || {};
|
||||
var console = root.console || {log: function(){}};
|
||||
function USE(arg, req){
|
||||
return req? require(arg) : arg.slice? USE[R(arg)] : function(mod, path){
|
||||
arg(mod = {exports: {}});
|
||||
@ -13,5 +8,5 @@
|
||||
return p.split('/').slice(-1).toString().replace('.js','');
|
||||
}
|
||||
}
|
||||
if(typeof module !== "undefined"){ var common = module }
|
||||
if(typeof module !== "undefined"){ var MODULE = module }
|
||||
|
13
src/puff.js
Normal file
13
src/puff.js
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
var to = (typeof setImmediate !== "undefined")? setImmediate : setTimeout, puff = function(cb){
|
||||
if(Q.length){ Q.push(cb); return } Q = [cb];
|
||||
to(function go(S){ S = S || +new Date;
|
||||
var i = 0, cb; while(i < 9 && (cb = Q[i++])){ cb() }
|
||||
console.STAT && console.STAT(S, +new Date - S, 'puff');
|
||||
if(cb && !(+new Date - S)){ return go(S) }
|
||||
if(!(Q = Q.slice(i)).length){ return }
|
||||
to(go, 0);
|
||||
}, 0);
|
||||
}, Q = [];
|
||||
module.exports = setTimeout.puff = puff;
|
||||
|
52
src/put.js
52
src/put.js
@ -1,21 +1,7 @@
|
||||
|
||||
var Gun = require('./root');
|
||||
Gun.chain.put = function(data, cb, as){
|
||||
// #soul.has=value>state
|
||||
// ~who#where.where=what>when@was
|
||||
// TODO: BUG! Put probably cannot handle plural chains! `!as` is quickfix test.
|
||||
var gun = this, at = (gun._), root = at.root.$, ctx = root._, M = 100, tmp;
|
||||
/*if(!ctx.puta && !as){ if(tmp = ctx.puts){ if(tmp > M){ // without this, when synchronous, writes to a 'not found' pile up, when 'not found' resolves it recursively calls `put` which incrementally resolves each write. Stack overflow limits can be as low as 10K, so this limit is hardcoded to 1% of 10K.
|
||||
(ctx.stack || (ctx.stack = [])).push([gun, data, cb, as]);
|
||||
if(ctx.puto){ return }
|
||||
ctx.puto = setTimeout(function drain(){
|
||||
var d = ctx.stack.splice(0,M), i = 0, at; ctx.puta = true;
|
||||
while(at = d[i++]){ at[0].put(at[1], at[2], at[3]) } delete ctx.puta;
|
||||
if(ctx.stack.length){ return ctx.puto = setTimeout(drain, 0) }
|
||||
ctx.stack = ctx.puts = ctx.puto = null;
|
||||
}, 0);
|
||||
return gun;
|
||||
} ++ctx.puts } else { ctx.puts = 1 } }*/
|
||||
as = as || {};
|
||||
as.data = data;
|
||||
as.via = as.$ = as.via || as.$ || gun;
|
||||
@ -34,6 +20,7 @@ Gun.chain.put = function(data, cb, as){
|
||||
return gun;
|
||||
}
|
||||
as.soul = as.soul || (as.not = Gun.node.soul(as.data) || (as.via.back('opt.uuid') || Gun.text.random)());
|
||||
as.via._.stun = {};
|
||||
if(!as.soul){ // polyfill async uuid for SEA
|
||||
as.via.back('opt.uuid')(function(err, soul){ // TODO: improve perf without anonymous callback
|
||||
if(err){ return Gun.log(err) } // TODO: Handle error!
|
||||
@ -46,9 +33,11 @@ Gun.chain.put = function(data, cb, as){
|
||||
ify(as);
|
||||
return gun;
|
||||
}
|
||||
as.via._.stun = {};
|
||||
if(Gun.is(data)){
|
||||
data.get(function(soul, o, msg){
|
||||
if(!soul){
|
||||
delete as.via._.stun;
|
||||
return Gun.log("The reference you are saving is a", typeof msg.put, '"'+ msg.put +'", not a node (object)!');
|
||||
}
|
||||
gun.put(Gun.val.link.ify(soul), cb, as);
|
||||
@ -70,6 +59,14 @@ Gun.chain.put = function(data, cb, as){
|
||||
}
|
||||
return gun;
|
||||
};
|
||||
/*Gun.chain.put = function(data, cb, as){ // don't rewrite! :(
|
||||
var gun = this, at = gun._;
|
||||
as = as || {};
|
||||
as.soul || (as.soul = at.soul || ('string' == typeof cb && cb));
|
||||
if(!as.soul){ return get(data, cb, as) }
|
||||
|
||||
return gun;
|
||||
}*/
|
||||
|
||||
function ify(as){
|
||||
as.batch = batch;
|
||||
@ -101,9 +98,10 @@ function stun(cb){
|
||||
}
|
||||
|
||||
function batch(){ var as = this;
|
||||
if(!as.graph || obj_map(as.stun, no)){ return }
|
||||
if(!as.graph || !obj_empty(as.stun)){ return }
|
||||
as.res = as.res || function(cb){ if(cb){ cb() } };
|
||||
as.res(function(){
|
||||
delete as.via._.stun;
|
||||
var cat = (as.$.back(-1)._), ask = cat.ask(function(ack){
|
||||
cat.root.on('ack', ack);
|
||||
if(ack.err){ Gun.log(ack) }
|
||||
@ -124,6 +122,7 @@ function batch(){ var as = this;
|
||||
});
|
||||
cat.root.mum = mum? obj.to(mum, cat.root.mum) : mum;
|
||||
cat.root.now = tmp;
|
||||
as.via._.on('res', {}); delete as.via._.tag.res; // emitting causes mem leak?
|
||||
}, as);
|
||||
if(as.res){ as.res() }
|
||||
} function no(v,k){ if(v){ return true } }
|
||||
@ -145,16 +144,20 @@ function map(v,k,n, at){ var as = this;
|
||||
at.soul(id);
|
||||
return;
|
||||
}
|
||||
(as.stun = as.stun || {})[path] = true;
|
||||
ref.get(soul, true, {as: {at: at, as: as, p:path}});
|
||||
(as.stun = as.stun || {})[path] = 1;
|
||||
ref.get(soul, true, {as: {at: at, as: as, p:path, ref: ref}});
|
||||
}, {as: as, at: at});
|
||||
//if(is){ return {} }
|
||||
}
|
||||
|
||||
var G = String.fromCharCode(31);
|
||||
function soul(id, as, msg, eve){
|
||||
var as = as.as, cat = as.at; as = as.as;
|
||||
var as = as.as, path = as.p, ref = as.ref, cat = as.at; as = as.as;
|
||||
var sat = ref.back(function(at){ return sat = at.soul || at.link || at.dub });
|
||||
var pat = [sat || as.soul].concat(ref._.has || ref._.get || path)
|
||||
var at = ((msg || {}).$ || {})._ || {};
|
||||
id = at.dub = at.dub || id || Gun.node.soul(cat.obj) || Gun.node.soul(msg.put || at.put) || Gun.val.link.is(msg.put || at.put) || (as.via.back('opt.uuid') || Gun.text.random)(); // TODO: BUG!? Do we really want the soul of the object given to us? Could that be dangerous?
|
||||
id = at.dub = at.dub || id || Gun.node.soul(cat.obj) || Gun.node.soul(msg.put || at.put) || Gun.val.link.is(msg.put || at.put) || pat.join('/') /* || (function(){
|
||||
return (as.soul+'.')+Gun.text.hash(path.join(G)).toString(32);
|
||||
})(); // TODO: BUG!? Do we really want the soul of the object given to us? Could that be dangerous? What about copy operations? */
|
||||
if(eve){ eve.stun = true }
|
||||
if(!id){ // polyfill async uuid for SEA
|
||||
as.via.back('opt.uuid')(function(err, id){ // TODO: improve perf without anonymous callback
|
||||
@ -169,7 +172,7 @@ function soul(id, as, msg, eve){
|
||||
function solve(at, id, cat, as){
|
||||
at.$.back(-1).get(id);
|
||||
cat.soul(id);
|
||||
as.stun[cat.path] = false;
|
||||
delete as.stun[cat.path];
|
||||
as.batch();
|
||||
}
|
||||
|
||||
@ -186,6 +189,7 @@ function any(soul, as, msg, eve){
|
||||
if(as.ref !== as.$){
|
||||
tmp = (as.$._).get || at.get;
|
||||
if(!tmp){ // TODO: Handle
|
||||
delete as.via._.stun;
|
||||
Gun.log("Please report this as an issue! Put.no.get"); // TODO: BUG!??
|
||||
return;
|
||||
}
|
||||
@ -193,7 +197,7 @@ function any(soul, as, msg, eve){
|
||||
tmp = null;
|
||||
}
|
||||
if(u === data){
|
||||
if(!at.get){ return } // TODO: Handle
|
||||
if(!at.get){ delete as.via._.stun; return } // TODO: Handle
|
||||
if(!soul){
|
||||
tmp = at.$.back(function(at){
|
||||
if(at.link || at.soul){ return at.link || at.soul }
|
||||
@ -218,7 +222,7 @@ function any(soul, as, msg, eve){
|
||||
}
|
||||
if(!as.soul){ // polyfill async uuid for SEA
|
||||
as.via.back('opt.uuid')(function(err, soul){ // TODO: improve perf without anonymous callback
|
||||
if(err){ return Gun.log(err) } // Handle error.
|
||||
if(err){ delete as.via._.stun; return Gun.log(err) } // Handle error.
|
||||
as.ref.put(as.data, as.soul = soul, as);
|
||||
});
|
||||
return;
|
||||
@ -226,7 +230,7 @@ function any(soul, as, msg, eve){
|
||||
}
|
||||
as.ref.put(as.data, as.soul, as);
|
||||
}
|
||||
var obj = Gun.obj, obj_is = obj.is, obj_put = obj.put, obj_map = obj.map;
|
||||
var obj = Gun.obj, obj_is = obj.is, obj_put = obj.put, obj_map = obj.map, obj_empty = obj.empty;
|
||||
var u, empty = {}, noop = function(){}, iife = function(fn,as){fn.call(as||empty)};
|
||||
var node_ = Gun.node._;
|
||||
|
196
src/root.js
196
src/root.js
@ -1,14 +1,14 @@
|
||||
|
||||
|
||||
function Gun(o){
|
||||
if(o instanceof Gun){ return (this._ = {gun: this, $: this}).$ }
|
||||
if(o instanceof Gun){ return (this._ = {$: this}).$ }
|
||||
if(!(this instanceof Gun)){ return new Gun(o) }
|
||||
return Gun.create(this._ = {gun: this, $: this, opt: o});
|
||||
return Gun.create(this._ = {$: this, opt: o});
|
||||
}
|
||||
|
||||
Gun.is = function($){ return ($ instanceof Gun) || ($ && $._ && ($ === $._.$)) || false }
|
||||
|
||||
Gun.version = 0.9;
|
||||
Gun.version = 0.2020;
|
||||
|
||||
Gun.chain = Gun.prototype;
|
||||
Gun.chain.toJSON = function(){};
|
||||
@ -23,6 +23,7 @@ Gun.graph = require('./graph');
|
||||
Gun.on = require('./onto');
|
||||
Gun.ask = require('./ask');
|
||||
Gun.dup = require('./dup');
|
||||
Gun.puff = require('./puff');
|
||||
|
||||
;(function(){
|
||||
Gun.create = function(at){
|
||||
@ -33,45 +34,131 @@ Gun.dup = require('./dup');
|
||||
at.dup = at.dup || Gun.dup();
|
||||
var gun = at.$.opt(at.opt);
|
||||
if(!at.once){
|
||||
at.on('in', root, at);
|
||||
at.on('out', root, {at: at, out: root});
|
||||
at.on('in', universe, at);
|
||||
at.on('out', universe, at);
|
||||
at.on('put', map, at);
|
||||
Gun.on('create', at);
|
||||
at.on('create', at);
|
||||
}
|
||||
at.once = 1;
|
||||
return gun;
|
||||
}
|
||||
function root(msg){
|
||||
//add to.next(at); // TODO: MISSING FEATURE!!!
|
||||
var ev = this, as = ev.as, at = as.at || as, gun = at.$, dup, tmp;
|
||||
if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) }
|
||||
if((dup = at.dup).check(tmp)){
|
||||
if(as.out === msg.out){
|
||||
msg.out = u;
|
||||
ev.to.next(msg);
|
||||
function universe(msg){
|
||||
if(!msg){ return }
|
||||
if(msg.out === universe){ this.to.next(msg); return }
|
||||
var eve = this, as = eve.as, at = as.at || as, gun = at.$, dup = at.dup, tmp, DBG = msg.DBG;
|
||||
(tmp = msg['#']) || (tmp = msg['#'] = text_rand(9));
|
||||
if(dup.check(tmp)){ return } dup.track(tmp);
|
||||
tmp = msg._; msg._ = ('function' == typeof tmp)? tmp : function(){};
|
||||
(msg.$ && (msg.$ === (msg.$._||'').$)) || (msg.$ = gun);
|
||||
if(!at.ask(msg['@'], msg)){ // is this machine listening for an ack?
|
||||
DBG && (DBG.u = +new Date);
|
||||
if(msg.get){ Gun.on._get(msg, gun) }
|
||||
if(msg.put){ put(msg); return }
|
||||
}
|
||||
DBG && (DBG.uc = +new Date);
|
||||
eve.to.next(msg);
|
||||
DBG && (DBG.ua = +new Date);
|
||||
msg.out = universe; at.on('out', msg);
|
||||
DBG && (DBG.ue = +new Date);
|
||||
}
|
||||
function put(msg){
|
||||
if(!msg){ return }
|
||||
var ctx = msg._||'', root = ctx.root = ((msg.$||'')._||'').root;
|
||||
var put = msg.put, id = msg['#'], err, tmp;
|
||||
var DBG = ctx.DBG = msg.DBG;
|
||||
if(put['#'] && put['.']){ root.on('put', msg); return }
|
||||
/*root.on(id, function(m){
|
||||
console.log('ack:', m);
|
||||
});*/
|
||||
ctx.out = msg;
|
||||
ctx.lot = {s: 0, more: 1};
|
||||
var S = +new Date;
|
||||
DBG && (DBG.p = S);
|
||||
for(var soul in put){ // Gun.obj.native() makes this safe.
|
||||
var node = put[soul], states;
|
||||
if(!node){ err = ERR+cut(soul)+"no node."; break }
|
||||
if(!(tmp = node._)){ err = ERR+cut(soul)+"no meta."; break }
|
||||
if(soul !== tmp[_soul]){ err = ERR+cut(soul)+"soul not same."; break }
|
||||
if(!(states = tmp[state_])){ err = ERR+cut(soul)+"no state."; break }
|
||||
for(var key in node){ // double loop uncool, but have to support old format.
|
||||
if(node_ === key){ continue }
|
||||
var val = node[key], state = states[key];
|
||||
if(u === state){ err = ERR+cut(key)+"on"+cut(soul)+"no state."; break }
|
||||
if(!val_is(val)){ err = ERR+cut(key)+"on"+cut(soul)+"bad "+(typeof val)+cut(val); break }
|
||||
ham(val, key, soul, state, msg);
|
||||
}
|
||||
if(err){ break }
|
||||
}
|
||||
DBG && (DBG.pe = +new Date);
|
||||
if(console.STAT){ console.STAT(S, +new Date - S, 'mix');console.STAT(S, ctx.lot.s, 'mix #') }
|
||||
if(ctx.err = err){ root.on('in', {'@': id, err: Gun.log(err)}); return }
|
||||
if(!(--ctx.lot.more)){ fire(ctx) } // if synchronous.
|
||||
if(!ctx.stun && !msg['@']){ root.on('in', {'@': id, ok: -1}) } // in case no diff sent to storage, etc., still ack.
|
||||
} Gun.on.put = put;
|
||||
function ham(val, key, soul, state, msg){
|
||||
var ctx = msg._||'', root = ctx.root, graph = root.graph, lot;
|
||||
var vertex = graph[soul] || empty, was = state_is(vertex, key, 1), known = vertex[key];
|
||||
var machine = State(), is = HAM(machine, state, was, val, known), u;
|
||||
if(!is.incoming){
|
||||
if(is.defer){
|
||||
var to = state - machine;
|
||||
setTimeout(function(){
|
||||
ham(val, key, soul, state, msg);
|
||||
}, to > MD? MD : to); // setTimeout Max Defer 32bit :(
|
||||
if(!ctx.to){ root.on('in', {'@': msg['#'], err: to}) } ctx.to = 1;
|
||||
return to;
|
||||
}
|
||||
return;
|
||||
}
|
||||
dup.track(tmp);
|
||||
if(tmp = msg['@']){ dup.track(tmp) } // HNPERF: Bump original request's liveliness.
|
||||
if(!at.ask(tmp, msg)){
|
||||
if(msg.get){
|
||||
Gun.on.get(msg, gun); //at.on('get', get(msg));
|
||||
}
|
||||
if(msg.put){
|
||||
Gun.on.put(msg, gun); //at.on('put', put(msg));
|
||||
}
|
||||
}
|
||||
ev.to.next(msg);
|
||||
if(!as.out){
|
||||
msg.out = root;
|
||||
at.on('out', msg);
|
||||
}
|
||||
(lot = ctx.lot||'').s++; lot.more++;
|
||||
(ctx.stun || (ctx.stun = {}))[soul+key] = 1;
|
||||
var DBG = ctx.DBG; DBG && (DBG.ph = DBG.ph || +new Date);
|
||||
root.on('put', {'#': msg['#'], '@': msg['@'], put: {'#': soul, '.': key, ':': val, '>': state}, _: ctx});
|
||||
}
|
||||
function map(msg){
|
||||
var DBG; if(DBG = (msg._||'').DBG){ DBG.pa = +new Date; DBG.pm = DBG.pm || +new Date}
|
||||
var eve = this, root = eve.as, graph = root.graph, ctx = msg._, put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>'], id = msg['#'], tmp;
|
||||
graph[soul] = state_ify(graph[soul], key, state, val, soul); // TODO: Only put in graph if subscribed? Relays vs Browsers?
|
||||
chain(ctx, soul, key, (u !== (tmp = put['=']))? tmp : val, state); // TODO: This should NOT be how the API works, this should be done at an extension layer, but hacky solution to migrate with old code for now.
|
||||
if((tmp = ctx.out) && (tmp = tmp.put)){
|
||||
tmp[soul] = state_ify(tmp[soul], key, state, val, soul); // TODO: Hacky, fix & come back later, for actual pushing messages.
|
||||
}
|
||||
if(!(--ctx.lot.more)){ fire(ctx) } // TODO: 'forget' feature in SEA tied to this, bad approach, but hacked in for now. Any changes here must update there.
|
||||
eve.to.next(msg);
|
||||
}
|
||||
function chain(ctx, soul, key,val, state){
|
||||
var root = ctx.root, put, tmp;
|
||||
(root.opt||'').super && root.$.get(soul); // I think we need super for now, but since we are rewriting, should consider getting rid of it.
|
||||
if(!root || !(tmp = root.next) || !(tmp = tmp[soul]) || !tmp.$){ return }
|
||||
(put = ctx.put || (ctx.put = {}))[soul] = state_ify(put[soul], key, state, val, soul);
|
||||
tmp.put = state_ify(tmp.put, key, state, val, soul);
|
||||
}
|
||||
function fire(ctx){
|
||||
if(ctx.err){ return }
|
||||
var stop = {};
|
||||
var root = ctx.root, next = root.next||'', put = ctx.put, tmp;
|
||||
var S = +new Date;
|
||||
//Gun.graph.is(put, function(node, soul){
|
||||
for(var soul in put){ var node = put[soul]; // Gun.obj.native() makes this safe.
|
||||
if(!(tmp = next[soul]) || !tmp.$){ continue }
|
||||
root.stop = stop; // temporary fix till a better solution?
|
||||
tmp.on('in', {$: tmp.$, get: soul, put: node});
|
||||
root.stop = null; // temporary fix till a better solution?
|
||||
}
|
||||
console.STAT && console.STAT(S, +new Date - S, 'fire');
|
||||
ctx.DBG && (ctx.DBG.f = +new Date);
|
||||
if(!(tmp = ctx.out)){ return }
|
||||
tmp.out = universe;
|
||||
root.on('out', tmp);
|
||||
}
|
||||
var ERR = "Error: Invalid graph!";
|
||||
var cut = function(s){ return " '"+(''+s).slice(0,9)+"...' " }
|
||||
var HAM = Gun.HAM, MD = 2147483647, State = Gun.state;
|
||||
}());
|
||||
|
||||
;(function(){
|
||||
Gun.on.put = function(msg, gun){
|
||||
Gun.on._put = function(msg, gun){
|
||||
var at = gun._, ctx = {$: gun, graph: at.graph, put: {}, map: {}, souls: {}, machine: Gun.state(), ack: msg['@'], cat: at, stop: {}};
|
||||
if(!Gun.obj.map(msg.put, perf, ctx)){ return } // HNPERF: performance test, not core code, do not port.
|
||||
if(!Gun.graph.is(msg.put, null, verify, ctx)){ ctx.err = "Error: Invalid graph!" }
|
||||
@ -81,13 +168,12 @@ Gun.dup = require('./dup');
|
||||
if(u !== ctx.defer){
|
||||
var to = ctx.defer - ctx.machine;
|
||||
setTimeout(function(){
|
||||
Gun.on.put(msg, gun);
|
||||
Gun.on._put(msg, gun);
|
||||
}, to > MD? MD : to ); // setTimeout Max Defer 32bit :(
|
||||
}
|
||||
if(!ctx.diff){ return }
|
||||
at.on('put', obj_to(msg, {put: ctx.diff}));
|
||||
};
|
||||
var MD = 2147483647;
|
||||
function verify(val, key, node, soul){ var ctx = this;
|
||||
var state = Gun.state.is(node, key), tmp;
|
||||
if(!state){ return ctx.err = "Error: No state on '"+key+"' in node '"+soul+"'!" }
|
||||
@ -155,10 +241,12 @@ Gun.dup = require('./dup');
|
||||
}
|
||||
function perf(node, soul){ if(node !== this.graph[soul]){ return true } } // HNPERF: do not port!
|
||||
|
||||
Gun.on.get = function(msg, gun){
|
||||
Gun.on._get = function(msg, gun){
|
||||
var root = gun._, get = msg.get, soul = get[_soul], node = root.graph[soul], has = get[_has], tmp;
|
||||
var next = root.next || (root.next = {}), at = next[soul];
|
||||
// queue concurrent GETs?
|
||||
var ctx = msg._||'', DBG = ctx.DBG = msg.DBG;
|
||||
DBG && (DBG.g = +new Date);
|
||||
if(!node){ return root.on('get', msg) }
|
||||
if(has){
|
||||
if('string' != typeof has || !obj_has(node, has)){ return root.on('get', msg) }
|
||||
@ -171,16 +259,19 @@ Gun.dup = require('./dup');
|
||||
}
|
||||
node = Gun.graph.node(node);
|
||||
tmp = (at||empty).ack;
|
||||
var faith = function(){}; faith.faith = true; // HNPERF: We're testing performance improvement by skipping going through security again, but this should be audited.
|
||||
var faith = function(){}; faith.ram = faith.faith = true; // HNPERF: We're testing performance improvement by skipping going through security again, but this should be audited.
|
||||
DBG && (DBG.ga = +new Date);
|
||||
root.on('in', {
|
||||
'@': msg['#'],
|
||||
how: 'mem',
|
||||
put: node,
|
||||
ram: 1,
|
||||
$: gun,
|
||||
_: faith
|
||||
});
|
||||
DBG && (DBG.gm = +new Date);
|
||||
//if(0 < tmp){ return }
|
||||
root.on('get', msg);
|
||||
DBG && (DBG.gd = +new Date);
|
||||
}
|
||||
}());
|
||||
|
||||
@ -205,39 +296,30 @@ Gun.dup = require('./dup');
|
||||
obj_map(v, each, this[k]);
|
||||
}, at.opt);
|
||||
Gun.on('opt', at);
|
||||
at.opt.uuid = at.opt.uuid || function(){ return state_lex() + text_rand(12) }
|
||||
//at.opt.uuid = at.opt.uuid || function(){ return state_lex() + text_rand(12) }
|
||||
Gun.obj.native();
|
||||
return gun;
|
||||
}
|
||||
}());
|
||||
Gun.obj.native = function(){ var p = Object.prototype; for(var i in p){ console.log("Native Object.prototype polluted, reverting", i); delete p[i]; } };
|
||||
|
||||
var list_is = Gun.list.is;
|
||||
var text = Gun.text, text_is = text.is, text_rand = text.random;
|
||||
var obj = Gun.obj, obj_is = obj.is, obj_has = obj.has, obj_to = obj.to, obj_map = obj.map, obj_copy = obj.copy;
|
||||
var state_lex = Gun.state.lex, _soul = Gun.val.link._, _has = '.', node_ = Gun.node._, rel_is = Gun.val.link.is;
|
||||
var obj = Gun.obj, obj_empty = obj.empty, obj_is = obj.is, obj_has = obj.has, obj_to = obj.to, obj_map = obj.map, obj_copy = obj.copy;
|
||||
var state_lex = Gun.state.lex, state_ify = Gun.state.ify, state_is = Gun.state.is, _soul = Gun.val.link._, _has = '.', node_ = Gun.node._, val_is = Gun.val.is, rel_is = Gun.val.link.is, state_ = Gun.state._;
|
||||
var empty = {}, u;
|
||||
var C;
|
||||
|
||||
console.only = function(i, s){ return (console.only.i && i === console.only.i && console.only.i++) && (console.log.apply(console, arguments) || s) };
|
||||
|
||||
Gun.log = function(){ return (!Gun.log.off && console.log.apply(console, arguments)), [].slice.call(arguments).join(' ') }
|
||||
Gun.log.once = function(w,s,o){ return (o = Gun.log.once)[w] = o[w] || 0, o[w]++ || Gun.log(s) }
|
||||
|
||||
;"Please do not remove these messages unless you are paying for a monthly sponsorship, thanks!";
|
||||
Gun.log.once("welcome", "Hello wonderful person! :) Thanks for using GUN, feel free to ask for help on https://gitter.im/amark/gun and ask StackOverflow questions tagged with 'gun'!");
|
||||
;"Please do not remove these messages unless you are paying for a monthly sponsorship, thanks!";
|
||||
Gun.log = function(){ return (!Gun.log.off && C.log.apply(C, arguments)), [].slice.call(arguments).join(' ') };
|
||||
Gun.log.once = function(w,s,o){ return (o = Gun.log.once)[w] = o[w] || 0, o[w]++ || Gun.log(s) };
|
||||
|
||||
if(typeof window !== "undefined"){ (window.GUN = window.Gun = Gun).window = window }
|
||||
try{ if(typeof common !== "undefined"){ common.exports = Gun } }catch(e){}
|
||||
try{ if(typeof MODULE !== "undefined"){ MODULE.exports = Gun } }catch(e){}
|
||||
module.exports = Gun;
|
||||
|
||||
/*Gun.on('opt', function(ctx){ // FOR TESTING PURPOSES
|
||||
this.to.next(ctx);
|
||||
if(ctx.once){ return }
|
||||
ctx.on('node', function(msg){
|
||||
var to = this.to;
|
||||
//Gun.node.is(msg.put, function(v,k){ msg.put[k] = v + v });
|
||||
setTimeout(function(){
|
||||
to.next(msg);
|
||||
},1);
|
||||
});
|
||||
});*/
|
||||
(Gun.window||'').console = (Gun.window||'').console || {log: function(){}};
|
||||
(C = console).only = function(i, s){ return (C.only.i && i === C.only.i && C.only.i++) && (C.log.apply(C, arguments) || s) };
|
||||
|
||||
;"Please do not remove welcome log unless you are paying for a monthly sponsorship, thanks!";
|
||||
Gun.log.once("welcome", "Hello wonderful person! :) Thanks for using GUN, please ask for help on http://chat.gun.eco if anything takes you longer than 5min to figure out!");
|
||||
|
@ -6,15 +6,18 @@ Gun.chain.set = function(item, cb, opt){
|
||||
opt = opt || {}; opt.item = opt.item || item;
|
||||
if(soul = Gun.node.soul(item)){ item = Gun.obj.put({}, soul, Gun.val.link.ify(soul)) }
|
||||
if(!Gun.is(item)){
|
||||
if(Gun.obj.is(item)){;
|
||||
item = gun.back(-1).get(soul = soul || Gun.node.soul(item) || gun.back('opt.uuid')()).put(item);
|
||||
if(Gun.obj.is(item)){
|
||||
//item = gun.back(-1).get(soul = soul || Gun.node.soul(item) || (gun.back('opt.uuid') || uuid)()).put(item);
|
||||
soul = soul || Gun.node.soul(item) || uuid(); // this just key now, not a soul.
|
||||
}
|
||||
return gun.get(soul || (Gun.state.lex() + Gun.text.random(7))).put(item, cb, opt);
|
||||
return gun.get(soul || uuid()).put(item, cb, opt);
|
||||
}
|
||||
item.get(function(soul, o, msg){
|
||||
if(!soul && item._.stun){ item._.on('res', function(){ this.off(); gun.set(item, cb, opt) }); return }
|
||||
if(!soul){ return cb.call(gun, {err: Gun.log('Only a node can be linked! Not "' + msg.put + '"!')}) }
|
||||
gun.put(Gun.obj.put({}, soul, Gun.val.link.ify(soul)), cb, opt);
|
||||
},true);
|
||||
return item;
|
||||
}
|
||||
function uuid(){ return Gun.state.lex() + Gun.text.random(7) }
|
||||
|
@ -6,7 +6,7 @@ function State(){
|
||||
/*if(perf){
|
||||
t = start + perf.now(); // Danger: Accuracy decays significantly over time, even if precise.
|
||||
} else {*/
|
||||
t = time();
|
||||
t = +new Date;
|
||||
//}
|
||||
if(last < t){
|
||||
return N = 0, last = t + State.drift;
|
||||
@ -15,10 +15,10 @@ function State(){
|
||||
}
|
||||
var time = Type.time.is, last = -Infinity, N = 0, D = 1000; // WARNING! In the future, on machines that are D times faster than 2016AD machines, you will want to increase D by another several orders of magnitude so the processing speed never out paces the decimal resolution (increasing an integer effects the state accuracy).
|
||||
var perf = (typeof performance !== 'undefined')? (performance.timing && performance) : false, start = (perf && perf.timing && perf.timing.navigationStart) || (perf = false);
|
||||
State._ = '>';
|
||||
var S_ = State._ = '>';
|
||||
State.drift = 0;
|
||||
State.is = function(n, k, o){ // convenience function to get the state on a key on a node and return it.
|
||||
var tmp = (k && n && n[N_] && n[N_][State._]) || o;
|
||||
var tmp = (k && n && n[N_] && n[N_][S_]) || o;
|
||||
if(!tmp){ return }
|
||||
return num_is(tmp = tmp[k])? tmp : -Infinity;
|
||||
}
|
||||
@ -30,7 +30,7 @@ State.ify = function(n, k, s, v, soul){ // put a key's state on a node.
|
||||
}
|
||||
n = Node.soul.ify(n, soul); // then make it so!
|
||||
}
|
||||
var tmp = obj_as(n[N_], State._); // grab the states data.
|
||||
var tmp = obj_as(n[N_], S_); // grab the states data.
|
||||
if(u !== k && k !== N_){
|
||||
if(num_is(s)){
|
||||
tmp[k] = s; // add the valid state.
|
||||
|
24
src/type.js
24
src/type.js
@ -35,6 +35,17 @@ Type.text.match = function(t, o){ var tmp, u;
|
||||
if(u !== o['<'] && t <= o['<']){ return true }
|
||||
return false;
|
||||
}
|
||||
Type.text.hash = function(s, c){ // via SO
|
||||
if(typeof s !== 'string'){ return }
|
||||
c = 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;
|
||||
}
|
||||
Type.list = {is: function(l){ return (l instanceof Array) }}
|
||||
Type.list.slit = Array.prototype.slice;
|
||||
Type.list.sort = function(k){ // creates a new sort function based off some key
|
||||
@ -77,9 +88,9 @@ Type.obj.copy = function(o){ // because http://web.archive.org/web/2014032822402
|
||||
return !o? o : JSON.parse(JSON.stringify(o)); // is shockingly faster than anything else, and our data has to be a subset of JSON anyways!
|
||||
}
|
||||
;(function(){
|
||||
function empty(v,i){ var n = this.n;
|
||||
function empty(v,i){ var n = this.n, u;
|
||||
if(n && (i === n || (obj_is(n) && obj_has(n, i)))){ return }
|
||||
if(i){ return true }
|
||||
if(u !== i){ return true }
|
||||
}
|
||||
Type.obj.empty = function(o, n){
|
||||
if(!o){ return true }
|
||||
@ -95,20 +106,21 @@ Type.obj.copy = function(o){ // because http://web.archive.org/web/2014032822402
|
||||
} t.r = t.r || [];
|
||||
t.r.push(k);
|
||||
};
|
||||
var keys = Object.keys, map;
|
||||
var keys = Object.keys, map, u;
|
||||
Object.keys = Object.keys || function(o){ return map(o, function(v,k,t){t(k)}) }
|
||||
Type.obj.map = map = function(l, c, _){
|
||||
var u, i = 0, x, r, ll, lle, f = fn_is(c);
|
||||
t.r = null;
|
||||
var u, i = 0, x, r, ll, lle, f = 'function' == typeof c;
|
||||
t.r = u;
|
||||
if(keys && obj_is(l)){
|
||||
ll = keys(l); lle = true;
|
||||
}
|
||||
_ = _ || {};
|
||||
if(list_is(l) || ll){
|
||||
x = (ll || l).length;
|
||||
for(;i < x; i++){
|
||||
var ii = (i + Type.list.index);
|
||||
if(f){
|
||||
r = lle? c.call(_ || this, l[ll[i]], ll[i], t) : c.call(_ || this, l[i], ii, t);
|
||||
r = lle? c.call(_, l[ll[i]], ll[i], t) : c.call(_, l[i], ii, t);
|
||||
if(r !== u){ return r }
|
||||
} else {
|
||||
//if(Type.test.is(c,l[i])){ return ii } // should implement deep equality testing!
|
||||
|
Loading…
x
Reference in New Issue
Block a user