-
Notifications
You must be signed in to change notification settings - Fork 0
/
browser.js
116 lines (97 loc) · 2.6 KB
/
browser.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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
require('indexeddbshim/dist/indexeddbshim.js')
// iOS8 homescreen bug with window.indexedDB readonly and null
// shimmed mozIndexedDb is picked up by IDBWrapper
if (!window.indexedDB) window.mozIndexedDB = window.shimIndexedDB
var sublevel = require('level-sublevel')
var map = require('map-stream')
var stringify = require('json-stable-stringify')
module.exports = airplanedb
function airplanedb (db) {
if (db.sync) return db
db = sublevel(db)
var changelog = db.sublevel('changelog')
var lastSync = db.sublevel('lastsync')
var replicating = {}
var hook
function addHook () {
if (!hook) hook = db.pre(addChange)
}
function removeHook () {
if (hook) hook()
hook = null
}
function running () {
return !!hook
}
addHook()
function addChange (ch, add, batch) {
if (ch.key in replicating) {
var value = replicating[ch.key]
delete replicating[ch.key]
if (stringify(ch.value) === stringify(value)) return
}
add({
key: ch.key,
value: {
type: ch.type
},
type: 'put',
prefix: changelog
})
}
db.sync = sync
db.sync.on = addHook
db.sync.running = running
db.sync.off = removeHook
return db
function sync (range, remotedb, cb) {
var stringRange = stringify(range)
changelog.createReadStream(range)
.pipe(map(replicateTo))
.on('error', cb)
.on('end', syncFrom)
function replicateTo (item, cb) {
if (item.value.type === 'del') {
remotedb.del(item.key, done)
} else {
db.get(item.key, function (err, value) {
if (err) return done(err)
remotedb.put(item.key, value, done)
})
}
function done (err) {
if (err) return cb(err)
changelog.del(item.key, cb)
}
}
function syncFrom () {
lastSync.get(stringRange, function ts (_, from) {
remotedb.sync(from, range).pipe(map(replicateFrom))
.on('error', cb)
.on('end', cb)
})
var maxTs = ''
function replicateFrom (item, cb) {
var ts = item.key.slice(-28, -4)
var method = item.key.slice(-3)
var key = item.key.slice(0, -29)
if (method === 'del') {
replicating[key] = undefined
db.del(key, done)
} else {
replicating[key] = item.value
db.put(key, item.value, done)
}
function done (err) {
if (err) return cb(err)
if (ts > maxTs) {
lastSync.put(stringRange, ts.slice(0, -1) + '\xff', cb)
maxTs = ts
} else {
cb()
}
}
}
}
}
}