Merge branch 'master' into feature-multicast

This commit is contained in:
Martti Malmi
2019-04-15 12:55:41 -07:00
39 changed files with 45278 additions and 704 deletions

18
lib/fsrm.js Normal file
View 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);
};

View File

@@ -1,73 +1,72 @@
$(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 noop = function(){}, u;
var m = window.meta = {edit:[]};
var k = m.key = {};
k.meta = {17:17, 91:17, 93:17, 224:17};
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(m.flip.is()){
(k.combo || (k.combo = [])).push(eve.which);
m.check('on', eve.which, k.at || (k.at = m.edit));
if(eve.repeat){ return }
var key = (k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode;
if(!eve.fake && key === k.last){ return } k.last = key;
if(!eve.fake && $(eve.target).closest('input, textarea, [contenteditable=true]').length){
if(k.meta[key]){ k.down.meta = key = -1 }
if(!k.down.meta){ return }
}
(k.combo || (k.combo = [])).push(key);
m.check('on', key, k.at || (k.at = m.edit));
if(k.meta[key]){
m.list(k.at.back || m.edit);
if(k.at && !k.at.back){ m.flip() }
}
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 }
k.eve = m.eve = eve;
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.at === m.edit){ k.wipe() }
if(27 === eve.which){ return m.flip(false) }
}
m.flip = function(tmp, aid){
if(aid){
m.flip.aid = true;
setTimeout(function(){$(document).one('click',function(eve){m.flip(m.flip.aid = false)})},250); // ugly but important for visual aid.
var key = (k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode;
if(!eve.fake && $(eve.target).closest('input, textarea, [contenteditable=true]').length){
if(k.meta[key]){
k.down.meta = null;
key = -1;
} else
if(!k.down.meta){ return }
}
k.last = null;
if($(':focus').closest('#meta').length){ return }
m.check('up', key);
if(-1 === key || 27 === eve.which){ k.wipe() }
}
m.flip = function(tmp){
var board = $('#meta .meta-menu');
((tmp === false) || (!tmp && board.is(':visible')))?
board.addClass('meta-none')
: board.removeClass('meta-none');
}
m.flip.is = function(){
if(m.flip.aid && ((m.eve||{}).fake || k.at !== m.edit)){ m.flip.aid = false }
return !m.flip.aid && $('#meta .meta-menu').is(':visible');
return $('#meta .meta-menu').is(':visible');
}
m.flip.wait = 500;
m.check = function(how, key, at){
at = k.at || m.edit;
//m.list(at);
var edit = at[key], tmp;
var edit = at[key];
if(!edit){ return }
if(k.eve && k.eve.preventDefault){ k.eve.preventDefault() }
var tmp = k.eve || noop;
if(tmp.preventDefault){ tmp.preventDefault() }
if(edit[how]){
edit[how](m.eve);
if(k.at !== m.edit && 'up' === how){
if(k.down.meta){ m.list(k.at = m.edit) }
else { k.wipe() }
if(tmp.fake && !edit.fake){
m.tap.edit = edit;
} else {
edit[how](m.eve);
/*if(k.at !== m.edit && 'up' === how){
if(k.down.meta){ m.list(k.at = m.edit) }
else { k.wipe() }
}*/
}
}
if('up' != how){ return }
edit.back = at;
m.list(edit, at);
if(at != edit){ edit.back = at }
m.list(edit, true);
}
m.list = function(at){
m.list = function(at, opt){
if(!at){ return m.flip(false) }
var l = [];
$.each(at, function(i,k){ 'back' != i && k.combo && l.push(k) });
$.each(at, function(i,k){ 'back' != i && k.combo && k.name && l.push(k) });
if(!l.length){ return }
k.at = at;
l = l.sort(function(a,b){
@@ -82,8 +81,10 @@ $(function(){
$.each(l, function(i, k){
$ul.append($('<li>').text(k.name));
});
if(!at.back){ return }
$ul.append($('<li>').html('&larr;').one('click', function(){ m.list(k.at = at.back) }));
if(opt){ m.flip(true) }
$ul.append($('<li>').html('&larr;').one('click', function(){
m.list(k.at = at.back);
}));
}
m.ask = function(help, cb){
var $ul = $('#meta .meta-menu ul').empty();
@@ -96,34 +97,33 @@ $(function(){
});
var $li = $('<li>').append($form);
$ul.append($li);
m.flip(true);
$put.focus();
}
k.wipe = function(){
k.wipe = function(opt){
k.down.meta = false;
k.combo = [];
m.flip(false);
m.flip.aid = false;
if(!opt){ m.flip(false) }
m.list(k.at = m.edit);
};
$(document).on('keydown', k.down).on('keyup', k.up);
m.tap = {};
m.tap.select = function(eve){
m.tap.range = null;
if(!(m.tap.text()||'').trim()){
if(m.tap.was){
m.tap.was = null;
m.flip(false);
}
return;
}
m.flip(m.tap.range = monotype((eve||{}).target), m.tap.was = true);
}
m.tap.text = function(tmp){
return ((tmp = window.getSelection) && tmp().toString()) ||
((tmp = document.selection) && tmp.createRange().text) || '';
m.tap = function(){
var on = $('.meta-on')
.or($($(document.querySelectorAll(':hover')).get().reverse()).first())
.or($(document.elementFromPoint(meta.tap.x, meta.tap.y)));
return on;
}
$(window).on('blur', k.wipe).on('focus', k.wipe);
$(document).on('select contextmenu keyup mouseup', '[contenteditable=true]', m.tap.select);
//.on('keydown', '[contenteditable=true]', function(e){});
$(document).on('mousedown mousemove mouseup', function(eve){
m.tap.eve = eve;
m.tap.x = eve.pageX||0;
m.tap.y = eve.pageY||0;
m.tap.on = $(eve.target);
}).on('mousedown touchstart', function(eve){
var tmp = m.tap.edit;
if(!tmp || !tmp.on){ return }
tmp.on(eve);
m.tap.edit = null;
});
$(document).on('touchstart', '#meta .meta-start', function(eve){ m.tap.stun = true });
$(document).on('click', '#meta .meta-menu li', function(eve){
if(m.tap.stun){ return m.tap.stun = false }
@@ -132,10 +132,11 @@ $(function(){
k.down(eve);
k.up(eve);
});
$(document).on('keydown', k.down).on('keyup', k.up);
meta.edit = function(edit){
var tmp = edit.combow = [];
$.each(edit.combo || (edit.combo = []), function(i,k){
if(!k || !k.length){ return }
if(!k || !k.length){ if('number' == typeof k){ tmp.push(k) } return }
tmp.push(k.toUpperCase().charCodeAt(0));
});
var at = meta.edit, l = edit.combo.length;
@@ -143,37 +144,7 @@ $(function(){
edit.combow = edit.combow.join(',');
m.list(meta.edit);
}
meta.text = {zws: '&#8203;'};
meta.text.editor = function(opt, as){ var tmp;
if(!opt){ return }
opt = (typeof opt == 'string')? {edit: opt} : opt.tag? opt : {tag: opt};
var r = opt.range = opt.range || m.tap.range || monotype(), cmd = opt.edit;
as = opt.as = opt.as || as;
if(cmd && document.execCommand){
r.restore();
if(document.execCommand(cmd, null, as||null)){ return }
}
if(!opt.tag){ return }
opt.tag = $(opt.tag);
opt.name = opt.name || opt.tag.prop('tagName');
if((tmp = $(r.get()).closest(opt.name)).length){
if(r.s === r.e){
tmp.after(meta.text.zws);
r = r.select(monotype.next(tmp[0]),1);
} else {
tmp.contents().unwrap(opt.name);
}
} else
if(r.s === r.e){
r.insert(opt.tag);
r = r.select(opt.tag);
} else {
r.wrap(opt.tag);
}
r.restore();
opt.range = null;
if(m.tap.range){ m.tap.range = monotype() }
}
$.fn.or = function(s){ return this.length ? this : $(s||'body') };
;(function(){try{
/* UI */
if(meta.css){ return }
@@ -199,10 +170,12 @@ $(function(){
width: '2em',
height: '2em',
opacity: 0.7,
outline: 'none',
color: '#000044',
overflow: 'visible',
transition: 'all 0.2s ease-in'
},
'#meta *': {outline: 'none'},
'#meta .meta-none': {display: 'none'},
'#meta span': {'line-height': '2em'},
'#meta .meta-menu': {
@@ -263,98 +236,147 @@ $(function(){
}
}catch(e){}}());
;(function(){
// on fires when shortcut keydowns or on touch after command selected and then touchdown
meta.edit({
name: "Bold",
combo: ['B'],
on: function(e){
meta.text.editor('bold');
},
up: function(){}
});
meta.edit({
name: "Italic",
combo: ['I'],
on: function(e){
meta.text.editor('italic');
},
up: function(){}
});
meta.edit({
name: "Underline",
combo: ['U'],
on: function(e){
meta.text.editor('underline');
},
up: function(){}
});
meta.edit({
name: "linK",
combo: ['K'],
up: function(e){
var range = meta.tap.range || monotype();
meta.ask('Paste or type link...', function(url){
meta.text.editor({tag: $('<a href="'+url+'">link</a>'), edit: url? 'createLink' : 'unlink', as: url, range: range});
})
},
on: function(){}
});
meta.edit({name: "aliGn", combo: ['G']});
meta.edit({
name: "Left",
combo: ['G','L'],
on: function(e){ meta.text.editor('justifyLeft') },
up: function(){}
});
meta.edit({
name: "Right",
combo: ['G','R'],
on: function(e){ meta.text.editor('justifyRight') },
up: function(){ }
});
meta.edit({
name: "Middle",
combo: ['G','M'],
on: function(e){ meta.text.editor('justifyCenter') },
up: function(){ }
});
meta.edit({
name: "Justify",
combo: ['G','J'],
on: function(e){ meta.text.editor('justifyFull') },
up: function(){}
});
// Align Number
// Align Points
// Align Strike
meta.edit({name: "Size", combo: ['S']});
meta.edit({
name: "Small",
combo: ['S','S'],
on: function(e){ meta.text.editor('fontSize', 2) },
up: function(){ }
});
meta.edit({
name: "Normal",
combo: ['S','N'],
on: function(e){ meta.text.editor('fontSize', 5) },
up: function(){}
});
meta.edit({
name: "Header",
combo: ['S','H'],
on: function(e){ meta.text.editor('fontSize', 6) },
up: function(){}
});
meta.edit({
name: "Title",
combo: ['S','T'],
on: function(e){ meta.text.editor('fontSize', 7) },
up: function(){}
});
// Size Spacing
// Size Super
// Size Sub
meta.edit({name: "Edit", combo: ['E']});
// include basic text editing by default.
var monotype = window.monotype || function(){console.log("monotype needed")};
var m = meta;
m.text = {zws: '&#8203;'};
m.text.on = function(eve){ var tmp;
if($((eve||{}).target).closest('#meta').length){ return }
m.text.range = null;
if(!(m.text.copy()||'').trim()){
m.flip(false);
m.list(m.text.it);
return;
}
m.text.range = monotype((eve||{}).target);
m.text.it.on(eve);
}
m.text.copy = function(tmp){
return ((tmp = window.getSelection) && tmp().toString()) ||
((tmp = document.selection) && tmp.createRange().text) || '';
}
$(document).on('select contextmenu keyup mouseup', '[contenteditable=true]', m.text.on);
m.text.editor = function(opt, as){ var tmp;
if(!opt){ return }
opt = (typeof opt == 'string')? {edit: opt} : opt.tag? opt : {tag: opt};
var r = opt.range = opt.range || m.text.range || monotype(), cmd = opt.edit;
as = opt.as = opt.as || as;
if(cmd && document.execCommand){
r.restore();
if(document.execCommand(cmd, null, as||null)){
if(m.text.range){ m.text.range = monotype() }
return;
}
}
if(!opt.tag){ return }
opt.tag = $(opt.tag);
opt.name = opt.name || opt.tag.prop('tagName');
if((tmp = $(r.get()).closest(opt.name)).length){
if(r.s === r.e){
tmp.after(m.text.zws);
r = r.select(monotype.next(tmp[0]),1);
} else {
tmp.contents().unwrap(opt.name);
}
} else
if(r.s === r.e){
r.insert(opt.tag);
r = r.select(opt.tag);
} else {
r.wrap(opt.tag);
}
r.restore();
opt.range = null;
if(m.text.range){ m.text.range = monotype() }
}
meta.edit(meta.text.it = {combo: [-1], on: function(){ m.list(this, true) }, back: meta.edit}); // -1 is key for typing.
meta.text.it[-1] = meta.text.it;
meta.edit({
name: "Bold",
combo: [-1,'B'], fake: -1,
on: function(eve){
meta.text.editor('bold');
},
up: function(){}
});
meta.edit({
name: "Italic",
combo: [-1,'I'], fake: -1,
on: function(eve){
meta.text.editor('italic');
},
up: function(){}
});
/*meta.edit({
name: "Underline",
combo: [-1,'U'], fake: -1,
on: function(eve){
meta.text.editor('underline');
},
up: function(){}
});*/
meta.edit({
name: "linK",
combo: [-1,'K'], fake: -1,
on: function(eve){
var range = meta.text.range || monotype();
meta.ask('Paste or type link...', function(url){
meta.text.editor({tag: $('<a href="'+url+'">link</a>'), edit: url? 'createLink' : 'unlink', as: url, range: range});
})
}
});
//meta.edit({name: "aliGn", combo: [-1,'G']}); // MOVE TO ADVANCED MENu!
meta.edit({
name: "Left",
combo: [-1,'G','L'], fake: -1,
on: function(eve){ meta.text.editor('justifyLeft') },
up: function(){}
});
meta.edit({
name: "Right",
combo: [-1,'G','R'], fake: -1,
on: function(eve){ meta.text.editor('justifyRight') },
up: function(){ }
});
meta.edit({
name: "Middle",
combo: [-1,'G','M'], fake: -1,
on: function(eve){ meta.text.editor('justifyCenter') },
up: function(){ }
});
meta.edit({
name: "Justify",
combo: [-1,'G','J'], fake: -1,
on: function(eve){ meta.text.editor('justifyFull') },
up: function(){}
});
// Align Number
// Align Points
// Align Strike
meta.edit({name: "Size", combo: [-1,'S'], on: function(){ m.list(this, true) }});
meta.edit({
name: "Small",
combo: [-1,'S','S'], fake: -1,
on: function(eve){ meta.text.editor('fontSize', 2) },
up: function(){ }
});
meta.edit({
name: "Normal",
combo: [-1,'S','N'], fake: -1,
on: function(eve){ meta.text.editor('fontSize', 5) },
up: function(){}
});
meta.edit({
name: "Header",
combo: [-1,'S','H'], fake: -1,
on: function(eve){ meta.text.editor('fontSize', 6) },
up: function(){}
});
meta.edit({
name: "Title",
combo: [-1,'S','T'], fake: -1,
on: function(eve){ meta.text.editor('fontSize', 7) },
up: function(){}
});
}());
});

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);
}());

View File

@@ -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(){};

View File

@@ -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
View 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;
}
}());

View File

@@ -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');

View File

@@ -1,8 +1,11 @@
var fs = require('fs');
var path = require('path');
var dot = /\.\.+/g;
var slash = /\/\/+/g;
function CDN(dir){
return function(req, res){
req.url = (req.url||'').replace(dot,'').replace(slash,'/');
if(serve(req, res)){ return } // filters GUN requests!
fs.createReadStream(path.join(dir, req.url)).on('error',function(tmp){ // static files!
try{ tmp = fs.readFileSync(path.join(dir, 'index.html')) }catch(e){}

View File

@@ -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 }
}
});
});

View File

@@ -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);