-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
localStorage.js
69 lines (60 loc) · 3.13 KB
/
localStorage.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
;(function(){
if(typeof Gun === 'undefined'){ return }
var noop = function(){}, store, u;
try{store = (Gun.window||noop).localStorage}catch(e){}
if(!store){
Gun.log("Warning: No localStorage exists to persist data to!");
store = {setItem: function(k,v){this[k]=v}, removeItem: function(k){delete this[k]}, getItem: function(k){return this[k]}};
}
var parse = JSON.parseAsync || function(t,cb,r){ var u; try{ cb(u, JSON.parse(t,r)) }catch(e){ cb(e) } }
var json = JSON.stringifyAsync || function(v,cb,r,s){ var u; try{ cb(u, JSON.stringify(v,r,s)) }catch(e){ cb(e) } }
Gun.on('create', function lg(root){
this.to.next(root);
var opt = root.opt, graph = root.graph, acks = [], disk, to, size, stop;
if(false === opt.localStorage){ return }
opt.prefix = opt.file || 'gun/';
try{ disk = lg[opt.prefix] = lg[opt.prefix] || JSON.parse(size = store.getItem(opt.prefix)) || {}; // TODO: Perf! This will block, should we care, since limited to 5MB anyways?
}catch(e){ disk = lg[opt.prefix] = {}; }
size = (size||'').length;
root.on('get', function(msg){
this.to.next(msg);
var lex = msg.get, soul, data, tmp, u;
if(!lex || !(soul = lex['#'])){ return }
data = disk[soul] || u;
if(data && (tmp = lex['.']) && !Object.plain(tmp)){ // pluck!
data = Gun.state.ify({}, tmp, Gun.state.is(data, tmp), data[tmp], soul);
}
//if(data){ (tmp = {})[soul] = data } // back into a graph.
//setTimeout(function(){
Gun.on.get.ack(msg, data); //root.on('in', {'@': msg['#'], put: tmp, lS:1});// || root.$});
//}, Math.random() * 10); // FOR TESTING PURPOSES!
});
root.on('put', function(msg){
this.to.next(msg); // remember to call next middleware adapter
var put = msg.put, soul = put['#'], key = put['.'], id = msg['#'], ok = msg.ok||'', tmp; // pull data off wire envelope
disk[soul] = Gun.state.ify(disk[soul], key, put['>'], put[':'], soul); // merge into disk object
if(stop && size > (4999880)){ root.on('in', {'@': id, err: "localStorage max!"}); return; }
//if(!msg['@']){ acks.push(id) } // then ack any non-ack write. // TODO: use batch id.
if(!msg['@'] && (!msg._.via || Math.random() < (ok['@'] / ok['/']))){ acks.push(id) } // then ack any non-ack write. // TODO: use batch id.
if(to){ return }
to = setTimeout(flush, 9+(size / 333)); // 0.1MB = 0.3s, 5MB = 15s
});
function flush(){
if(!acks.length && ((setTimeout.turn||'').s||'').length){ setTimeout(flush,99); return; } // defer if "busy" && no saves.
var err, ack = acks; clearTimeout(to); to = false; acks = [];
json(disk, function(err, tmp){
try{!err && store.setItem(opt.prefix, tmp);
}catch(e){ err = stop = e || "localStorage failure" }
if(err){
Gun.log(err + " Consider using GUN's IndexedDB plugin for RAD for more storage space, https://gun.eco/docs/RAD#install");
root.on('localStorage:error', {err: err, get: opt.prefix, put: disk});
}
size = tmp.length;
//if(!err && !Object.empty(opt.peers)){ return } // only ack if there are no peers. // Switch this to probabilistic mode
setTimeout.each(ack, function(id){
root.on('in', {'@': id, err: err, ok: 0}); // localStorage isn't reliable, so make its `ok` code be a low number.
},0,99);
})
}
});
}());