mirror of
https://github.com/amark/gun.git
synced 2025-03-30 15:08:33 +00:00
book & rad APIs stabilizing
This commit is contained in:
parent
dc5f90ad61
commit
d7f19473a4
22
lib/book.js
22
lib/book.js
@ -17,7 +17,7 @@ var sT = setTimeout, B = sT.Book || (sT.Book = function(text){
|
||||
return b.set(word, is);
|
||||
};
|
||||
// TODO: if from text, preserve the separator symbol.
|
||||
b.list = [{from: text, size: (text||'').length, substring: sub, toString: to, book: b, get: b}];
|
||||
b.list = [{from: text, size: (text||'').length, substring: sub, toString: to, book: b, get: b, read: list}];
|
||||
b.page = page;
|
||||
b.set = set;
|
||||
b.get = get;
|
||||
@ -27,7 +27,7 @@ var sT = setTimeout, B = sT.Book || (sT.Book = function(text){
|
||||
|
||||
function page(word){
|
||||
var b = this, l = b.list, i = spot(word, l, b.parse), p = l[i];
|
||||
if('string' == typeof p){ l[i] = p = {size: -1, first: b.parse? b.parse(p) : p, substring: sub, toString: to, book: b, get: b} } // TODO: test, how do we arrive at this condition again?
|
||||
if('string' == typeof p){ l[i] = p = {size: -1, first: b.parse? b.parse(p) : p, substring: sub, toString: to, book: b, get: b, read: list} } // TODO: test, how do we arrive at this condition again?
|
||||
//p.i = i;
|
||||
return p;
|
||||
// TODO: BUG! What if we get the page, it turns out to be too big & split, we must then RE get the page!
|
||||
@ -55,12 +55,12 @@ function got(word, page){
|
||||
a = slot(has); // edge case bug?
|
||||
if(word != B.decode(a[0])){ return }
|
||||
}
|
||||
has = l[i] = b.all[word] = {word: word, is: B.decode(a[1]), page: page, substring: subt, toString: tot}; // TODO: convert to a JS value!!! Maybe index! TODO: BUG word needs a page!!!! TODO: Check for other types!!!
|
||||
has = l[i] = b.all[word] = {word: ''+word, is: B.decode(a[1]), page: page, substring: subt, toString: tot}; // TODO: convert to a JS value!!! Maybe index! TODO: BUG word needs a page!!!! TODO: Check for other types!!!
|
||||
return has.is;
|
||||
}
|
||||
|
||||
function spot(word, sorted, parse){ parse = parse || spot.no || (spot.no = function(t){ return t }); // TODO: BUG???? Why is there substring()||0 ? // TODO: PERF!!! .toString() is +33% faster, can we combine it with the export?
|
||||
var L = sorted, min = 0, page, found, l = word.length, max = L.length, i = max/2;
|
||||
var L = sorted, min = 0, page, found, l = (word=''+word).length, max = L.length, i = max/2;
|
||||
while(((word < (page = (parse(L[i=i>>0])||'').substring())) || ((parse(L[i+1])||'').substring() <= word)) && i != min){ // L[i] <= word < L[i+1]
|
||||
i += (page <= word)? (max - (min = i))/2 : -((max = i) - min)/2;
|
||||
}
|
||||
@ -73,11 +73,17 @@ function from(a, t, l){
|
||||
(l = a.from = slot(t = t||a.from||'')).toString = join;
|
||||
return l;
|
||||
}
|
||||
function list(each){ each = each || function(x){return x}
|
||||
// TODO: BUG!!! in limbo items need to get situated before calling this, if there are any. (obviously, we shouldn't do it again if limbo has previously been sorted).
|
||||
var i = 0, l = from(this)||[], w, r = [], p = this.book.parse || function(){};
|
||||
while(w = l[i++]){ r.push(each(slot(w)[1],p(w)||w,this)) }
|
||||
return r;
|
||||
}
|
||||
|
||||
function set(word, is){
|
||||
var b = this, has = b.all[word];
|
||||
if(has){ return b(word, is) } // updates to in-memory items will always match exactly.
|
||||
var page = b.page(word), tmp; // before we assume this is an insert tho, we need to check
|
||||
var page = b.page(word=''+word), tmp; // before we assume this is an insert tho, we need to check
|
||||
if(page && page.from){ // if it could be an update to an existing word from parseless.
|
||||
b.get(word);
|
||||
if(b.all[word]){ return b(word, is) }
|
||||
@ -100,7 +106,7 @@ function split(p, b){ // TODO: use closest hash instead of half.
|
||||
//while(tmp = L[i++]){ }
|
||||
var L = p.limbo = sort(p.limbo), l = L.length, i = l/2 >> 0, j = i, half = L[j], tmp;
|
||||
//console.timeEnd();
|
||||
var next = {limbo: [], first: half.substring(), size: 0, substring: sub, toString: to, book: b, get: b}, nl = next.limbo;
|
||||
var next = {limbo: [], first: half.substring(), size: 0, substring: sub, toString: to, book: b, get: b, read: list}, nl = next.limbo;
|
||||
nl.toString = join;
|
||||
//console.time();
|
||||
while(tmp = L[i++]){
|
||||
@ -131,9 +137,11 @@ function heal(l, s){ var i, e;
|
||||
function size(t){ return (t||'').length||1 } // bits/numbers less size? Bug or feature?
|
||||
function subt(i,j){ return this.word }
|
||||
//function tot(){ return this.text = this.text || "'"+(this.word)+"'"+(this.is)+"'" }
|
||||
function tot(){ var tmp;
|
||||
function tot(){ var tmp = {};
|
||||
//if((tmp = this.page) && tmp.saving){ delete tmp.book.all[this.word]; } // TODO: BUG! Book can't know about RAD, this was from RAD, so this MIGHT be correct but we need to refactor. Make sure to add tests that will re-trigger this.
|
||||
return this.text = this.text || ":"+B.encode(this.word)+":"+B.encode(this.is)+":";
|
||||
tmp[this.word] = this.is;
|
||||
return this.text = this.text || B.encode(tmp,'|',':').slice(1,-1);
|
||||
//return this.text = this.text || "'"+(this.word)+"'"+(this.is)+"'";
|
||||
}
|
||||
function sub(i,j){ return (this.first||this.word||B.decode((from(this)||'')[0]||'')).substring(i,j) }
|
||||
|
@ -7,15 +7,12 @@
|
||||
|
||||
var has = (sT.RAD.has || (sT.RAD.has = {}))[opt.file];
|
||||
if(has){ return has }
|
||||
var r = function rad(word, is, reply){
|
||||
var r = function rad(word, is, reply){ r.word = word;
|
||||
if(!b){ start(word, is, reply); return r }
|
||||
if(is === undefined || 'function' == typeof is){ // THIS IS A READ:
|
||||
var page = b.page(word);
|
||||
if(page.from){
|
||||
return is(null, page);
|
||||
}
|
||||
read(word, is, page); // get from disk
|
||||
return
|
||||
if(page.from){ return is && is(page, null), r }
|
||||
return read(word, is, page), r; // get from disk
|
||||
}
|
||||
//console.log("OFF");return;
|
||||
// ON WRITE:
|
||||
@ -25,15 +22,16 @@
|
||||
write(word, reply);
|
||||
return r;
|
||||
}, /** @param b the book */ b;
|
||||
r.then = function(cb, p){ return p = (new Promise(function(yes, no){ r(r.word, yes) })), cb? p.then(cb) : p }
|
||||
r.read = r.results = function(cb){ return (new Promise(async function(yes, no){ yes((await r(r.word)).read(cb)) })) }
|
||||
|
||||
async function read(word, reply, page){
|
||||
async function read(word, reply, page){ // TODO: this function doesn't do much, inline it???
|
||||
if(!reply){ return }
|
||||
var p = page || b.page(word);
|
||||
reply = reply.call ? reply : () => { };
|
||||
log(`read() ${word.slice(0, 40)}`);
|
||||
get(p, function(err, disk){
|
||||
if(err){ log("ERR! in read() get() cb", err); reply(err); return }
|
||||
if(err){ log("ERR! in read() get() cb", err); reply(p.no, err); return }
|
||||
p.from = disk || p.from;
|
||||
reply(null, p, b);
|
||||
reply(p, null, b);
|
||||
})
|
||||
}
|
||||
|
||||
@ -68,7 +66,7 @@
|
||||
RAD.put(file, data, function(err, ok){
|
||||
delete put[file];
|
||||
cb && cb(err, ok);
|
||||
});
|
||||
}, opt);
|
||||
};
|
||||
function get(file, cb){
|
||||
var tmp;
|
||||
@ -78,9 +76,9 @@
|
||||
if(tmp = put[file = fname(file)]){ cb(u, tmp.data); return }
|
||||
if(tmp = get[file]){ tmp.push(cb); return } get[file] = [cb];
|
||||
RAD.get(file, function(err, data){
|
||||
tmp = get[file]; delete get[file];
|
||||
tmp = get[file]||''; delete get[file];
|
||||
var i = -1, f; while (f = tmp[++i]){ f(err, data) } // TODO: BUG! CPU SCHEDULE?
|
||||
});
|
||||
}, opt);
|
||||
};
|
||||
|
||||
function start(word, is, reply){
|
||||
@ -90,7 +88,7 @@
|
||||
if(b){ r(word, is, reply); return }
|
||||
b = r.book = Book();
|
||||
if((d = Book.slot(d)).length){ b.list = d } // TODO: BUG! Add some other sort of corrupted/error check here?
|
||||
watch(b).parse = function(t){ return ('string' == typeof t)? Book.decode(Book.slot(t)[0]) : t } // TODO: This was ugly temporary, but is necessary, and is logically correct, but is there a cleaner, nicer, less assumptiony way to do it?
|
||||
watch(b).parse = function(t){ return ('string' == typeof t)? Book.decode(Book.slot(t)[0]) : t } // TODO: This was ugly temporary, but is necessary, and is logically correct, but is there a cleaner, nicer, less assumptiony way to do it? // TODO: SOLUTION?! I think this needs to be in Book, not RAD.
|
||||
r(word, is, reply);
|
||||
})
|
||||
}
|
||||
@ -116,7 +114,8 @@
|
||||
}
|
||||
|
||||
function ename(t){ return encodeURIComponent(t).replace(/\*/g, '%2A').slice(0, 250) }
|
||||
function fname(p){ return opt.file + '/' + ename(p.substring()) }
|
||||
//function fname(p){ return opt.file + '/' + ename(p.substring()) }
|
||||
function fname(p){ return ename(p.substring()) }
|
||||
|
||||
|
||||
function valid(word, is, reply){
|
||||
@ -131,6 +130,7 @@
|
||||
|
||||
return r;
|
||||
}), MAX = 1000/* 300000000 */;
|
||||
sT.each = sT.each || function(l,f){l.forEach(f)};
|
||||
|
||||
try { module.exports = RAD } catch (e){ }
|
||||
|
||||
@ -169,13 +169,13 @@
|
||||
if(!fs){ return }
|
||||
|
||||
var sT = setTimeout, RAD = sT.RAD;
|
||||
RAD.put = function(file, data, cb){
|
||||
fs.writeFile(file, data, cb);
|
||||
RAD.put = function(file, data, cb, opt){
|
||||
fs.writeFile(opt.file+'/'+file, data, cb);
|
||||
}
|
||||
RAD.get = function(file, cb){
|
||||
fs.readFile(file, function(err, data){
|
||||
if(err && 'ENOENT' === (err.code || '').toUpperCase()){ return cb() }
|
||||
cb(err, data.toString());
|
||||
RAD.get = function(file, cb, opt){
|
||||
fs.readFile(opt.file+'/'+file, function(err, data){
|
||||
if(err && 'ENOENT' === (err.code||'').toUpperCase()){ return cb() }
|
||||
cb(err, (data||'').toString()||data);
|
||||
});
|
||||
}
|
||||
}());
|
||||
@ -187,28 +187,30 @@
|
||||
if(!lS){ return }
|
||||
|
||||
var sT = setTimeout, RAD = sT.RAD;
|
||||
RAD.put = function(file, data, cb){
|
||||
RAD.put = function(file, data, cb, opt){
|
||||
setTimeout(function(){
|
||||
lS[file] = data;
|
||||
lS[opt.file+'/'+file] = data;
|
||||
cb(null, 1);
|
||||
},9);
|
||||
},1);
|
||||
}
|
||||
RAD.get = function(file, cb){
|
||||
RAD.get = function(file, cb, opt){
|
||||
setTimeout(function(){
|
||||
cb(null, lS[file]);
|
||||
},9);
|
||||
cb(null, lS[opt.file+'/'+file]);
|
||||
},1);
|
||||
}
|
||||
}());
|
||||
|
||||
;(function(){ return;
|
||||
var get;
|
||||
try { get = fetch } catch (e){ };
|
||||
try { get = fetch } catch (e){ console.log("WARNING! need `npm install node-fetch@2.6`"); get = fetch = require('node-fetch') };
|
||||
if(!get){ return }
|
||||
|
||||
var sT = setTimeout, RAD = sT.RAD;
|
||||
RAD.put = function(file, data, cb){ cb(401) }
|
||||
RAD.get = async function(file, cb){
|
||||
var t = (await (await fetch('http://localhost:8765/gun/'+file)).text());
|
||||
var sT = setTimeout, RAD = sT.RAD, put = RAD.put, get = RAD.get;
|
||||
RAD.put = function(file, data, cb, opt){ put && put(file, data, cb, opt);
|
||||
cb(401)
|
||||
}
|
||||
RAD.get = async function(file, cb, opt){ get && get(file, cb, opt);
|
||||
var t = (await (await fetch('http://localhost:8766/gun/1data/'+file)).text());
|
||||
if('404' == t){ cb(); return }
|
||||
cb(null, t);
|
||||
}
|
||||
|
14
package-lock.json
generated
14
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gun",
|
||||
"version": "0.2020.1237",
|
||||
"version": "0.2020.1239",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -48,7 +48,7 @@
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/addressparser/-/addressparser-0.3.2.tgz",
|
||||
"integrity": "sha1-WYc/Nej89sc2HBAjkmHXbhU0i7I=",
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"ansi-colors": {
|
||||
"version": "3.2.3",
|
||||
@ -299,7 +299,7 @@
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/emailjs/-/emailjs-2.2.0.tgz",
|
||||
"integrity": "sha1-ulsj5KSwpFEPZS6HOxVOlAe2ygM=",
|
||||
"optional": true,
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"addressparser": "^0.3.2",
|
||||
"emailjs-mime-codec": "^2.0.7"
|
||||
@ -309,13 +309,13 @@
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/emailjs-base64/-/emailjs-base64-1.1.4.tgz",
|
||||
"integrity": "sha512-4h0xp1jgVTnIQBHxSJWXWanNnmuc5o+k4aHEpcLXSToN8asjB5qbXAexs7+PEsUKcEyBteNYsSvXUndYT2CGGA==",
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"emailjs-mime-codec": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/emailjs-mime-codec/-/emailjs-mime-codec-2.0.9.tgz",
|
||||
"integrity": "sha512-7qJo4pFGcKlWh/kCeNjmcgj34YoJWY0ekZXEHYtluWg4MVBnXqGM4CRMtZQkfYwitOhUgaKN5EQktJddi/YIDQ==",
|
||||
"optional": true,
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emailjs-base64": "^1.1.4",
|
||||
"ramda": "^0.26.1",
|
||||
@ -810,7 +810,7 @@
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz",
|
||||
"integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==",
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"require-directory": {
|
||||
"version": "2.1.1",
|
||||
@ -887,7 +887,7 @@
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.7.0.tgz",
|
||||
"integrity": "sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==",
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"tslib": {
|
||||
"version": "2.3.0",
|
||||
|
@ -107,7 +107,7 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
|
||||
});
|
||||
|
||||
it('read', function(done){
|
||||
rad('hello', function(err, page){
|
||||
rad('hello', function(page, err){
|
||||
var val = page.get('hello');
|
||||
expect(val).to.be('world');
|
||||
done();
|
||||
@ -144,7 +144,7 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
|
||||
it('save '+type, done => { setTimeout(function(){
|
||||
rad('type-'+type, type, function(err, ok){
|
||||
expect(err).to.not.be.ok();
|
||||
rad('type-'+type, function(err, page){
|
||||
rad('type-'+type, function(page, err){
|
||||
var val = page.get('type-'+type);
|
||||
expect(val).to.be(type);
|
||||
done();
|
||||
@ -154,7 +154,8 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
|
||||
});});
|
||||
|
||||
describe('error on invalid primitives', function(){
|
||||
it('test invalid', done => {
|
||||
console.log("TODO: TESTS! Add invalid data type tests, error checking. HINT: Maybe also add invisible ASCII character tests here too.");
|
||||
it.skip('test invalid', done => {
|
||||
rad('type-NaN', NaN, function(err, ok){
|
||||
expect(err).to.be.ok();
|
||||
done();
|
||||
@ -169,7 +170,7 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
|
||||
var prev = RAD(opt);
|
||||
|
||||
prev('helloz', 'world', function(err, ok){
|
||||
prev('helloz', function(err, page){
|
||||
prev('helloz', function(page, err){
|
||||
prev('zalice', 'yay', function(err){
|
||||
expect(page.text.split('helloz').length).to.be(2);
|
||||
done();
|
||||
@ -182,12 +183,13 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
|
||||
(C) WRITE ONLY: we write a page, and it is new to disk.
|
||||
*/
|
||||
});
|
||||
|
||||
it('make sure word does not get duplicated when data is re-saved after read <', done => {
|
||||
var opt = {file: 'azadata'}
|
||||
var prev = RAD(opt);
|
||||
|
||||
prev('helloz', 'world', function(err, ok){
|
||||
prev('helloz', function(err, page){
|
||||
prev('helloz', function(page, err){
|
||||
prev('azalice', 'yay', function(err){
|
||||
expect(page.text.split('helloz').length).to.be(2);
|
||||
done();
|
||||
@ -280,9 +282,8 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
|
||||
var rad = RAD(opt);
|
||||
rad('pu-alice', 'cool', function(err, ok){
|
||||
expect(err).to.not.be.ok();
|
||||
//return;
|
||||
var next = RAD(opt);
|
||||
next('pu-alice', function(err, page){
|
||||
next('pu-alice', function(page, err){
|
||||
expect('cool').to.be(page.get('pu-alice'));
|
||||
done();
|
||||
})
|
||||
@ -296,8 +297,7 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
|
||||
|
||||
function gen(val){ return val + String.random(99,'a') }
|
||||
var opt = {file: 'gen'}
|
||||
//var rad = window.names = Book();
|
||||
var rad = window.names = RAD(opt);
|
||||
var rad = RAD(opt);
|
||||
it('Generate more than 1 page', done => {
|
||||
|
||||
var i = 0;
|
||||
@ -312,13 +312,12 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
|
||||
});
|
||||
|
||||
it('Make sure parseless lookup works with incrementally parsed values', done => {
|
||||
|
||||
rad = RAD(opt);
|
||||
rad('adora', function(err, page){
|
||||
rad('adora', function(page, err){
|
||||
var n = page.get('adora');
|
||||
expect(gen('adora')).to.be(n);
|
||||
|
||||
rad('aia', function(err, page){
|
||||
rad('aia', function(page, err){
|
||||
var n = page.get('aia');
|
||||
expect(gen('aia')).to.be(n);
|
||||
done();
|
||||
@ -332,7 +331,7 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
|
||||
rad = RAD(opt);
|
||||
names.forEach(function(name){
|
||||
name = name.toLowerCase();
|
||||
rad(name, function(err, page){
|
||||
rad(name+'a', function(page, err){
|
||||
var n = page.get(name);
|
||||
expect(gen(name)).to.be(n);
|
||||
|
||||
@ -340,7 +339,6 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
|
||||
done.c = setTimeout(done, 99);
|
||||
});
|
||||
});
|
||||
console.log("TODO: BUG!!! MARK & ROGOWSKI COME BACK HERE: NOTICED THAT INDEX IS NOT ESCAPED ALTHO THERE MAY BE OTHER THINGS TO DO FIRST!!!");
|
||||
|
||||
});
|
||||
|
||||
@ -357,9 +355,27 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
|
||||
rad('c', r);
|
||||
|
||||
});*/
|
||||
|
||||
it.skip('index metadata', done => {
|
||||
localStorage.clear();
|
||||
var B = setTimeout.Book;
|
||||
var r = setTimeout.RAD();
|
||||
//r('hello', 'world');
|
||||
//return;
|
||||
var i = 200; while(--i){ r('store'+i, Math.random()+'r'+Math.random()) }
|
||||
console.log('switch test to a test of replication, maybe with panic');
|
||||
r('store150', function(page, err){
|
||||
console.log("<<<<<<<<<");
|
||||
page.meta = 'https://localhost:9876,https://localhost:9877';
|
||||
var i = 200; while(--i){ r('store'+i+'b', Math.random()+'r'+Math.random()) }
|
||||
console.log(">>>>>>>>>");
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
console.log("Performance Tests: 2023 Nov 12, 60M put/sec, 120M get/sec, 1M get/sec with splits.");
|
||||
|
||||
});
|
||||
|
||||
var ntmp = names;
|
||||
|
Loading…
x
Reference in New Issue
Block a user