mirror of
https://github.com/amark/gun.git
synced 2025-03-30 15:08:33 +00:00
Merge branch 'master' of https://github.com/amark/gun
This commit is contained in:
commit
ed509d0ae3
@ -8,6 +8,8 @@
|
||||
# an installer that will automatically do it for you.
|
||||
|
||||
#debian/ubuntu
|
||||
su -
|
||||
apt-get install sudo -y
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install curl git git-core -y
|
||||
#fedora/openSUSE
|
||||
|
@ -4,7 +4,7 @@
|
||||
<title>Party by Neon ERA</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="./style.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Alegreya+Sans:300italic" rel="stylesheet" type="text/css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Raleway:100" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Caveat" rel="stylesheet">
|
||||
<style>
|
||||
.write {
|
||||
@ -69,13 +69,30 @@
|
||||
#hi .faces img {
|
||||
w-idth: 5%;
|
||||
width: 3em;
|
||||
width: 7vh;
|
||||
}
|
||||
#hi .ton {
|
||||
border-radius: 1em;
|
||||
font-size: 150%;
|
||||
font-size: 2.25vmax;
|
||||
margin: 0 0.5em 0 0.5em;
|
||||
background: transparent;
|
||||
border: 1px solid white;
|
||||
color: white;
|
||||
font-family: 'Raleway', sans-serif;
|
||||
}
|
||||
#hi .ton:hover {
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
</style>
|
||||
<div class="loud write shout rim">Party by NEON ERA.</div>
|
||||
<div class="loud write shout rim">Join the Private Party!</div>
|
||||
<div id="faces" class="flush faces">
|
||||
<div class="right" style="max-width: 20em;">
|
||||
<input id="halias" class="write jot sap" placeholder="username">
|
||||
<input id="hpass" type="password" class="write jot sap" placeholder="passphrase">
|
||||
<div class="right" style="max-width: 30em;">
|
||||
<a href="chrome://extensions" target="_blank"><button class="ton">Install Now</button></a>
|
||||
<a href="#"><button class="ton">How It Works</button></a>
|
||||
<!-- input id="halias" class="write jot sap" placeholder="username">
|
||||
<input id="hpass" type="password" class="write jot sap" placeholder="passphrase" -->
|
||||
<script>
|
||||
$.as.route.page('hi', () => {
|
||||
$('#hpass').on('focus', () => {
|
||||
@ -136,6 +153,14 @@
|
||||
return faces;
|
||||
});
|
||||
</script>
|
||||
<div class="pad ditch">
|
||||
<p class="loud"><i>Your friend has invited you to add a privacy extension to your browser:</i></p>
|
||||
<p> - Decrypts your friends' messages across any site!</p>
|
||||
<p> - Stops tech monopolies from selling your private data to advertisers.</p>
|
||||
<p> - Gives you ownership and control over all your data online.</p>
|
||||
<p> - Creates a searchable history of your posts, friends, and more!</p>
|
||||
</div>
|
||||
<div id="faces2" class="flush faces"></div>
|
||||
<div class="pad ditch">
|
||||
<p class="loud"><i>Express your thoughts & connect with the world around you!</i></p>
|
||||
<p> - Discover new relationships.</p>
|
||||
@ -143,12 +168,10 @@
|
||||
<p> - Watch fun videos and photos from people who share.</p>
|
||||
<p> - But this time, you own it: fully decentralized.</p>
|
||||
</div>
|
||||
<div id="faces2" class="flush faces">
|
||||
</div>
|
||||
<div class="pad ditch" style="margin-top: 1em;">
|
||||
<p><span class="loud write shout">Welcome</span><span class="write loud">, you are currently connected to <b id="peers" class="huet4">2</b> peers. <b>Why not try to sign up or log in?</b></span></p>
|
||||
<p><span class="loud write shout">Welcome,</span><!-- span class="write loud">, you are currently connected to <b id="peers" class="huet4">2</b> peers. <b>Why not try to sign up or log in?</b></span --></p>
|
||||
<p> - Your identity is created here, by you. Not on a server.</p>
|
||||
<p> - It uses secure <a href="https://gun.eco/explainers/data/security.html">cryptographic</a> methods to protect you.</p>
|
||||
<p> - It uses secure <a href="https://gun.eco/docs/Cartoon-Cryptography">cryptographic</a> methods to protect you.</p>
|
||||
<p> - Only you have access to it, meaning even we cannot reset your password!</p>
|
||||
<p> - For added security, you can freely <a href="https://github.com/amark/gun">download</a> and run it on your own computer.</p>
|
||||
</div>
|
||||
@ -718,7 +741,7 @@
|
||||
if(e.err){ return }
|
||||
var m = $($("#d"+e.id)[0] || $('#d0').clone(true,true).attr('id', 'd'+e.id).css('backgroundImage', '').appendTo('#draft')).addClass('pulse');
|
||||
if(up){ return up.shrink(e, resize, 1000) }
|
||||
console.log(e.id, e.base64);
|
||||
//console.log(e.id, e.base64);
|
||||
m.removeClass('pulse').css({
|
||||
backgroundImage: 'url(' + e.base64 + ')',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
@ -727,7 +750,7 @@
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<!-- script async src="../../gun/lib/fun.js"></script -->
|
||||
<script async src="../../gun/lib/fun.js"></script>
|
||||
<script async src="../../gun/lib/normalize.js"></script>
|
||||
<script async src="../../gun/lib/monotype.js"></script>
|
||||
<script async src="../../gun/lib/meta.js"></script>
|
||||
|
@ -1,15 +1,7 @@
|
||||
@import url(https://fonts.googleapis.com/css?family=Oxygen);
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Oxygen', 'Trebuchet MS', arial;
|
||||
position: relative;
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 18pt;
|
||||
}
|
||||
|
||||
@ -43,6 +35,10 @@ ul, li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
[contenteditable=true]:empty:before {
|
||||
content: attr(placeholder);
|
||||
}
|
||||
|
||||
.model, .none { display: none }
|
||||
.hide {
|
||||
opacity: 0;
|
||||
@ -107,6 +103,10 @@ ul, li {
|
||||
.loud {
|
||||
font-size: 150%;
|
||||
}
|
||||
.shout {
|
||||
font-size: 36pt;
|
||||
font-size: 6.5vmax;
|
||||
}
|
||||
.jot {
|
||||
border-bottom: 1px dashed #95B2CA;
|
||||
}
|
||||
|
65
gun.js
65
gun.js
@ -807,25 +807,9 @@
|
||||
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];
|
||||
if(obj_has(soul, '*')){ // TEMPORARY HACK FOR MARTTI, TESTING
|
||||
var graph = {};
|
||||
Gun.obj.map(root.graph, function(node, s){
|
||||
if(Gun.text.match(s, soul)){
|
||||
graph[s] = Gun.obj.copy(node);
|
||||
}
|
||||
});
|
||||
if(!Gun.obj.empty(graph)){
|
||||
root.on('in', {
|
||||
'@': msg['#'],
|
||||
how: '*',
|
||||
put: graph,
|
||||
$: gun
|
||||
});
|
||||
}
|
||||
} // TEMPORARY HACK FOR MARTTI, TESTING
|
||||
if(!node){ return root.on('get', msg) }
|
||||
if(has){
|
||||
if(!obj_has(node, has)){ return root.on('get', msg) }
|
||||
if('string' != typeof has || !obj_has(node, has)){ return root.on('get', msg) }
|
||||
node = Gun.state.to(node, has);
|
||||
// If we have a key in-memory, do we really need to fetch?
|
||||
// Maybe... in case the in-memory key we have is a local write
|
||||
@ -966,6 +950,7 @@
|
||||
at.on('in', at);
|
||||
return;
|
||||
}*/
|
||||
if(at.lex){ msg.get = obj_to(at.lex, msg.get) }
|
||||
if(get['#'] || at.soul){
|
||||
get['#'] = get['#'] || at.soul;
|
||||
msg['#'] || (msg['#'] = text_rand(9));
|
||||
@ -988,6 +973,17 @@
|
||||
get: back.get
|
||||
});
|
||||
if(tmp){ return }
|
||||
} else
|
||||
if('string' != typeof get){
|
||||
var put = {}, meta = (back.put||{})._;
|
||||
Gun.obj.map(back.put, function(v,k){
|
||||
if(!Gun.text.match(k, get)){ return }
|
||||
put[k] = v;
|
||||
})
|
||||
if(!Gun.obj.empty(put)){
|
||||
put._ = meta;
|
||||
back.on('in', {$: back.$, put: put, get: back.get})
|
||||
}
|
||||
}
|
||||
root.ask(ack, msg);
|
||||
return root.on('in', msg);
|
||||
@ -1087,7 +1083,6 @@
|
||||
relate(cat, msg, at, rel);
|
||||
echo(cat, msg, eve);
|
||||
}
|
||||
var C = 0;
|
||||
|
||||
function relate(at, msg, from, rel){
|
||||
if(!rel || node_ === at.get){ return }
|
||||
@ -1203,7 +1198,7 @@
|
||||
function ack(msg, ev){
|
||||
var as = this.as, get = as.get || empty, at = as.$._, tmp = (msg.put||empty)[get['#']];
|
||||
if(at.ack){ at.ack = (at.ack + 1) || 1; }
|
||||
if(!msg.put || (get['.'] && !obj_has(tmp, at.get))){
|
||||
if(!msg.put || ('string' == typeof get['.'] && !obj_has(tmp, at.get))){
|
||||
if(at.put !== u){ return }
|
||||
at.on('in', {
|
||||
get: at.get,
|
||||
@ -1259,12 +1254,18 @@
|
||||
} else
|
||||
if(tmp = rel.is(key)){
|
||||
return this.get(tmp, cb, as);
|
||||
} else
|
||||
if(obj.is(key)){
|
||||
gun = this;
|
||||
if(tmp = ((tmp = key['#'])||empty)['='] || tmp){ gun = gun.get(tmp) }
|
||||
gun._.lex = key;
|
||||
return gun;
|
||||
} else {
|
||||
(as = this.chain())._.err = {err: Gun.log('Invalid get request!', key)}; // CLEAN UP
|
||||
if(cb){ cb.call(as, as._.err) }
|
||||
return as;
|
||||
}
|
||||
if(tmp = cat.stun){ // TODO: Refactor?
|
||||
if(tmp = this._.stun){ // TODO: Refactor?
|
||||
gun._.stun = gun._.stun || tmp;
|
||||
}
|
||||
if(cb && cb instanceof Function){
|
||||
@ -1359,7 +1360,18 @@
|
||||
// #soul.has=value>state
|
||||
// ~who#where.where=what>when@was
|
||||
// TODO: BUG! Put probably cannot handle plural chains!
|
||||
var gun = this, at = (gun._), root = at.root.$, tmp;
|
||||
var gun = this, at = (gun._), root = at.root.$, ctx = root._, M = 100, tmp;
|
||||
if(!ctx.puta){ 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;
|
||||
@ -1392,7 +1404,7 @@
|
||||
}
|
||||
if(Gun.is(data)){
|
||||
data.get(function(soul, o, msg){
|
||||
if(!soul && Gun.val.is(msg.put)){
|
||||
if(!soul){
|
||||
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);
|
||||
@ -1454,7 +1466,9 @@
|
||||
if(!ack.lack){ this.off() } // One response is good enough for us currently. Later we may want to adjust this.
|
||||
if(!as.ack){ return }
|
||||
as.ack(ack, this);
|
||||
//--C;
|
||||
}, as.opt);
|
||||
//C++;
|
||||
// NOW is a hack to get synchronous replies to correctly call.
|
||||
// and STOP is a hack to get async behavior to correctly call.
|
||||
// neither of these are ideal, need to be fixed without hacks,
|
||||
@ -1469,6 +1483,7 @@
|
||||
}, as);
|
||||
if(as.res){ as.res() }
|
||||
} function no(v,k){ if(v){ return true } }
|
||||
//console.debug(999,1); var C = 0; setInterval(function(){ try{ debug.innerHTML = C }catch(e){console.log(e)} }, 500);
|
||||
|
||||
function map(v,k,n, at){ var as = this;
|
||||
var is = Gun.is(v);
|
||||
@ -1657,6 +1672,7 @@
|
||||
}
|
||||
|
||||
function val(msg, eve, to){
|
||||
if(!msg.$){ eve.off(); return }
|
||||
var opt = this.as, cat = opt.at, gun = msg.$, at = gun._, data = at.put || msg.put, link, tmp;
|
||||
if(tmp = msg.$$){
|
||||
link = tmp = (msg.$$._);
|
||||
@ -1748,8 +1764,9 @@
|
||||
}
|
||||
function each(v,k){
|
||||
if(n_ === k){ return }
|
||||
var msg = this.msg, gun = msg.$, at = this.at, tmp = (gun.get(k)._);
|
||||
(tmp.echo || (tmp.echo = {}))[at.id] = tmp.echo[at.id] || at;
|
||||
var msg = this.msg, gun = msg.$, at = gun._, cat = this.at, tmp = at.lex;
|
||||
if(tmp && !Gun.text.match(k, tmp['.'] || tmp['#'] || tmp)){ return } // TODO: Ugly hack!
|
||||
((tmp = gun.get(k)._).echo || (tmp.echo = {}))[cat.id] = tmp.echo[cat.id] || cat;
|
||||
}
|
||||
var obj_map = Gun.obj.map, noop = function(){}, event = {stun: noop, off: noop}, n_ = Gun.node._, u;
|
||||
})(USE, './map');
|
||||
|
2
gun.min.js
vendored
2
gun.min.js
vendored
File diff suppressed because one or more lines are too long
18
lib/fsrm.js
Normal file
18
lib/fsrm.js
Normal file
@ -0,0 +1,18 @@
|
||||
var fs = require('fs');
|
||||
var nodePath = require('path');
|
||||
|
||||
var dir = __dirname + '/../';
|
||||
|
||||
module.exports = function rm(path, full) {
|
||||
path = full || nodePath.join(dir, path);
|
||||
if(!fs.existsSync(path)){ return }
|
||||
fs.readdirSync(path).forEach(function(file,index){
|
||||
var curPath = path + "/" + file;
|
||||
if(fs.lstatSync(curPath).isDirectory()) { // recurse
|
||||
rm(null, curPath);
|
||||
} else { // delete file
|
||||
fs.unlinkSync(curPath);
|
||||
}
|
||||
});
|
||||
fs.rmdirSync(path);
|
||||
};
|
54
lib/meta.js
54
lib/meta.js
@ -1,27 +1,17 @@
|
||||
$(function(){
|
||||
var m = window.meta = {edit:[], os:{}}, ua = '', u;
|
||||
try{ua = navigator.userAgent.toLowerCase()}catch(e){}
|
||||
m.os.is = {
|
||||
win: (ua.search("win") >= 0)? "windows":false,
|
||||
lin: (ua.search("linux") >= 0)? "linux":false,
|
||||
mac: (ua.search("mac") >= 0)? "macintosh":false,
|
||||
and: (ua.search("android") >= 0)? "android":false,
|
||||
ios: (ua.search('ipod') >= 0
|
||||
|| ua.search('iphone') >= 0
|
||||
|| ua.search('ipad') >= 0)? "ios":false
|
||||
}
|
||||
var k = m.key = {ctrl: 17, cmd: 91};
|
||||
k.meta = (m.os.is.win||m.os.is.lin||m.os.is.and)? k.ctrl : k.cmd;
|
||||
var m = window.meta = {edit:[]}, u;
|
||||
var k = m.key = {};
|
||||
k.meta = {17:1, 91:1, 93:1, 224:1};
|
||||
k.down = function(eve){
|
||||
if($(eve.target).is('input') || eve.repeat){ return }
|
||||
(k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode;
|
||||
if(!eve.fake && eve.which === k.last){ return }
|
||||
if(k.meta === (k.last = eve.which)){ k.down.meta = m.flip(k.wipe()) || true }
|
||||
if(k.meta[(k.last = eve.which)]){ k.down.meta = m.flip(k.wipe()) || true }
|
||||
if(m.flip.is()){
|
||||
(k.combo || (k.combo = [])).push(eve.which);
|
||||
m.check('on', eve.which, k.at || (k.at = m.edit));
|
||||
}
|
||||
if(eve.metaKey && (k.meta !== eve.which)){ k.up(eve) } // on some systems, meta hijacks keyup
|
||||
if(eve.metaKey && (!k.meta[eve.which])){ k.up(eve) } // on some systems, meta hijacks keyup
|
||||
}
|
||||
k.up = function(eve){ var tmp;
|
||||
if($(eve.target).is('input')){ return }
|
||||
@ -29,7 +19,7 @@ $(function(){
|
||||
k.last = null;
|
||||
eve.which = eve.which || eve.fake || eve.keyCode;
|
||||
if(m.flip.is()){ m.check('up', eve.which) }
|
||||
if(tmp = (k.meta === eve.which)){ k.down.meta = false }
|
||||
if(tmp = (k.meta[eve.which])){ k.down.meta = false }
|
||||
if(tmp && k.at === m.edit){ k.wipe() }
|
||||
if(27 === eve.which){ return m.flip(false) }
|
||||
}
|
||||
@ -355,6 +345,38 @@ $(function(){
|
||||
// Size Spacing
|
||||
// Size Super
|
||||
// Size Sub
|
||||
/*
|
||||
meta.edit({name: "Edit", combo: ['E']});
|
||||
meta.edit({name: "Add", combo: ['E','A'],
|
||||
on: function(e){
|
||||
console.log(111);
|
||||
var r = m.tap.range || monotype();
|
||||
r.insert($('<div>hi</div>'));
|
||||
}
|
||||
});
|
||||
meta.edit({name: "Color", combo: ['E','C'],
|
||||
on: function(e){
|
||||
console.log(111);
|
||||
var r = m.tap.range || monotype();
|
||||
meta.ask('Color name or code?', function(color){
|
||||
r.get().closest('div').css({background: color});
|
||||
});
|
||||
}
|
||||
});
|
||||
meta.edit({name: "Width", combo: ['E','W'],
|
||||
on: function(e){
|
||||
var r = m.tap.range || monotype(), s = e.pageX||0, on = r.get().closest('div'), was = on.width();
|
||||
console.log(1);
|
||||
$(document).on('mousemove.tmp', function(eve){
|
||||
var w = was + ((eve.pageX||0) - was);
|
||||
console.log(w);
|
||||
on.css({width: w});
|
||||
})
|
||||
}, up: function(){
|
||||
console.log(0);
|
||||
$(document).off('mousemove.tmp');
|
||||
}
|
||||
});
|
||||
*/
|
||||
}());
|
||||
});
|
@ -29,12 +29,13 @@
|
||||
hierarchy: ['div', 'pre', 'ol', 'ul', 'li',
|
||||
'h1', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'a', // block
|
||||
'b', 'code', 'i', 'span', 's', 'sub', 'sup', 'u', // inline
|
||||
'br'] // empty
|
||||
'br', 'img'] // empty
|
||||
,tags: {
|
||||
'a': {attrs:{'href':1}, exclude:{'a':1}},
|
||||
'b': {exclude:{'b':1,'p':1}},
|
||||
'br': {empty: 1},
|
||||
'i': {exclude:{'i':1,'p':1}},
|
||||
'img': {attrs:{'src':1}, empty: 1},
|
||||
'span': {exclude:{'p':1,'ul':1,'ol':1,'li':1,'br':1}},
|
||||
's': {space:1},
|
||||
'u': {exclude:{'u':1,'p':1},space:1},
|
||||
@ -138,12 +139,17 @@
|
||||
return $(($(e)[0]||{})[d]);
|
||||
}
|
||||
|
||||
var xssattr = /[^a-z:]/ig, xssjs = /javascript:/ig;
|
||||
// url("javascript: // and all permutations
|
||||
// stylesheets can apparently have XSS?
|
||||
|
||||
// create key val attributes object from elements attributes
|
||||
function attrsAsObj(e, filterCb){
|
||||
var attrObj = {};
|
||||
(e = $(e)) && e.length && $(e[0].attributes||[]).each(function(value,name){
|
||||
name = name.nodeName||name.name;
|
||||
value = e.attr(name);
|
||||
if(value.replace(xssattr,'').match(xssjs)){ e.removeAttr(name); return }
|
||||
value = filterCb? filterCb(value,name,e) : value;
|
||||
if(value !== undefined && value !== false)
|
||||
attrObj[name] = value;
|
||||
|
135
lib/radisk.js
135
lib/radisk.js
@ -5,15 +5,21 @@
|
||||
opt = opt || {};
|
||||
opt.log = opt.log || console.log;
|
||||
opt.file = String(opt.file || 'radata');
|
||||
var has = (Radisk.has || (Radisk.has = {}))[opt.file];
|
||||
if(has){ return has }
|
||||
|
||||
opt.pack = opt.pack || (opt.memory? (opt.memory * 1000 * 1000) : 1399000000) * 0.3; // max_old_space_size defaults to 1400 MB.
|
||||
opt.until = opt.until || opt.wait || 9;
|
||||
opt.batch = opt.batch || 10 * 1000;
|
||||
opt.until = opt.until || opt.wait || 250;
|
||||
opt.batch = opt.batch || (10 * 1000);
|
||||
opt.chunk = opt.chunk || (1024 * 1024 * 10); // 10MB
|
||||
opt.code = opt.code || {};
|
||||
opt.code.from = opt.code.from || '!';
|
||||
//opt.jsonify = true; // TODO: REMOVE!!!!
|
||||
|
||||
function ename(t){ return encodeURIComponent(t).replace(/\*/g, '%2A') }
|
||||
function atomic(v){ return u !== v && (!v || 'object' != typeof v) }
|
||||
var map = Gun.obj.map;
|
||||
var LOG = false;
|
||||
|
||||
if(!opt.store){
|
||||
return opt.log("ERROR: Radisk needs `opt.store` interface with `{get: fn, put: fn (, list: fn)}`!");
|
||||
@ -36,25 +42,29 @@
|
||||
var r = function(key, val, cb){
|
||||
key = ''+key;
|
||||
if(val instanceof Function){
|
||||
var o = cb;
|
||||
cb = val;
|
||||
val = r.batch(key);
|
||||
if(u !== val){
|
||||
cb(u, val, o);
|
||||
if(atomic(val)){ return }
|
||||
// if a node is requested and some of it is cached... the other parts might not be.
|
||||
return cb(u, val);
|
||||
}
|
||||
if(r.thrash.at){
|
||||
val = r.thrash.at(key);
|
||||
if(u !== val){
|
||||
cb(u, val, o);
|
||||
if(atomic(val)){ cb(u, val, o); return }
|
||||
// if a node is requested and some of it is cached... the other parts might not be.
|
||||
return cb(u, val);
|
||||
}
|
||||
}
|
||||
return r.read(key, cb);
|
||||
return r.read(key, cb, o);
|
||||
}
|
||||
r.batch(key, val);
|
||||
if(cb){ r.batch.acks.push(cb) }
|
||||
if(++r.batch.ed >= opt.batch){ return r.thrash() } // (2)
|
||||
clearTimeout(r.batch.to); // (1)
|
||||
if(r.batch.to){ return }
|
||||
//clearTimeout(r.batch.to); // (1) // THIS LINE IS EVIL! NEVER USE IT! ALSO NEVER DELETE THIS SO WE NEVER MAKE THE SAME MISTAKE AGAIN!
|
||||
r.batch.to = setTimeout(r.thrash, opt.until || 1);
|
||||
}
|
||||
|
||||
@ -73,9 +83,11 @@
|
||||
r.batch = Radix();
|
||||
r.batch.acks = [];
|
||||
r.batch.ed = 0;
|
||||
//var id = Gun.text.random(2), S = (+new Date); console.log("<<<<<<<<<<<<", id);
|
||||
r.save(batch, function(err, ok){
|
||||
if(++i > 1){ return }
|
||||
if(++i > 1){ opt.log('RAD ERR: Radisk has callbacked multiple times, please report this as a BUG at github.com/amark/gun/issues ! ' + i); return }
|
||||
if(err){ opt.log('err', err) }
|
||||
//console.log(">>>>>>>>>>>>", id, ((+new Date) - S), batch.acks.length);
|
||||
map(batch.acks, function(cb){ cb(err, ok) });
|
||||
thrash.at = null;
|
||||
thrash.ing = false;
|
||||
@ -90,7 +102,7 @@
|
||||
4. Read the previous file to that into memory
|
||||
5. Scan through the in memory radix for all values lexically less than the limit.
|
||||
6. Merge and write all of those to the in-memory file and back to disk.
|
||||
7. If file to large, split. More details needed here.
|
||||
7. If file too large, split. More details needed here.
|
||||
*/
|
||||
r.save = function(rad, cb){
|
||||
var s = function Span(){};
|
||||
@ -136,28 +148,32 @@
|
||||
Therefore it is unavoidable that a read will have to happen,
|
||||
the question is just how long you delay it.
|
||||
*/
|
||||
r.write = function(file, rad, cb, force){
|
||||
r.write = function(file, rad, cb, o){
|
||||
o = ('object' == typeof o)? o : {force: o};
|
||||
var f = function Fractal(){};
|
||||
f.text = '';
|
||||
f.count = 0;
|
||||
f.file = file;
|
||||
f.each = function(val, key, k, pre){
|
||||
//console.log("RAD:::", JSON.stringify([val, key, k, pre]));
|
||||
if(u !== val){ f.count++ }
|
||||
if(opt.pack <= (val||'').length){ return cb("Record too big!"), true }
|
||||
var enc = Radisk.encode(pre.length) +'#'+ Radisk.encode(k) + (u === val? '' : ':'+ Radisk.encode(val)) +'\n';
|
||||
if((opt.chunk < f.text.length + enc.length) && (1 < f.count) && !force){
|
||||
if((opt.chunk < f.text.length + enc.length) && (1 < f.count) && !o.force){
|
||||
f.text = '';
|
||||
f.limit = Math.ceil(f.count/2);
|
||||
f.count = 0;
|
||||
f.sub = Radix();
|
||||
Radix.map(rad, f.slice)
|
||||
Radix.map(rad, f.slice);
|
||||
return true;
|
||||
}
|
||||
f.text += enc;
|
||||
}
|
||||
f.write = function(){
|
||||
var tmp = ename(file);
|
||||
var start; LOG && (start = (+new Date)); // comment this out!
|
||||
opt.store.put(tmp, f.text, function(err){
|
||||
LOG && console.log("wrote JSON in", (+new Date) - start); // comment this out!
|
||||
if(err){ return cb(err) }
|
||||
r.list.add(tmp, cb);
|
||||
});
|
||||
@ -168,7 +184,7 @@
|
||||
var name = f.file;
|
||||
f.file = key;
|
||||
f.count = 0;
|
||||
r.write(name, f.sub, f.next, force);
|
||||
r.write(name, f.sub, f.next, o);
|
||||
return true;
|
||||
}
|
||||
f.sub(key, val);
|
||||
@ -177,51 +193,73 @@
|
||||
if(err){ return cb(err) }
|
||||
f.sub = Radix();
|
||||
if(!Radix.map(rad, f.slice)){
|
||||
r.write(f.file, f.sub, cb, force);
|
||||
r.write(f.file, f.sub, cb, o);
|
||||
}
|
||||
}
|
||||
if(opt.jsonify){ return r.write.jsonify(f, file, rad, cb, o) } // temporary testing idea
|
||||
if(!Radix.map(rad, f.each, true)){ f.write() }
|
||||
}
|
||||
|
||||
r.write.jsonify = function(f, file, rad, cb, o){
|
||||
var raw;
|
||||
var start; LOG && (start = (+new Date)); // comment this out!
|
||||
try{raw = JSON.stringify(rad.$);
|
||||
}catch(e){ return cb("Record too big!") }
|
||||
LOG && console.log("stringified JSON in", (+new Date) - start); // comment this out!
|
||||
if(opt.chunk < raw.length && !o.force){
|
||||
if(Radix.map(rad, f.each, true)){ return }
|
||||
}
|
||||
f.text = raw;
|
||||
f.write();
|
||||
}
|
||||
|
||||
;(function(){
|
||||
var Q = {};
|
||||
r.read = function(key, cb, next){
|
||||
if(RAD && !next){ // cache
|
||||
r.read = function(key, cb, o){
|
||||
o = o || {};
|
||||
if(RAD && !o.next){ // cache
|
||||
var val = RAD(key);
|
||||
if(u !== val){
|
||||
//if(u !== val){
|
||||
//cb(u, val, o);
|
||||
if(atomic(val)){ cb(u, val, o); return }
|
||||
// if a node is requested and some of it is cached... the other parts might not be.
|
||||
return cb(u, val);
|
||||
}
|
||||
//}
|
||||
}
|
||||
var g = function Get(){}, tmp;
|
||||
g.lex = function(file){
|
||||
file = (u === file)? u : decodeURIComponent(file);
|
||||
if(!file || file > (next || key)){
|
||||
if(next){ g.file = file }
|
||||
if(!file || file > (o.next || key)){
|
||||
if(o.next){ g.file = file }
|
||||
if(tmp = Q[g.file]){
|
||||
tmp.push({key: key, ack: cb, file: g.file});
|
||||
tmp.push({key: key, ack: cb, file: g.file, opt: o});
|
||||
return true;
|
||||
}
|
||||
Q[g.file] = [{key: key, ack: cb, file: g.file}];
|
||||
Q[g.file] = [{key: key, ack: cb, file: g.file, opt: o}];
|
||||
r.parse(g.file, g.it);
|
||||
return true;
|
||||
}
|
||||
g.file = file;
|
||||
}
|
||||
g.it = function(err, disk){
|
||||
g.it = function(err, disk, info){
|
||||
if(g.err = err){ opt.log('err', err) }
|
||||
g.info = info;
|
||||
if(disk){ RAD = g.disk = disk }
|
||||
disk = Q[g.file]; delete Q[g.file];
|
||||
map(disk, g.ack);
|
||||
}
|
||||
g.ack = function(as){
|
||||
if(!as.ack){ return }
|
||||
var tmp = as.key, rad = g.disk || noop, data = rad(tmp), last = rad.last;
|
||||
if(data){ as.ack(g.err, data) }
|
||||
else if(!as.file){ return as.ack(g.err, u) }
|
||||
if(!last || last === tmp){ return as.ack(g.err, u) } // is this correct?
|
||||
if(last > tmp && 0 > last.indexOf(tmp)){ return as.ack(g.err, u) }
|
||||
r.read(tmp, as.ack, as.file);
|
||||
var tmp = as.key, o = as.opt, info = g.info, rad = g.disk || noop, data = rad(tmp), last = rad.last;
|
||||
o.parsed = (o.parsed || 0) + (info.parsed||0);
|
||||
o.chunks = (o.chunks || 0) + 1;
|
||||
if(!o.some){ o.some = (u !== data) }
|
||||
if(u !== data){ as.ack(g.err, data, o) }
|
||||
else if(!as.file){ !o.some && as.ack(g.err, u, o); return }
|
||||
if(/*!last || */last === tmp){ !o.some && as.ack(g.err, u, o); return }
|
||||
if(last && last > tmp && 0 != last.indexOf(tmp)){ !o.some && as.ack(g.err, u, o); return }
|
||||
if(o.some && o.parsed >= o.limit){ return }
|
||||
o.next = as.file;
|
||||
r.read(tmp, as.ack, o);
|
||||
}
|
||||
r.list(g.lex);
|
||||
}
|
||||
@ -236,14 +274,13 @@
|
||||
Then we can work on the harder problem of being multi-process.
|
||||
*/
|
||||
var Q = {}, s = String.fromCharCode(31);
|
||||
r.parse = function(file, cb){ var q;
|
||||
r.parse = function(file, cb, raw){ var q;
|
||||
if(q = Q[file]){ return q.push(cb) } q = Q[file] = [cb];
|
||||
var p = function Parse(){};
|
||||
var p = function Parse(){}, info = {};
|
||||
p.disk = Radix();
|
||||
p.read = function(err, data){ var tmp;
|
||||
delete Q[file];
|
||||
if((p.err = err) || (p.not = !data)){
|
||||
//return cb(err, u);//map(q, p.ack);
|
||||
return map(q, p.ack);
|
||||
}
|
||||
if(typeof data !== 'string'){
|
||||
@ -251,12 +288,34 @@
|
||||
if(opt.pack <= data.length){
|
||||
p.err = "Chunk too big!";
|
||||
} else {
|
||||
data = data.toString();
|
||||
data = data.toString(); // If it crashes, it crashes here. How!?? We check size first!
|
||||
}
|
||||
}catch(e){ p.err = e }
|
||||
if(p.err){ return map(q, p.ack) }
|
||||
}
|
||||
info.parsed = data.length;
|
||||
|
||||
var start; LOG && (start = (+new Date)); // keep this commented out in production!
|
||||
if(opt.jsonify){ // temporary testing idea
|
||||
try{
|
||||
var json = JSON.parse(data);
|
||||
p.disk.$ = json;
|
||||
LOG && console.log('parsed JSON in', (+new Date) - start); // keep this commented out in production!
|
||||
map(q, p.ack);
|
||||
return;
|
||||
}catch(e){ tmp = e }
|
||||
if('{' === data[0]){
|
||||
p.err = tmp || "JSON error!";
|
||||
return map(q, p.ack);
|
||||
}
|
||||
}
|
||||
|
||||
var start; LOG && (start = (+new Date)); // keep this commented out in production!
|
||||
var tmp = p.split(data), pre = [], i, k, v;
|
||||
if(!tmp || 0 !== tmp[1]){
|
||||
p.err = "File '"+file+"' does not have root radix! ";
|
||||
return map(q, p.ack);
|
||||
}
|
||||
while(tmp){
|
||||
k = v = u;
|
||||
i = tmp[1];
|
||||
@ -274,6 +333,7 @@
|
||||
if(u !== k && u !== v){ p.disk(pre.join(''), v) }
|
||||
tmp = p.split(tmp[2]);
|
||||
}
|
||||
LOG && console.log('parsed JSON in', (+new Date) - start); // keep this commented out in production!
|
||||
//cb(err, p.disk);
|
||||
map(q, p.ack);
|
||||
};
|
||||
@ -290,9 +350,10 @@
|
||||
}
|
||||
p.ack = function(cb){
|
||||
if(!cb){ return }
|
||||
if(p.err || p.not){ return cb(p.err, u) }
|
||||
cb(u, p.disk);
|
||||
if(p.err || p.not){ return cb(p.err, u, info) }
|
||||
cb(u, p.disk, info);
|
||||
}
|
||||
if(raw){ return p.read(null, raw) }
|
||||
opt.store.get(ename(file), p.read);
|
||||
}
|
||||
}());
|
||||
@ -315,8 +376,11 @@
|
||||
return cb(u, 1);
|
||||
}
|
||||
dir(file, true);
|
||||
cb.listed = (cb.listed || 0) + 1;
|
||||
r.write(f, dir, function(err, ok){
|
||||
if(err){ return cb(err) }
|
||||
cb.listed = (cb.listed || 0) - 1;
|
||||
if(cb.listed !== 0){ return }
|
||||
cb(u, 1);
|
||||
}, true);
|
||||
}
|
||||
@ -353,6 +417,7 @@
|
||||
}());
|
||||
|
||||
var noop = function(){}, RAD, u;
|
||||
Radisk.has[opt.file] = r;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
53
lib/radix.js
53
lib/radix.js
@ -5,9 +5,9 @@
|
||||
key = ''+key;
|
||||
if(!t && u !== val){
|
||||
radix.last = (key < radix.last)? radix.last : key;
|
||||
radix.sort = null;
|
||||
delete (radix.$||{})[_];
|
||||
}
|
||||
t = t || radix[_] || (radix[_] = {});
|
||||
t = t || radix.$ || (radix.$ = {});
|
||||
var i = 0, l = key.length-1, k = key[i], at, tmp;
|
||||
while(!(at = t[k]) && i < l){
|
||||
k += key[++i];
|
||||
@ -15,9 +15,9 @@
|
||||
if(!at){
|
||||
if(!map(t, function(r, s){
|
||||
var ii = 0, kk = '';
|
||||
while(s[ii] == key[ii]){
|
||||
if((s||'').length){ while(s[ii] == key[ii]){
|
||||
kk += s[ii++];
|
||||
}
|
||||
} }
|
||||
if(kk){
|
||||
if(u === val){
|
||||
if(ii <= l){ return }
|
||||
@ -25,47 +25,52 @@
|
||||
}
|
||||
var __ = {};
|
||||
__[s.slice(ii)] = r;
|
||||
(__[key.slice(ii)] = {})[$] = val;
|
||||
(t[kk] = {})[_] = __;
|
||||
ii = key.slice(ii);
|
||||
('' === ii)? (__[''] = val) : ((__[ii] = {})[''] = val);
|
||||
t[kk] = __;
|
||||
delete t[s];
|
||||
return true;
|
||||
}
|
||||
})){
|
||||
if(u === val){ return; }
|
||||
(t[k] || (t[k] = {}))[$] = val;
|
||||
(t[k] || (t[k] = {}))[''] = val;
|
||||
}
|
||||
if(u === val){
|
||||
return tmp;
|
||||
}
|
||||
} else
|
||||
if(i == l){
|
||||
if(u === val){ return (u === (tmp = at[$]))? at[_] : tmp }
|
||||
at[$] = val;
|
||||
if(u === val){ return (u === (tmp = at['']))? at : tmp }
|
||||
at[''] = val;
|
||||
} else {
|
||||
if(u !== val){ at.sort = null }
|
||||
return radix(key.slice(++i), val, at[_] || (at[_] = {}));
|
||||
if(u !== val){ delete at[_] }
|
||||
return radix(key.slice(++i), val, at || (at = {}));
|
||||
}
|
||||
}
|
||||
return radix;
|
||||
};
|
||||
|
||||
Radix.map = function map(radix, cb, opt, pre){ pre = pre || [];
|
||||
var t = radix[_] || radix, keys = radix.sort || (radix.sort = Object.keys(t).sort()), i = 0, l = keys.length;
|
||||
for(;i < l; i++){ var key = keys[i], tree = t[key], tmp;
|
||||
if(u !== (tmp = tree[$])){
|
||||
tmp = cb(tmp, pre.join('') + key, key, pre);
|
||||
var t = ('function' == typeof radix)? radix.$ || {} : radix;
|
||||
if(!t){ return }
|
||||
var keys = (t[_]||no).sort || (t[_] = function $(){ $.sort = Object.keys(t).sort(); return $ }()).sort;
|
||||
//var keys = Object.keys(t).sort();
|
||||
var i = 0, l = keys.length;
|
||||
for(;i < l; i++){ var key = keys[i], tree = t[key], tmp, p;
|
||||
if(!tree || '' === key || _ === key){ continue }
|
||||
p = pre.slice(); p.push(key);
|
||||
if(u !== (tmp = tree[''])){
|
||||
tmp = cb(tmp, p.join(''), key, pre);
|
||||
if(u !== tmp){ return tmp }
|
||||
} else
|
||||
} else
|
||||
if(opt){
|
||||
cb(u, pre.join(''), key, pre);
|
||||
}
|
||||
if(tmp = tree[_]){
|
||||
pre.push(key);
|
||||
tmp = map(tree, cb, opt, pre);
|
||||
//tmp = map(tmp, cb, opt, pre);
|
||||
tmp = cb(u, pre.join(''), key, pre);
|
||||
if(u !== tmp){ return tmp }
|
||||
pre.pop();
|
||||
}
|
||||
pre = p;
|
||||
tmp = map(tree, cb, opt, pre);
|
||||
if(u !== tmp){ return tmp }
|
||||
pre.pop();
|
||||
}
|
||||
};
|
||||
|
||||
@ -80,6 +85,6 @@
|
||||
}
|
||||
|
||||
var map = Gun.obj.map, no = {}, u;
|
||||
var $ = String.fromCharCode(30), _ = String.fromCharCode(29);
|
||||
var _ = String.fromCharCode(24);
|
||||
|
||||
}());
|
@ -3,6 +3,7 @@ var Gun = (typeof window !== "undefined")? window.Gun : require('../gun');
|
||||
function Store(opt){
|
||||
opt = opt || {};
|
||||
opt.file = String(opt.file || 'radata');
|
||||
if(Gun.TESTING){ opt.file = 'radatatest' }
|
||||
var fs = require('fs'), u;
|
||||
var store = function Store(){};
|
||||
|
||||
|
142
lib/rindexed.js
142
lib/rindexed.js
@ -9,115 +9,47 @@
|
||||
function Store(opt){
|
||||
opt = opt || {};
|
||||
opt.file = String(opt.file || 'radata');
|
||||
var db = null;
|
||||
if(Gun.TESTING){ opt.file = 'radatatest' }
|
||||
opt.chunk = opt.chunk || (1024 * 1024); // 1MB
|
||||
var db = null, u;
|
||||
|
||||
opt.indexedDB = opt.indexedDB || window.indexedDB;
|
||||
// Initialize indexedDB. Version 1.
|
||||
var request = opt.indexedDB.open(opt.file, 1)
|
||||
try{opt.indexedDB = opt.indexedDB || indexedDB}catch(e){}
|
||||
try{if(!opt.indexedDB || 'file:' == location.protocol){
|
||||
var store = {}, s = {};
|
||||
store.put = function(f, d, cb){ s[f] = d; cb(null, 1) };
|
||||
store.get = function(f, cb){ cb(null, s[f] || u) };
|
||||
console.log('Warning: No indexedDB exists to persist data to!');
|
||||
return store;
|
||||
}}catch(e){}
|
||||
|
||||
var store = function Store(){};
|
||||
store.start = function(){
|
||||
var o = indexedDB.open(opt.file, 1);
|
||||
o.onupgradeneeded = function(eve){ (eve.target.result).createObjectStore(opt.file) }
|
||||
o.onsuccess = function(){ db = o.result }
|
||||
o.onerror = function(eve){ console.log(eve||1); }
|
||||
}; store.start();
|
||||
|
||||
// Create schema. onupgradeneeded is called only when DB is first created or when the DB version increases.
|
||||
request.onupgradeneeded = function(event){
|
||||
var db = event.target.result;
|
||||
db.createObjectStore(opt.file);
|
||||
store.put = function(key, data, cb){
|
||||
if(!db){ setTimeout(function(){ store.put(key, data, cb) },1); return }
|
||||
var tx = db.transaction([opt.file], 'readwrite');
|
||||
var obj = tx.objectStore(opt.file);
|
||||
var req = obj.put(data, ''+key);
|
||||
req.onsuccess = obj.onsuccess = tx.onsuccess = function(){ cb(null, 1) }
|
||||
req.onabort = obj.onabort = tx.onabort = function(eve){ cb(eve||'put.tx.abort') }
|
||||
req.onerror = obj.onerror = tx.onerror = function(eve){ cb(eve||'put.tx.error') }
|
||||
}
|
||||
|
||||
// onsuccess is called when the DB is ready.
|
||||
request.onsuccess = function(){
|
||||
db = request.result;
|
||||
store.get = function(key, cb){
|
||||
if(!db){ setTimeout(function(){ store.get(key, cb) },9); return }
|
||||
var tx = db.transaction([opt.file], 'readonly');
|
||||
var obj = tx.objectStore(opt.file);
|
||||
var req = obj.get(''+key);
|
||||
req.onsuccess = function(){ cb(null, req.result) }
|
||||
req.onabort = function(eve){ cb(eve||4) }
|
||||
req.onerror = function(eve){ cb(eve||5) }
|
||||
}
|
||||
|
||||
request.onerror = function(event){
|
||||
console.log('ERROR: RAD IndexedDB generic error:', event);
|
||||
};
|
||||
|
||||
var store = function Store(){}, u;
|
||||
|
||||
store.put = function(file, data, cb){
|
||||
cb = cb || function(){};
|
||||
var doPut = function(){
|
||||
// Start a transaction. The transaction will be automaticallt closed when the last success/error handler took no new action.
|
||||
var transaction = db.transaction([opt.file], 'readwrite');
|
||||
|
||||
// Add or update data.
|
||||
var radStore = transaction.objectStore(opt.file);
|
||||
var putRequest = radStore.put(data, file);
|
||||
putRequest.onsuccess = radStore.onsuccess = transaction.onsuccess = function(){
|
||||
//console.log('RAD IndexedDB put transaction was succesful.');
|
||||
cb(null, 1);
|
||||
};
|
||||
putRequest.onabort = radStore.onabort = transaction.onabort = function(){
|
||||
var es = 'ERROR: RAD IndexedDB put transaction was aborted.';
|
||||
console.log(es);
|
||||
cb(es, undefined);
|
||||
};
|
||||
putRequest.onerror = radStore.onerror = transaction.onerror = function(event){
|
||||
var es = 'ERROR: RAD IndexedDB put transaction was in error: ' + JSON.stringify(event)
|
||||
console.log(es);
|
||||
cb(es, undefined);
|
||||
};
|
||||
}
|
||||
if(!db){
|
||||
waitDbReady(doPut, 100, function(){
|
||||
var es = 'ERROR: Timeout: RAD IndexedDB not ready.';
|
||||
console.log(es);
|
||||
cb(es, undefined);
|
||||
}, 10)
|
||||
} else {
|
||||
doPut();
|
||||
}
|
||||
};
|
||||
|
||||
store.get = function(file, cb){
|
||||
cb = cb || function(){};
|
||||
var doGet = function(){
|
||||
// Start a transaction. The transaction will be automaticallt closed when the last success/error handler took no new action.
|
||||
var transaction = db.transaction([opt.file], 'readwrite');
|
||||
|
||||
// Read data.
|
||||
var radStore = transaction.objectStore(opt.file);
|
||||
var getRequest = radStore.get(file);
|
||||
getRequest.onsuccess = function(){
|
||||
//console.log('RAD IndexedDB get transaction was succesful.');
|
||||
cb(null, getRequest.result);
|
||||
};
|
||||
getRequest.onabort = function(){
|
||||
var es = 'ERROR: RAD IndexedDB get transaction was aborted.';
|
||||
console.log(es);
|
||||
cb(es, undefined);
|
||||
};
|
||||
getRequest.onerror = function(event){
|
||||
var es = 'ERROR: RAD IndexedDB get transaction was in error: ' + JSON.stringify(event)
|
||||
console.log(es);
|
||||
cb(es, undefined);
|
||||
};
|
||||
}
|
||||
if(!db){
|
||||
waitDbReady(doGet, 100, function(){
|
||||
var es = 'ERROR: Timeout: RAD IndexedDB not ready.';
|
||||
console.log(es);
|
||||
cb(es, undefined);
|
||||
}, 10)
|
||||
} else {
|
||||
doGet();
|
||||
}
|
||||
};
|
||||
|
||||
var waitDbReady = function(readyFunc, checkInterval, timeoutFunc, timeoutSecs){
|
||||
var startTime = new Date();
|
||||
var checkFunc = function(){
|
||||
if(db){
|
||||
readyFunc();
|
||||
} else {
|
||||
if((new Date() - startTime) / 1000 >= timeoutSecs){
|
||||
timeoutFunc();
|
||||
} else {
|
||||
setTimeout(checkFunc, checkInterval);
|
||||
}
|
||||
}
|
||||
};
|
||||
checkFunc();
|
||||
};
|
||||
|
||||
setInterval(function(){ db && db.close(); db = null; store.start() }, 1000 * 15); // reset webkit bug?
|
||||
return store;
|
||||
}
|
||||
|
||||
@ -126,4 +58,4 @@
|
||||
} else {
|
||||
module.exports = Store;
|
||||
}
|
||||
}());
|
||||
}());
|
27
lib/rls.js
Normal file
27
lib/rls.js
Normal file
@ -0,0 +1,27 @@
|
||||
;(function(){
|
||||
var Gun = (typeof window !== "undefined")? window.Gun : require('../gun');
|
||||
|
||||
Gun.on('create', function(root){
|
||||
this.to.next(root);
|
||||
root.opt.store = root.opt.store || Store(root.opt);
|
||||
});
|
||||
|
||||
function Store(opt){
|
||||
opt = opt || {};
|
||||
opt.file = String(opt.file || 'radata');
|
||||
if(Gun.TESTING){ opt.file = 'radatatest' }
|
||||
var store = function Store(){};
|
||||
|
||||
var ls = localStorage;
|
||||
store.put = function(key, data, cb){ ls[''+key] = data; cb(null, 1) }
|
||||
store.get = function(key, cb){ cb(null, ls[''+key]) }
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
if(Gun.window){
|
||||
Gun.window.RlocalStorage = Store;
|
||||
} else {
|
||||
module.exports = Store;
|
||||
}
|
||||
}());
|
@ -8,8 +8,8 @@ Gun.on('create', function(root){
|
||||
this.to.next(root);
|
||||
var opt = root.opt;
|
||||
if(!process.env.AWS_S3_BUCKET){ return }
|
||||
opt.batch = opt.batch || (1000 * 1);
|
||||
opt.until = opt.until || (1000 * 15);
|
||||
opt.batch = opt.batch || (1000 * 10);
|
||||
opt.until = opt.until || (1000 * 3);
|
||||
opt.chunk = opt.chunk || (1024 * 1024 * 10); // 10MB
|
||||
|
||||
try{AWS = require('aws-sdk');
|
||||
|
138
lib/store.js
138
lib/store.js
@ -1,58 +1,86 @@
|
||||
var Gun = (typeof window !== "undefined")? window.Gun : require('../gun');
|
||||
|
||||
|
||||
Gun.on('create', function(root){
|
||||
this.to.next(root);
|
||||
var opt = root.opt, u;
|
||||
if(false === opt.radisk){ return }
|
||||
var Radisk = (Gun.window && Gun.window.Radisk) || require('./radisk');
|
||||
var Radix = Radisk.Radix;
|
||||
|
||||
opt.store = opt.store || (!Gun.window && require('./rfs')(opt));
|
||||
var rad = Radisk(opt), esc = String.fromCharCode(27);
|
||||
|
||||
root.on('put', function(msg){
|
||||
this.to.next(msg);
|
||||
var id = msg['#'], track = !msg['@'], acks = track? 0 : u; // only ack non-acks.
|
||||
if(msg.rad && !track){ return } // don't save our own acks
|
||||
Gun.graph.is(msg.put, null, function(val, key, node, soul){
|
||||
if(track){ ++acks }
|
||||
val = Radisk.encode(val, null, esc)+'>'+Radisk.encode(Gun.state.is(node, key), null, esc);
|
||||
rad(soul+'.'+key, val, (track? ack : u));
|
||||
});
|
||||
function ack(err, ok){
|
||||
acks--;
|
||||
if(ack.err){ return }
|
||||
if(ack.err = err){
|
||||
root.on('in', {'@': id, err: err});
|
||||
return;
|
||||
}
|
||||
if(acks){ return }
|
||||
root.on('in', {'@': id, ok: 1});
|
||||
}
|
||||
});
|
||||
|
||||
root.on('get', function(msg){
|
||||
this.to.next(msg);
|
||||
var id = msg['#'], soul = msg.get['#'], key = msg.get['.']||'', tmp = soul+'.'+key, node;
|
||||
rad(tmp, function(err, val){
|
||||
if(val){
|
||||
if(val && typeof val !== 'string'){
|
||||
if(key){
|
||||
val = u;
|
||||
} else {
|
||||
Radix.map(val, each)
|
||||
}
|
||||
}
|
||||
if(!node && val){ each(val, key) }
|
||||
}
|
||||
root.on('in', {'@': id, put: Gun.graph.node(node), err: err? err : u, rad: Radix});
|
||||
});
|
||||
function each(val, key){
|
||||
tmp = val.lastIndexOf('>');
|
||||
var state = Radisk.decode(val.slice(tmp+1), null, esc);
|
||||
val = Radisk.decode(val.slice(0,tmp), null, esc);
|
||||
node = Gun.state.ify(node, key, state, val, soul);
|
||||
}
|
||||
});
|
||||
|
||||
this.to.next(root);
|
||||
var opt = root.opt, u;
|
||||
if(false === opt.radisk){ return }
|
||||
var Radisk = (Gun.window && Gun.window.Radisk) || require('./radisk');
|
||||
var Radix = Radisk.Radix;
|
||||
|
||||
opt.store = opt.store || (!Gun.window && require('./rfs')(opt));
|
||||
var rad = Radisk(opt), esc = String.fromCharCode(27);
|
||||
|
||||
root.on('put', function(msg){
|
||||
this.to.next(msg);
|
||||
var id = msg['#'] || Gun.text.random(3), track = !msg['@'], acks = track? 0 : u; // only ack non-acks.
|
||||
if(msg.rad && !track){ return } // don't save our own acks
|
||||
Gun.graph.is(msg.put, null, function(val, key, node, soul){
|
||||
if(track){ ++acks }
|
||||
//console.log('put:', soul, key, val);
|
||||
val = Radisk.encode(val, null, esc)+'>'+Radisk.encode(Gun.state.is(node, key), null, esc);
|
||||
rad(soul+esc+key, val, (track? ack : u));
|
||||
});
|
||||
function ack(err, ok){
|
||||
acks--;
|
||||
if(ack.err){ return }
|
||||
if(ack.err = err){
|
||||
root.on('in', {'@': id, err: err});
|
||||
return;
|
||||
}
|
||||
if(acks){ return }
|
||||
//console.log("PAT!", id);
|
||||
root.on('in', {'@': id, ok: 1});
|
||||
}
|
||||
});
|
||||
|
||||
root.on('get', function(msg){
|
||||
this.to.next(msg);
|
||||
var id = msg['#'], get = msg.get, soul = msg.get['#'], has = msg.get['.']||'', opt = {}, graph, lex, key, tmp;
|
||||
if(typeof soul == 'string'){
|
||||
key = soul;
|
||||
} else
|
||||
if(soul){
|
||||
if(tmp = soul['*']){ opt.limit = 1 }
|
||||
key = tmp || soul['='];
|
||||
}
|
||||
if(key && !opt.limit){ // a soul.has must be on a soul, and not during soul*
|
||||
if(typeof has == 'string'){
|
||||
key = key+esc+(opt.atom = has);
|
||||
} else
|
||||
if(has){
|
||||
if(tmp = has['*']){ opt.limit = 1 }
|
||||
if(key){ key = key+esc + (tmp || (opt.atom = has['='])) }
|
||||
}
|
||||
}
|
||||
if((tmp = get['%']) || opt.limit){
|
||||
opt.limit = (tmp <= (opt.pack || (1000 * 100)))? tmp : 1;
|
||||
}
|
||||
//var start = (+new Date); // console.log("GET!", id, JSON.stringify(key));
|
||||
rad(key||'', function(err, data, o){
|
||||
if(data){
|
||||
if(typeof data !== 'string'){
|
||||
if(opt.atom){
|
||||
data = u;
|
||||
} else {
|
||||
Radix.map(data, each)
|
||||
}
|
||||
}
|
||||
if(!graph && data){ each(data, '') }
|
||||
}
|
||||
//console.log("GOT!", id, JSON.stringify(key), ((+new Date) - start));
|
||||
root.on('in', {'@': id, put: graph, err: err? err : u, rad: Radix});
|
||||
}, opt);
|
||||
function each(val, has, a,b){
|
||||
if(!val){ return }
|
||||
has = (key+has).split(esc);
|
||||
var soul = has.slice(0,1)[0];
|
||||
has = has.slice(-1)[0];
|
||||
opt.count = (opt.count || 0) + val.length;
|
||||
tmp = val.lastIndexOf('>');
|
||||
var state = Radisk.decode(val.slice(tmp+1), null, esc);
|
||||
val = Radisk.decode(val.slice(0,tmp), null, esc);
|
||||
(graph = graph || {})[soul] = Gun.state.ify(graph[soul], has, state, val, soul);
|
||||
if(opt.limit && opt.limit <= opt.count){ return true }
|
||||
}
|
||||
});
|
||||
});
|
@ -11,19 +11,7 @@ var write = function(path, data){
|
||||
return fs.writeFileSync(nodePath.join(dir, path), data);
|
||||
}
|
||||
|
||||
var rm = function(path, full) {
|
||||
path = full || nodePath.join(dir, path);
|
||||
if(!fs.existsSync(path)){ return }
|
||||
fs.readdirSync(path).forEach(function(file,index){
|
||||
var curPath = path + "/" + file;
|
||||
if(fs.lstatSync(curPath).isDirectory()) { // recurse
|
||||
rm(null, curPath);
|
||||
} else { // delete file
|
||||
fs.unlinkSync(curPath);
|
||||
}
|
||||
});
|
||||
fs.rmdirSync(path);
|
||||
};
|
||||
var rm = require('./fsrm');
|
||||
|
||||
var mk = function(path){
|
||||
path = nodePath.join(dir, path);
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "gun",
|
||||
"version": "0.9.9999991",
|
||||
"version": "0.2019.331",
|
||||
"description": "A realtime, decentralized, offline-first, graph data synchronization engine.",
|
||||
"main": "index.js",
|
||||
"browser": "gun.min.js",
|
||||
"browser": "gun.js",
|
||||
"scripts": {
|
||||
"start": "node examples/http.js 8765",
|
||||
"https": "HTTPS_KEY=test/https/server.key HTTPS_CERT=test/https/server.crt npm start",
|
||||
@ -13,7 +13,8 @@
|
||||
"testaxe": "mocha test/axe/holy-grail.js",
|
||||
"e2e": "mocha e2e/distributed.js",
|
||||
"docker": "hooks/build",
|
||||
"unbuild": "node lib/unbuild.js && uglifyjs gun.js -o gun.min.js -c -m"
|
||||
"minify": "uglifyjs gun.js -o gun.min.js -c -m",
|
||||
"unbuild": "node lib/unbuild.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
2
sea.js
2
sea.js
@ -510,7 +510,7 @@
|
||||
key = pair.epriv || pair;
|
||||
}
|
||||
var msg = (typeof data == 'string')? data : JSON.stringify(data);
|
||||
var rand = {s: shim.random(8), iv: shim.random(16)};
|
||||
var rand = {s: shim.random(9), iv: shim.random(15)}; // consider making this 9 and 15 or 18 or 12 to reduce == padding.
|
||||
var ct = await aeskey(key, rand.s, opt).then((aes) => (/*shim.ossl ||*/ shim.subtle).encrypt({ // Keeping the AES key scope as private as possible...
|
||||
name: opt.name || 'AES-GCM', iv: new Uint8Array(rand.iv)
|
||||
}, aes, new shim.TextEncoder().encode(msg)));
|
||||
|
26
src/chain.js
26
src/chain.js
@ -23,6 +23,7 @@ function output(msg){
|
||||
at.on('in', at);
|
||||
return;
|
||||
}*/
|
||||
if(at.lex){ msg.get = obj_to(at.lex, msg.get) }
|
||||
if(get['#'] || at.soul){
|
||||
get['#'] = get['#'] || at.soul;
|
||||
msg['#'] || (msg['#'] = text_rand(9));
|
||||
@ -45,6 +46,17 @@ function output(msg){
|
||||
get: back.get
|
||||
});
|
||||
if(tmp){ return }
|
||||
} else
|
||||
if('string' != typeof get){
|
||||
var put = {}, meta = (back.put||{})._;
|
||||
Gun.obj.map(back.put, function(v,k){
|
||||
if(!Gun.text.match(k, get)){ return }
|
||||
put[k] = v;
|
||||
})
|
||||
if(!Gun.obj.empty(put)){
|
||||
put._ = meta;
|
||||
back.on('in', {$: back.$, put: put, get: back.get})
|
||||
}
|
||||
}
|
||||
root.ask(ack, msg);
|
||||
return root.on('in', msg);
|
||||
@ -144,7 +156,6 @@ function input(msg){
|
||||
relate(cat, msg, at, rel);
|
||||
echo(cat, msg, eve);
|
||||
}
|
||||
var C = 0;
|
||||
|
||||
function relate(at, msg, from, rel){
|
||||
if(!rel || node_ === at.get){ return }
|
||||
@ -190,11 +201,11 @@ function map(data, key){ // Map over only the changes on every update.
|
||||
if(!(at = next[key])){
|
||||
return;
|
||||
}
|
||||
//if(data && data[_soul] && (tmp = Gun.val.rel.is(data)) && (tmp = (cat.root.$.get(tmp)._)) && obj_has(tmp, 'put')){
|
||||
//if(data && data[_soul] && (tmp = Gun.val.link.is(data)) && (tmp = (cat.root.$.get(tmp)._)) && obj_has(tmp, 'put')){
|
||||
// data = tmp.put;
|
||||
//}
|
||||
if(at.has){
|
||||
//if(!(data && data[_soul] && Gun.val.rel.is(data) === Gun.node.soul(at.put))){
|
||||
//if(!(data && data[_soul] && Gun.val.link.is(data) === Gun.node.soul(at.put))){
|
||||
if(u === at.put || !Gun.val.link.is(data)){
|
||||
at.put = data;
|
||||
}
|
||||
@ -217,7 +228,10 @@ function not(at, msg){
|
||||
if(!(at.has || at.soul)){ return }
|
||||
var tmp = at.map, root = at.root;
|
||||
at.map = null;
|
||||
if(at.has){ at.link = null }
|
||||
if(at.has){
|
||||
if(at.dub && at.root.stop){ at.dub = null }
|
||||
at.link = null;
|
||||
}
|
||||
//if(!root.now || !root.now[at.id]){
|
||||
if(!at.pass){
|
||||
if((!msg['@']) && null === tmp){ return }
|
||||
@ -257,7 +271,7 @@ function ask(at, soul){
|
||||
function ack(msg, ev){
|
||||
var as = this.as, get = as.get || empty, at = as.$._, tmp = (msg.put||empty)[get['#']];
|
||||
if(at.ack){ at.ack = (at.ack + 1) || 1; }
|
||||
if(!msg.put || (get['.'] && !obj_has(tmp, at.get))){
|
||||
if(!msg.put || ('string' == typeof get['.'] && !obj_has(tmp, at.get))){
|
||||
if(at.put !== u){ return }
|
||||
at.on('in', {
|
||||
get: at.get,
|
||||
@ -276,5 +290,5 @@ function ack(msg, ev){
|
||||
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;
|
||||
var text_rand = Gun.text.random;
|
||||
var _soul = Gun.val.rel._, node_ = Gun.node._;
|
||||
var _soul = Gun.val.link._, node_ = Gun.node._;
|
||||
|
11
src/get.js
11
src/get.js
@ -32,12 +32,18 @@ Gun.chain.get = function(key, cb, as){
|
||||
} else
|
||||
if(tmp = rel.is(key)){
|
||||
return this.get(tmp, cb, as);
|
||||
} else
|
||||
if(obj.is(key)){
|
||||
gun = this;
|
||||
if(tmp = ((tmp = key['#'])||empty)['='] || tmp){ gun = gun.get(tmp) }
|
||||
gun._.lex = key;
|
||||
return gun;
|
||||
} else {
|
||||
(as = this.chain())._.err = {err: Gun.log('Invalid get request!', key)}; // CLEAN UP
|
||||
if(cb){ cb.call(as, as._.err) }
|
||||
return as;
|
||||
}
|
||||
if(tmp = cat.stun){ // TODO: Refactor?
|
||||
if(tmp = this._.stun){ // TODO: Refactor?
|
||||
gun._.stun = gun._.stun || tmp;
|
||||
}
|
||||
if(cb && cb instanceof Function){
|
||||
@ -62,8 +68,7 @@ function cache(key, back){
|
||||
}
|
||||
function soul(gun, cb, opt, as){
|
||||
var cat = gun._, acks = 0, tmp;
|
||||
if(tmp = cat.soul){ return cb(tmp, as, cat), gun }
|
||||
if(tmp = cat.link){ return cb(tmp, as, cat), gun }
|
||||
if(tmp = cat.soul || cat.link || cat.dub){ return cb(tmp, as, cat), gun }
|
||||
gun.get(function(msg, ev){
|
||||
if(u === msg.put && (tmp = (obj_map(cat.root.opt.peers, function(v,k,t){t(k)})||[]).length) && ++acks < tmp){
|
||||
return;
|
||||
|
26
src/graph.js
26
src/graph.js
@ -31,7 +31,7 @@ var Graph = {};
|
||||
env.map = env;
|
||||
}
|
||||
if(env.soul){
|
||||
at.rel = Val.rel.ify(env.soul);
|
||||
at.link = Val.link.ify(env.soul);
|
||||
}
|
||||
env.shell = (as||{}).shell;
|
||||
env.graph = env.graph || {};
|
||||
@ -46,16 +46,16 @@ var Graph = {};
|
||||
at.env = env;
|
||||
at.soul = soul;
|
||||
if(Node.ify(at.obj, map, at)){
|
||||
at.rel = at.rel || Val.rel.ify(Node.soul(at.node));
|
||||
at.link = at.link || Val.link.ify(Node.soul(at.node));
|
||||
if(at.obj !== env.shell){
|
||||
env.graph[Val.rel.is(at.rel)] = at.node;
|
||||
env.graph[Val.link.is(at.link)] = at.node;
|
||||
}
|
||||
}
|
||||
return at;
|
||||
}
|
||||
function map(v,k,n){
|
||||
var at = this, env = at.env, is, tmp;
|
||||
if(Node._ === k && obj_has(v,Val.rel._)){
|
||||
if(Node._ === k && obj_has(v,Val.link._)){
|
||||
return n._; // TODO: Bug?
|
||||
}
|
||||
if(!(is = valid(v,k,n, at,env))){ return }
|
||||
@ -64,8 +64,8 @@ var Graph = {};
|
||||
if(obj_has(v, Node._) && Node.soul(v)){ // ? for safety ?
|
||||
at.node._ = obj_copy(v._);
|
||||
}
|
||||
at.node = Node.soul.ify(at.node, Val.rel.is(at.rel));
|
||||
at.rel = at.rel || Val.rel.ify(Node.soul(at.node));
|
||||
at.node = Node.soul.ify(at.node, Val.link.is(at.link));
|
||||
at.link = at.link || Val.link.ify(Node.soul(at.node));
|
||||
}
|
||||
if(tmp = env.map){
|
||||
tmp.call(env.as || {}, v,k,n, at);
|
||||
@ -84,14 +84,14 @@ var Graph = {};
|
||||
}
|
||||
tmp = node(env, {obj: v, path: at.path.concat(k)});
|
||||
if(!tmp.node){ return }
|
||||
return tmp.rel; //{'#': Node.soul(tmp.node)};
|
||||
return tmp.link; //{'#': Node.soul(tmp.node)};
|
||||
}
|
||||
function soul(id){ var at = this;
|
||||
var prev = Val.link.is(at.rel), graph = at.env.graph;
|
||||
at.rel = at.rel || Val.rel.ify(id);
|
||||
at.rel[Val.rel._] = id;
|
||||
var prev = Val.link.is(at.link), graph = at.env.graph;
|
||||
at.link = at.link || Val.link.ify(id);
|
||||
at.link[Val.link._] = id;
|
||||
if(at.node && at.node[Node._]){
|
||||
at.node[Node._][Val.rel._] = id;
|
||||
at.node[Node._][Val.link._] = id;
|
||||
}
|
||||
if(obj_has(graph, prev)){
|
||||
graph[id] = graph[prev];
|
||||
@ -131,13 +131,13 @@ Graph.node = function(node){
|
||||
}
|
||||
function map(v,k){ var tmp, obj;
|
||||
if(Node._ === k){
|
||||
if(obj_empty(v, Val.rel._)){
|
||||
if(obj_empty(v, Val.link._)){
|
||||
return;
|
||||
}
|
||||
this.obj[k] = obj_copy(v);
|
||||
return;
|
||||
}
|
||||
if(!(tmp = Val.rel.is(v))){
|
||||
if(!(tmp = Val.link.is(v))){
|
||||
this.obj[k] = v;
|
||||
return;
|
||||
}
|
||||
|
@ -28,8 +28,9 @@ function map(msg){
|
||||
}
|
||||
function each(v,k){
|
||||
if(n_ === k){ return }
|
||||
var msg = this.msg, gun = msg.$, at = this.at, tmp = (gun.get(k)._);
|
||||
(tmp.echo || (tmp.echo = {}))[at.id] = tmp.echo[at.id] || at;
|
||||
var msg = this.msg, gun = msg.$, at = gun._, cat = this.at, tmp = at.lex;
|
||||
if(tmp && !Gun.text.match(k, tmp['.'] || tmp['#'] || tmp)){ return } // TODO: Ugly hack!
|
||||
((tmp = gun.get(k)._).echo || (tmp.echo = {}))[cat.id] = tmp.echo[cat.id] || cat;
|
||||
}
|
||||
var obj_map = Gun.obj.map, noop = function(){}, event = {stun: noop, off: noop}, n_ = Gun.node._, u;
|
||||
|
@ -75,6 +75,7 @@ Gun.chain.once = function(cb, opt){
|
||||
}
|
||||
|
||||
function val(msg, eve, to){
|
||||
if(!msg.$){ eve.off(); return }
|
||||
var opt = this.as, cat = opt.at, gun = msg.$, at = gun._, data = at.put || msg.put, link, tmp;
|
||||
if(tmp = msg.$$){
|
||||
link = tmp = (msg.$$._);
|
||||
|
23
src/put.js
23
src/put.js
@ -4,7 +4,18 @@ 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!
|
||||
var gun = this, at = (gun._), root = at.root.$, tmp;
|
||||
var gun = this, at = (gun._), root = at.root.$, ctx = root._, M = 100, tmp;
|
||||
if(!ctx.puta){ 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;
|
||||
@ -40,10 +51,11 @@ Gun.chain.put = function(data, cb, as){
|
||||
if(!soul && Gun.val.is(msg.put)){
|
||||
return Gun.log("The reference you are saving is a", typeof msg.put, '"'+ msg.put +'", not a node (object)!');
|
||||
}
|
||||
gun.put(Gun.val.rel.ify(soul), cb, as);
|
||||
gun.put(Gun.val.link.ify(soul), cb, as);
|
||||
}, true);
|
||||
return gun;
|
||||
}
|
||||
if(at.has && (tmp = Gun.val.link.is(data))){ at.dub = tmp }
|
||||
as.ref = as.ref || (root._ === (tmp = at.back))? gun : tmp.$;
|
||||
if(as.ref._.soul && Gun.val.is(as.data) && at.get){
|
||||
as.data = obj_put({}, at.get, as.data);
|
||||
@ -98,7 +110,9 @@ function batch(){ var as = this;
|
||||
if(!ack.lack){ this.off() } // One response is good enough for us currently. Later we may want to adjust this.
|
||||
if(!as.ack){ return }
|
||||
as.ack(ack, this);
|
||||
//--C;
|
||||
}, as.opt);
|
||||
//C++;
|
||||
// NOW is a hack to get synchronous replies to correctly call.
|
||||
// and STOP is a hack to get async behavior to correctly call.
|
||||
// neither of these are ideal, need to be fixed without hacks,
|
||||
@ -113,6 +127,7 @@ function batch(){ var as = this;
|
||||
}, as);
|
||||
if(as.res){ as.res() }
|
||||
} function no(v,k){ if(v){ return true } }
|
||||
//console.debug(999,1); var C = 0; setInterval(function(){ try{ debug.innerHTML = C }catch(e){console.log(e)} }, 500);
|
||||
|
||||
function map(v,k,n, at){ var as = this;
|
||||
var is = Gun.is(v);
|
||||
@ -139,7 +154,7 @@ function map(v,k,n, at){ var as = this;
|
||||
function soul(id, as, msg, eve){
|
||||
var as = as.as, cat = as.at; as = as.as;
|
||||
var at = ((msg || {}).$ || {})._ || {};
|
||||
id = at.dub = at.dub || id || Gun.node.soul(cat.obj) || Gun.node.soul(msg.put || at.put) || Gun.val.rel.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) || (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?
|
||||
if(eve){ eve.stun = true }
|
||||
if(!id){ // polyfill async uuid for SEA
|
||||
at.via.back('opt.uuid')(function(err, id){ // TODO: improve perf without anonymous callback
|
||||
@ -198,7 +213,7 @@ function any(soul, as, msg, eve){
|
||||
if(node_ == at.get){
|
||||
as.soul = (at.put||empty)['#'] || at.dub;
|
||||
}
|
||||
as.soul = as.soul || at.soul || at.soul || (opt.uuid || as.via.back('opt.uuid') || Gun.text.random)();
|
||||
as.soul = as.soul || at.soul || at.link || (opt.uuid || as.via.back('opt.uuid') || Gun.text.random)();
|
||||
}
|
||||
if(!as.soul){ // polyfill async uuid for SEA
|
||||
as.via.back('opt.uuid')(function(err, soul){ // TODO: improve perf without anonymous callback
|
||||
|
20
src/root.js
20
src/root.js
@ -153,25 +153,9 @@ Gun.dup = require('./dup');
|
||||
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];
|
||||
if(obj_has(soul, '*')){ // TEMPORARY HACK FOR MARTTI, TESTING
|
||||
var graph = {};
|
||||
Gun.obj.map(root.graph, function(node, s){
|
||||
if(Gun.text.match(s, soul)){
|
||||
graph[s] = Gun.obj.copy(node);
|
||||
}
|
||||
});
|
||||
if(!Gun.obj.empty(graph)){
|
||||
root.on('in', {
|
||||
'@': msg['#'],
|
||||
how: '*',
|
||||
put: graph,
|
||||
$: gun
|
||||
});
|
||||
}
|
||||
} // TEMPORARY HACK FOR MARTTI, TESTING
|
||||
if(!node){ return root.on('get', msg) }
|
||||
if(has){
|
||||
if(!obj_has(node, has)){ return root.on('get', msg) }
|
||||
if('string' != typeof has || !obj_has(node, has)){ return root.on('get', msg) }
|
||||
node = Gun.state.to(node, has);
|
||||
// If we have a key in-memory, do we really need to fetch?
|
||||
// Maybe... in case the in-memory key we have is a local write
|
||||
@ -217,7 +201,7 @@ Gun.dup = require('./dup');
|
||||
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.rel._, _has = '.', node_ = Gun.node._, rel_is = Gun.val.link.is;
|
||||
var state_lex = Gun.state.lex, _soul = Gun.val.link._, _has = '.', node_ = Gun.node._, rel_is = Gun.val.link.is;
|
||||
var empty = {}, u;
|
||||
|
||||
console.debug = function(i, s){ return (console.debug.i && i === console.debug.i && console.debug.i++) && (console.log.apply(console, arguments) || s) };
|
||||
|
@ -10,11 +10,11 @@ Val.is = function(v){ // Valid values are a subset of JSON: null, binary, number
|
||||
|| num_is(v)){ // by "number" we mean integers or decimals.
|
||||
return true; // simple values are valid.
|
||||
}
|
||||
return Val.rel.is(v) || false; // is the value a soul relation? Then it is valid and return it. If not, everything else remaining is an invalid data type. Custom extensions can be built on top of these primitives to support other types.
|
||||
return Val.link.is(v) || false; // is the value a soul relation? Then it is valid and return it. If not, everything else remaining is an invalid data type. Custom extensions can be built on top of these primitives to support other types.
|
||||
}
|
||||
Val.link = Val.rel = {_: '#'};
|
||||
;(function(){
|
||||
Val.rel.is = function(v){ // this defines whether an object is a soul relation or not, they look like this: {'#': 'UUID'}
|
||||
Val.link.is = function(v){ // this defines whether an object is a soul relation or not, they look like this: {'#': 'UUID'}
|
||||
if(v && v[rel_] && !v._ && obj_is(v)){ // must be an object.
|
||||
var o = {};
|
||||
obj_map(v, map, o);
|
||||
@ -33,7 +33,7 @@ Val.link = Val.rel = {_: '#'};
|
||||
}
|
||||
}
|
||||
}());
|
||||
Val.rel.ify = function(t){ return obj_put({}, rel_, t) } // convert a soul into a relation and return it.
|
||||
Val.link.ify = function(t){ return obj_put({}, rel_, t) } // convert a soul into a relation and return it.
|
||||
Type.obj.has._ = '.';
|
||||
var rel_ = Val.link._, u;
|
||||
var bi_is = Type.bi.is;
|
||||
|
@ -1,5 +1,4 @@
|
||||
describe('Gun', function(){
|
||||
|
||||
var root;
|
||||
(function(){
|
||||
var env;
|
||||
@ -8,6 +7,7 @@ describe('Gun', function(){
|
||||
root = env.window? env.window : global;
|
||||
try{ env.window && root.localStorage && root.localStorage.clear() }catch(e){}
|
||||
try{ require('fs').unlinkSync('data.json') }catch(e){}
|
||||
try{ require('../lib/fsrm')('radatatest') }catch(e){}
|
||||
//root.Gun = root.Gun || require('../gun');
|
||||
if(root.Gun){
|
||||
root.Gun = root.Gun;
|
||||
@ -19,6 +19,7 @@ describe('Gun', function(){
|
||||
//require('../lib/file');
|
||||
require('../lib/store');
|
||||
require('../lib/rfs');
|
||||
require('./rad/rad.js');
|
||||
require('./sea/sea.js');
|
||||
}
|
||||
}(this));
|
||||
@ -613,6 +614,7 @@ describe('Gun', function(){
|
||||
});
|
||||
describe('Gun Safety', function(){
|
||||
/* WARNING NOTE: Internal API has significant breaking changes! */
|
||||
|
||||
var gun = Gun();
|
||||
it('is',function(){
|
||||
expect(Gun.is(gun)).to.be(true);
|
||||
@ -3048,7 +3050,7 @@ describe('Gun', function(){
|
||||
});
|
||||
|
||||
it('get put get get put reload get get then get', function(done){
|
||||
this.timeout(6000);
|
||||
this.timeout(9000);
|
||||
var gun = Gun();
|
||||
|
||||
gun.get('stef').put({name:'Stef'});
|
||||
@ -3081,7 +3083,7 @@ describe('Gun', function(){
|
||||
if(done.c){ return } done.c = 1;
|
||||
done();
|
||||
});
|
||||
},5000);
|
||||
},1200);
|
||||
});
|
||||
|
||||
it('get get get any parallel', function(done){
|
||||
@ -3677,12 +3679,12 @@ describe('Gun', function(){
|
||||
this.timeout(5000);
|
||||
var gun = Gun({test_no_peer:true}).get('g/m/no/slow');
|
||||
//console.log("---------- setup data done -----------");
|
||||
var prev, diff, max = 25, total = 9, largest = -1, gone = {};
|
||||
var prev, diff, max = 25, total = 9, largest = -1, gone = {}, u;
|
||||
//var prev, diff, max = Infinity, total = 10000, largest = -1, gone = {};
|
||||
// TODO: It would be nice if we could change these numbers for different platforms/versions of javascript interpreters so we can squeeze as much out of them.
|
||||
gun.get('history').map().on(function(time, index){
|
||||
//console.log(">>>", index, time);
|
||||
diff = Gun.time.is() - time;
|
||||
//console.log(">>>", index, time, diff);
|
||||
//return;
|
||||
expect(gone[index]).to.not.be.ok();
|
||||
gone[index] = diff;
|
||||
@ -3693,6 +3695,7 @@ describe('Gun', function(){
|
||||
var turns = 0;
|
||||
var many = setInterval(function(){
|
||||
if(turns > total || (diff || 0) > (max + 5)){
|
||||
if(u === diff){ return }
|
||||
clearTimeout(many);
|
||||
expect(Gun.num.is(diff)).to.be.ok();
|
||||
if(done.c){ return } done.c = 1;
|
||||
@ -3762,9 +3765,9 @@ describe('Gun', function(){
|
||||
var msg = {what: 'hello world'};
|
||||
//var ref = user.get('who').get('all').set(msg);
|
||||
//user.get('who').get('said').set(ref);
|
||||
var ref = gun.get('who').get('all').set(msg);
|
||||
gun.get('who').get('said').set(ref);
|
||||
gun.get('who').get('said').map().once(function(data){
|
||||
var ref = gun.get('s/r/who').get('all').set(msg);
|
||||
gun.get('s/r/who').get('said').set(ref);
|
||||
gun.get('s/r/who').get('said').map().once(function(data){
|
||||
expect(data.what).to.be.ok();
|
||||
done();
|
||||
})
|
||||
|
@ -23,8 +23,15 @@
|
||||
<script
|
||||
src="../sea.js">
|
||||
</script>
|
||||
<script src="./common.js"></script>
|
||||
|
||||
<script src="../lib/radix.js"></script>
|
||||
<script src="../lib/radisk.js"></script>
|
||||
<script src="../lib/store.js"></script>
|
||||
<script src="../lib/rindexed.js"></script>
|
||||
|
||||
<script src="./rad/rad.js"></script>
|
||||
<script src="./sea/sea.js"></script>
|
||||
<script src="./common.js"></script>
|
||||
<script>
|
||||
if(location.search){
|
||||
Gun.debug = true;
|
||||
|
71
test/normalize/normalize.html
Normal file
71
test/normalize/normalize.html
Normal file
@ -0,0 +1,71 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="../../../gun/examples/jquery.js"></script>
|
||||
<script async src="../../../gun/lib/monotype.js"></script>
|
||||
<script async src="../../../gun/lib/meta.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="edit" contenteditable='true'>the world is a beautiful place.</div>
|
||||
<div id="out">The world is a beautiful place.</div>
|
||||
<div id="test">
|
||||
<button id="render">render</button>
|
||||
<textarea id="before"></textarea>
|
||||
<textarea id="after"></textarea>
|
||||
<script src="../../../gun/lib/normalize.js"></script>
|
||||
</div>
|
||||
<script>
|
||||
$('#render').on('click', check);
|
||||
$('#edit').on('keyup', check).focus();
|
||||
function check(){
|
||||
var a = $('#edit').html();
|
||||
$('#before').val(a);
|
||||
var opt = {};
|
||||
opt.hierarchy = ['div', 'ol', 'ul', 'li', 'p', 'a', 'b', 'i', 'span', 's', 'sub', 'sup', 'u', 'br'];
|
||||
opt.convert = {'em': 'i', 'strong': 'b', 'strike': 's', 'font': 'span'};
|
||||
var b = $.normalize(a);
|
||||
$('#after').val(b);
|
||||
$('#out').html(b);
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
var $xss = $('<div id="xss">').appendTo('body');
|
||||
$.each([
|
||||
'javascript:',
|
||||
'JaVaScRiPt:',
|
||||
'java script:',
|
||||
'java\nscript:',
|
||||
'java\tscript:',
|
||||
'java\0script:',
|
||||
'jav	ascript:',
|
||||
'jav
ascript:',
|
||||
'jav
ascript:',
|
||||
'  javascript:',
|
||||
'javascript:',
|
||||
'javascript:',
|
||||
'javascript:',
|
||||
'\u006Aavascript:',
|
||||
'javascript:',
|
||||
'javascript:',
|
||||
'javascript:',
|
||||
'javascript:',
|
||||
'javascript:',
|
||||
'javascript:'
|
||||
], function(i,v){
|
||||
//console.log(v);
|
||||
var s = "<div><a href='"+v+"alert(1)'>xss</a></div>";
|
||||
var html = $.normalize(s);
|
||||
if(html.match(/href/ig)){ alert('xss') }
|
||||
$xss.append(html);
|
||||
console.log(html);
|
||||
});
|
||||
// url("javascript: // and all permutations
|
||||
// stylesheets can apparently have XSS?
|
||||
</script>
|
||||
<style>
|
||||
button { width: 100%; }
|
||||
textarea { width: 45%; height: 20em; font-size: 18pt; }
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
@ -3,9 +3,9 @@ var config = {
|
||||
port: 8765,
|
||||
servers: 2,
|
||||
browsers: 3,
|
||||
each: 1000000,
|
||||
burst: 25,
|
||||
wait: 25,
|
||||
each: 100000, //1000000,
|
||||
burst: 1,
|
||||
wait: 1,
|
||||
dir: __dirname,
|
||||
chunk: 1024 * 1024 * 10,
|
||||
notrad: false,
|
||||
|
@ -4,7 +4,7 @@ var config = {
|
||||
servers: 1,
|
||||
browsers: 2,
|
||||
each: 2500,
|
||||
burst: 25, // do not go below 1!
|
||||
burst: 1, // do not go below 1!
|
||||
wait: 1,
|
||||
route: {
|
||||
'/': __dirname + '/index.html',
|
||||
|
102
test/rad/browser.html
Normal file
102
test/rad/browser.html
Normal file
@ -0,0 +1,102 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>RindexedDB</h1>
|
||||
|
||||
<script src="../../../gun/gun.js"></script>
|
||||
<script src="../../../gun/lib/radix.js"></script>
|
||||
<script src="../../../gun/lib/radisk.js"></script>
|
||||
<script src="../../../gun/lib/store.js"></script>
|
||||
<script src="../../../gun/lib/rindexed.js"></script>
|
||||
<!-- script src="../../../gun/lib/rls.js"></script -->
|
||||
|
||||
<button onclick="spam()">spam</button>
|
||||
<button onclick="read()">read</button>
|
||||
<input id="wait" placeholder="wait" type="number">
|
||||
<input id="burst" placeholder="burst" type="number">
|
||||
<div id='debugs'></div>
|
||||
<div id='debug'></div>
|
||||
|
||||
<script>
|
||||
Gun.TESTING = true;
|
||||
try{localStorage.clear()}catch(e){}
|
||||
indexedDB.deleteDatabase('radatatest');
|
||||
|
||||
var opt = {localStorage: false};
|
||||
//opt.store = RindexedDB(opt);
|
||||
var gun = Gun(opt);
|
||||
</script>
|
||||
<script>
|
||||
wait.onchange = function(){ spam.wait = this.value }
|
||||
burst.onchange = function(){ spam.burst = this.value }
|
||||
//setTimeout(spam, 1);
|
||||
function spam(){
|
||||
//spam.max = 100000; spam.left = spam.max; spam.wait = 1; spam.burst = 250; spam.c = 0; spam.s = (+new Date);
|
||||
//spam.max = 100000; spam.left = spam.max; spam.wait = 1; spam.burst = 100; spam.c = 0; spam.s = (+new Date);
|
||||
spam.max = 1000000; spam.left = spam.max; spam.wait = 1; spam.burst = 250; spam.c = 0; spam.s = (+new Date);
|
||||
//spam.max = 100; spam.left = spam.max; spam.wait = 1; spam.burst = 1; spam.c = 0; spam.s = (+new Date);
|
||||
var to = setInterval(function(){ var b = spam.burst;
|
||||
if(spam.c >= spam.max){ clearTimeout(to); return; }
|
||||
if(!b){ b = burst = 1 }
|
||||
while(b--){ go(++spam.c) }
|
||||
function go(i){ var d = 0;
|
||||
//loc.put(i, {test: i}, function(err, ok){ var ack = {err: err, ok: ok};
|
||||
//ind.put(i, {test: i}, function(err, ok){ var ack = {err: err, ok: ok};
|
||||
var ref = gun.get(i).put({test: i}, function(ack){
|
||||
if(ack.err){ console.log(ack); }
|
||||
if(d++){ return }
|
||||
if(--spam.left){ return }
|
||||
spam.end = (+new Date) - spam.s;
|
||||
console.log('DONE!\n', spam.max, 'in', spam.end/1000, 'seconds\n', Math.round(spam.max / (spam.end/1000)), 'per second.');
|
||||
document.body.style.backgroundColor = 'lime';
|
||||
});
|
||||
}
|
||||
},wait);
|
||||
setInterval(function(){
|
||||
if(spam.end === true){ return }
|
||||
if(spam.end){ spam.end = true }
|
||||
var t = (+new Date) - spam.s, tmp, sec;
|
||||
var status = 'saved\n'+ (tmp = (spam.max - spam.left)) +' in '+ (sec = (t/1000)) +' seconds\n'+ Math.round(tmp / sec) +' per second';
|
||||
debugs.innerText = status;
|
||||
}, 500);
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
;(function(){
|
||||
var f = 'index';
|
||||
indexedDB.deleteDatabase(f);
|
||||
var o = indexedDB.open(f, 1), ind = {}, db;
|
||||
o.onupgradeneeded = function(eve){ (eve.target.result).createObjectStore(f) }
|
||||
o.onsuccess = function(){ db = o.result }
|
||||
o.onerror = function(eve){ console.log(eve||1); }
|
||||
ind.put = function(key, data, cb){
|
||||
if(!db){ setTimeout(function(){ ind.put(key, data, cb) },9); return }
|
||||
var tx = db.transaction([f], 'readwrite');
|
||||
var obj = tx.objectStore(f);
|
||||
var req = obj.put(data, ''+key);
|
||||
req.onsuccess = obj.onsuccess = tx.onsuccess = function(){ cb(null, 1) }
|
||||
req.onabort = obj.onabort = tx.onabort = function(eve){ cb(eve||2) }
|
||||
req.onerror = obj.onerror = tx.onerror = function(eve){ cb(eve||3) }
|
||||
}
|
||||
ind.get = function(key, cb){
|
||||
if(!db){ setTimeout(function(){ ind.get(key, cb) },9); return }
|
||||
var tx = db.transaction([f], 'readwrite');
|
||||
var obj = tx.objectStore(f);
|
||||
var req = obj.get(''+key);
|
||||
req.onsuccess = function(){ cb(null, req.result) }
|
||||
req.onabort = function(eve){ cb(eve||4) }
|
||||
req.onerror = function(eve){ cb(eve||5) }
|
||||
}
|
||||
window.ind = ind;
|
||||
}());
|
||||
</script>
|
||||
<script>
|
||||
;(function(){
|
||||
localStorage.clear();
|
||||
var ls = localStorage, loc = {};
|
||||
loc.put = function(key, data, cb){ ls[''+key] = data; cb(null, 1) }
|
||||
loc.get = function(key, cb){ cb(null, ls[''+key]) }
|
||||
window.loc = loc;
|
||||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
10
test/rad/parse.rad
Normal file
10
test/rad/parse.rad
Normal file
@ -0,0 +1,10 @@
|
||||
+1#"age:"+29>+1549776205172
|
||||
+1#"name:""Bob!>+1549776205172
|
||||
+1#"pet:"#XAqxAKkRa6lTsfAElEjDweqt>+1549776205172
|
||||
+0#"u/m
|
||||
+1#"
|
||||
+2#"alice:"#dlgw87rue6oVQhsvc3XFLrOu>+1549776205172
|
||||
+2#"bob:"#nuTAd2Tn4S5SiDVA7nxNBbZt>+1549776205172
|
||||
+1#"/p
|
||||
+2#"alice:"#USw3Dp7hTD7VMBLnd8dVBR4s>+1549776205200
|
||||
+2#"bob:"#1VwZRUw7vQ1hX8gspN1ZrHVj>+1549776205200
|
251
test/rad/rad.js
Normal file
251
test/rad/rad.js
Normal file
@ -0,0 +1,251 @@
|
||||
var root;
|
||||
var Gun;
|
||||
(function(){
|
||||
var env;
|
||||
if(typeof global !== 'undefined'){ env = global }
|
||||
if(typeof window !== 'undefined'){ env = window }
|
||||
root = env.window? env.window : global;
|
||||
try{ env.window && root.localStorage && root.localStorage.clear() }catch(e){}
|
||||
try{ require('fs').unlinkSync('data.json') }catch(e){}
|
||||
try{ require('../../lib/fsrm')('radatatest') }catch(e){}
|
||||
//root.Gun = root.Gun || require('../gun');
|
||||
if(root.Gun){
|
||||
root.Gun = root.Gun;
|
||||
root.Gun.TESTING = true;
|
||||
} else {
|
||||
root.Gun = require('../../gun');
|
||||
root.Gun.TESTING = true;
|
||||
//require('../lib/file');
|
||||
require('../../lib/store');
|
||||
require('../../lib/rfs');
|
||||
}
|
||||
|
||||
try{ var expect = global.expect = require("../expect") }catch(e){}
|
||||
|
||||
}(this));
|
||||
|
||||
;(function(){
|
||||
Gun = root.Gun
|
||||
|
||||
if(Gun.window && !Gun.window.RindexedDB){ return }
|
||||
|
||||
var opt = {};
|
||||
var Radisk = (Gun.window && Gun.window.Radisk) || require('../../lib/radisk');
|
||||
opt.store = ((Gun.window && Gun.window.RindexedDB) || require('../../lib/rfs'))(opt);
|
||||
opt.chunk = 1000;
|
||||
var Radix = Radisk.Radix;
|
||||
var rad = Radisk(opt), esc = String.fromCharCode(27);
|
||||
|
||||
describe('RAD', function(){
|
||||
|
||||
var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammamaria","Andy","Anselme","Ardeen","Armand","Ashelman","Aube","Averyl","Baker","Barger","Baten","Bee","Benia","Bernat","Bevers","Bittner","Bobbe","Bonny","Boyce","Breech","Brittaney","Bryn","Burkitt","Cadmann","Campagna","Carlee","Carver","Cavallaro","Chainey","Chaunce","Ching","Cianca","Claudina","Clyve","Colon","Cooke","Corrina","Crawley","Cullie","Dacy","Daniela","Daryn","Deedee","Denie","Devland","Dimitri","Dolphin","Dorinda","Dream","Dunham","Eachelle","Edina","Eisenstark","Elish","Elvis","Eng","Erland","Ethan","Evelyn","Fairman","Faus","Fenner","Fillander","Flip","Foskett","Fredette","Fullerton","Gamali","Gaspar","Gemina","Germana","Gilberto","Giuditta","Goer","Gotcher","Greenstein","Grosvenor","Guthrey","Haldane","Hankins","Harriette","Hayman","Heise","Hepsiba","Hewie","Hiroshi","Holtorf","Howlond","Hurless","Ieso","Ingold","Isidora","Jacoba","Janelle","Jaye","Jennee","Jillana","Johnson","Josy","Justinian","Kannan","Kast","Keeley","Kennett","Kho","Kiran","Knowles","Koser","Kroll","LaMori","Lanctot","Lasky","Laverna","Leff","Leonanie","Lewert","Lilybel","Lissak","Longerich","Lou","Ludeman","Lyman","Madai","Maia","Malvina","Marcy","Maris","Martens","Mathilda","Maye","McLain","Melamie","Meras","Micco","Millburn","Mittel","Montfort","Moth","Mutz","Nananne","Nazler","Nesta","Nicolina","Noellyn","Nuli","Ody","Olympie","Orlena","Other","Pain","Parry","Paynter","Pentheas","Pettifer","Phyllida","Plath","Posehn","Proulx","Quinlan","Raimes","Ras","Redmer","Renelle","Ricard","Rior","Rocky","Ron","Rosetta","Rubia","Ruttger","Salbu","Sandy","Saw","Scholz","Secor","September","Shanleigh","Shenan","Sholes","Sig","Sisely","Soble","Spanos","Stanwinn","Stevie","Stu","Suzanne","Tacy","Tanney","Tekla","Thackeray","Thomasin","Tilla","Tomas","Tracay","Tristis","Ty","Urana","Valdis","Vasta","Vezza","Vitoria","Wait","Warring","Weissmann","Whetstone","Williamson","Wittenburg","Wymore","Yoho","Zamir","Zimmermann"];
|
||||
|
||||
//console.log("HYPER TEST");var z = 10000; while(--z){ names.push(Gun.text.random(7)) }this.timeout(9000);
|
||||
|
||||
describe('Radix', function(){
|
||||
var radix = Radix();
|
||||
it('radix write read', function(done){
|
||||
var all = {};
|
||||
names.forEach(function(v,i){
|
||||
v = v.toLowerCase();
|
||||
all[v] = v;
|
||||
radix(v, i)
|
||||
});
|
||||
expect(Gun.obj.empty(all)).to.not.be.ok();
|
||||
Radix.map(radix, function(v,k){
|
||||
delete all[k];
|
||||
});
|
||||
expect(Gun.obj.empty(all)).to.be.ok();
|
||||
done();
|
||||
});
|
||||
|
||||
it('radix write read again', function(done){
|
||||
var all = {};
|
||||
names.forEach(function(v,i){
|
||||
v = v.toLowerCase();
|
||||
all[v] = v;
|
||||
//rad(v, i)
|
||||
});
|
||||
expect(Gun.obj.empty(all)).to.not.be.ok();
|
||||
Radix.map(radix, function(v,k){
|
||||
delete all[k];
|
||||
});
|
||||
expect(Gun.obj.empty(all)).to.be.ok();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Radisk', function(){
|
||||
|
||||
/*it('parse', function(done){
|
||||
this.timeout(60000);
|
||||
if(Gun.window){ return done() }
|
||||
var raw = require('fs').readFileSync(__dirname + '/parse.rad').toString();
|
||||
rad.parse('!', function(err, disk){
|
||||
console.log("!!!!", err);
|
||||
}, raw);
|
||||
return;
|
||||
});*/
|
||||
|
||||
|
||||
it('write contacts', function(done){
|
||||
var all = {}, to, start;
|
||||
names.forEach(function(v,i){
|
||||
v = v.toLowerCase();
|
||||
all[v] = true;
|
||||
rad(v, i, function(err, ok){
|
||||
expect(err).to.not.be.ok();
|
||||
delete all[v];
|
||||
if(!Gun.obj.empty(all)){ return }
|
||||
done();
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
it('read contacts', function(done){
|
||||
var all = {}, find = 'a';
|
||||
names.forEach(function(v){
|
||||
v = v.toLowerCase();
|
||||
if(v.indexOf(find) == 0){ all[v] = true }
|
||||
});
|
||||
rad(find, function(err, data){
|
||||
//console.log(">>>>>>>>> KUNG FOO PANDA <<<<<<<<<<<");
|
||||
//console.debug.i=1;console.log(data);
|
||||
Radix.map(data, function(v,k){
|
||||
delete all[find+k];
|
||||
});
|
||||
if(!Gun.obj.empty(all)){ return }
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('read again', function(done){
|
||||
var all = {}, find = 'm';
|
||||
names.forEach(function(v){
|
||||
v = v.toLowerCase();
|
||||
if(v.indexOf(find) == 0){ all[v] = true }
|
||||
});
|
||||
rad(find, function(err, data, info){
|
||||
Radix.map(data, function(v,k){
|
||||
delete all[find+k];
|
||||
});
|
||||
if(!Gun.obj.empty(all)){ return }
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('read bytes', function(done){
|
||||
var all = {}, find = 'm', to;
|
||||
names.forEach(function(v){
|
||||
v = v.toLowerCase();
|
||||
if(v.indexOf(find) == 0){ all[v] = true }
|
||||
});
|
||||
rad(find, function(err, data, info){
|
||||
Radix.map(data, function(v,k){
|
||||
delete all[find+k];
|
||||
});
|
||||
clearTimeout(to);
|
||||
to = setTimeout(function(){
|
||||
expect(Gun.obj.empty(all)).to.not.be.ok();
|
||||
done();
|
||||
},100);
|
||||
}, {limit: 1});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
var ntmp = names;
|
||||
describe('RAD + GUN', function(){
|
||||
var ochunk = 1000;
|
||||
var gun = Gun({chunk: ochunk});
|
||||
|
||||
it('write same', function(done){
|
||||
var all = {}, to, start, tmp;
|
||||
var names = [], c = 285;
|
||||
while(--c){ names.push('bob') }
|
||||
names.forEach(function(v,i){
|
||||
all[++i] = true;
|
||||
tmp = v.toLowerCase();
|
||||
gun.get('names').get(tmp).put({name: v, age: i}, function(ack){
|
||||
expect(ack.err).to.not.be.ok();
|
||||
delete all[i];
|
||||
if(!Gun.obj.empty(all)){ return }
|
||||
done();
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it('write contacts', function(done){
|
||||
var all = {}, to, start, tmp;
|
||||
names.forEach(function(v,i){
|
||||
all[++i] = true;
|
||||
tmp = v.toLowerCase();
|
||||
gun.get('names').get(tmp).put({name: v, age: i}, function(ack){
|
||||
expect(ack.err).to.not.be.ok();
|
||||
delete all[i];
|
||||
if(!Gun.obj.empty(all)){ return }
|
||||
done();
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
it('read contacts', function(done){
|
||||
var all = {}, find = 'm', to;
|
||||
names.forEach(function(v){
|
||||
v = v.toLowerCase();
|
||||
if(v.indexOf(find) == 0){ all[v] = true }
|
||||
});
|
||||
gun.get('names').get({'.': {'*': find}, '%': 1000 * 100}).once().map().once(function(data, key){
|
||||
expect(data.name).to.be.ok();
|
||||
expect(data.age).to.be.ok();
|
||||
delete all[key];
|
||||
clearTimeout(to);
|
||||
to = setTimeout(function(){
|
||||
expect(Gun.obj.empty(all)).to.be.ok();
|
||||
done();
|
||||
},100);
|
||||
});
|
||||
});
|
||||
|
||||
it('read contacts again', function(done){
|
||||
var all = {}, find = 'a', to;
|
||||
names.forEach(function(v){
|
||||
v = v.toLowerCase();
|
||||
if(v.indexOf(find) == 0){ all[v] = true }
|
||||
});
|
||||
gun.get('names').get({'.': {'*': find}, '%': 1000 * 100}).once().map().once(function(data, key){
|
||||
expect(data.name).to.be.ok();
|
||||
expect(data.age).to.be.ok();
|
||||
delete all[key];
|
||||
clearTimeout(to);
|
||||
to = setTimeout(function(){
|
||||
expect(Gun.obj.empty(all)).to.be.ok();
|
||||
done();
|
||||
},100);
|
||||
});
|
||||
});
|
||||
|
||||
it('read contacts fresh', function(done){
|
||||
var gun = Gun({chunk: ochunk});
|
||||
var all = {}, find = 'b', to;
|
||||
names.forEach(function(v){
|
||||
v = v.toLowerCase();
|
||||
if(v.indexOf(find) == 0){ all[v] = true }
|
||||
});
|
||||
gun.get('names').get({'.': {'*': find}, '%': 1000 * 100}).once().map().once(function(data, key){
|
||||
expect(data.name).to.be.ok();
|
||||
expect(data.age).to.be.ok();
|
||||
delete all[key];
|
||||
clearTimeout(to);
|
||||
to = setTimeout(function(){
|
||||
expect(Gun.obj.empty(all)).to.be.ok();
|
||||
done();
|
||||
},100);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}());
|
@ -10,7 +10,7 @@ describe('Radix', function(){
|
||||
rad('ablah', 'cool');
|
||||
rad('node/circle.bob', 'awesome');
|
||||
|
||||
expect(rad('asdf.')).to.be.eql({pub: {'\u001e': 'yum'}});
|
||||
expect(rad('asdf.')).to.be.eql({pub: {'': 'yum'}});
|
||||
expect(rad('nv/foo.bar')).to.be(undefined);
|
||||
});
|
||||
});
|
@ -7,6 +7,7 @@ var Gun;
|
||||
root = env.window? env.window : global;
|
||||
try{ env.window && root.localStorage && root.localStorage.clear() }catch(e){}
|
||||
try{ require('fs').unlinkSync('data.json') }catch(e){}
|
||||
try{ require('../../lib/fsrm')('radatatest') }catch(e){}
|
||||
//root.Gun = root.Gun || require('../gun');
|
||||
if(root.Gun){
|
||||
root.Gun = root.Gun;
|
||||
@ -296,12 +297,15 @@ describe('SEA', function(){
|
||||
})
|
||||
|
||||
it('refresh login', function(done){
|
||||
gun = Gun();
|
||||
user = gun.user();
|
||||
user.auth('carl', 'test123', function(ack){
|
||||
expect(ack.err).to.not.be.ok();
|
||||
done()
|
||||
})
|
||||
this.timeout(9000);
|
||||
setTimeout(function(){
|
||||
gun = Gun();
|
||||
user = gun.user();
|
||||
user.auth('carl', 'test123', function(ack){
|
||||
expect(ack.err).to.not.be.ok();
|
||||
done()
|
||||
})
|
||||
}, 800);
|
||||
})
|
||||
|
||||
it('gun put JSON', function(done){
|
||||
@ -361,4 +365,4 @@ describe('SEA', function(){
|
||||
|
||||
})
|
||||
|
||||
})()
|
||||
}());
|
@ -1,37 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="../../../gun/examples/jquery.js"></script>
|
||||
<script async src="../../../gun/lib/monotype.js"></script>
|
||||
<script async src="../../../gun/lib/meta.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="edit" contenteditable='true'>the world is a beautiful place.</div>
|
||||
<div id="out">The world is a beautiful place.</div>
|
||||
<div id="test">
|
||||
<button id="render">render</button>
|
||||
<textarea id="before"></textarea>
|
||||
<textarea id="after"></textarea>
|
||||
<script src="../../../gun/lib/canonize.js"></script>
|
||||
</div>
|
||||
<script>
|
||||
$('#render').on('click', check);
|
||||
$('#edit').on('keyup', check).focus();
|
||||
function check(){
|
||||
var a = $('#edit').html();
|
||||
$('#before').val(a);
|
||||
var opt = {};
|
||||
opt.hierarchy = ['div', 'ol', 'ul', 'li', 'p', 'a', 'b', 'i', 'span', 's', 'sub', 'sup', 'u', 'br'];
|
||||
opt.convert = {'em': 'i', 'strong': 'b', 'strike': 's', 'font': 'span'};
|
||||
var b = require.htmlNormalize(a);
|
||||
$('#after').val(b);
|
||||
$('#out').html(b);
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
button { width: 100%; }
|
||||
textarea { width: 45%; height: 20em; font-size: 18pt; }
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
44041
test/tmp/contacts.html
Normal file
44041
test/tmp/contacts.html
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user