autobee 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +198 -13
- package/lib/fast-forward.js +71 -0
- package/lib/topo.js +27 -7
- package/lib/writers.js +22 -3
- package/package.json +5 -3
package/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
const ReadyResource = require('ready-resource')
|
|
2
|
+
const ReadyGuard = require('ready-guard')
|
|
2
3
|
const b4a = require('b4a')
|
|
3
4
|
const safetyCatch = require('safety-catch')
|
|
4
5
|
const Hyperbee = require('hyperbee2')
|
|
5
6
|
const ID = require('hypercore-id-encoding')
|
|
7
|
+
const rrp = require('resolve-reject-promise')
|
|
6
8
|
const { AutobeeEncryption, WriterEncryption } = require('autobee-encryption')
|
|
7
9
|
const AutobeeWakeup = require('autobee-wakeup')
|
|
8
10
|
const Hypercore = require('hypercore')
|
|
@@ -11,6 +13,7 @@ const c = require('compact-encoding')
|
|
|
11
13
|
const asserts = require('./lib/asserts.js')
|
|
12
14
|
const boot = require('./lib/boot.js')
|
|
13
15
|
const encoding = require('./lib/encoding.js')
|
|
16
|
+
const FastForward = require('./lib/fast-forward.js')
|
|
14
17
|
const System = require('./lib/system.js')
|
|
15
18
|
const ApplyCalls = require('./lib/apply-calls.js')
|
|
16
19
|
const topo = require('./lib/topo.js')
|
|
@@ -19,6 +22,7 @@ const UpdateChanges = require('./lib/updates.js')
|
|
|
19
22
|
|
|
20
23
|
const EMPTY_HEAD = { length: 0, key: null }
|
|
21
24
|
const INTERRUPT = new Error('Apply interrupted')
|
|
25
|
+
const MIN_FF_GAP = 32
|
|
22
26
|
|
|
23
27
|
module.exports = class Autobee extends ReadyResource {
|
|
24
28
|
constructor(store, key = null, handlers = {}) {
|
|
@@ -32,14 +36,15 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
32
36
|
const { name = null, encrypted, encryptionKey } = handlers
|
|
33
37
|
|
|
34
38
|
this.encrypted = encrypted === true || !!encryptionKey
|
|
39
|
+
this._getEncryptionProviderBound = this._getEncryptionProvider.bind(this)
|
|
35
40
|
|
|
36
41
|
const bee = new Hyperbee(store.namespace('view'), {
|
|
37
42
|
// defer one tick to ensure consistent state, then return state prom
|
|
38
43
|
preload: async () => {
|
|
39
44
|
await 1
|
|
40
|
-
await this.
|
|
45
|
+
if (!this._bootGuard.opened) await this._bootGuard.ready()
|
|
41
46
|
},
|
|
42
|
-
getEncryptionProvider:
|
|
47
|
+
getEncryptionProvider: this._getEncryptionProviderBound
|
|
43
48
|
})
|
|
44
49
|
|
|
45
50
|
this.store = store
|
|
@@ -50,7 +55,7 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
50
55
|
this.bootstrap = null
|
|
51
56
|
|
|
52
57
|
this.system = new System(this.store.namespace('system'), this.name, {
|
|
53
|
-
getEncryptionProvider:
|
|
58
|
+
getEncryptionProvider: this._getEncryptionProviderBound,
|
|
54
59
|
encrypted: this.encrypted
|
|
55
60
|
})
|
|
56
61
|
|
|
@@ -66,12 +71,18 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
66
71
|
this.writers = null
|
|
67
72
|
this.bumping = 0
|
|
68
73
|
|
|
74
|
+
this.fastForwardBoot = handlers.fastForward || null
|
|
75
|
+
this.fastForward = null
|
|
76
|
+
this.fastForwarding = null
|
|
77
|
+
this.fastForwardTo = null
|
|
78
|
+
|
|
69
79
|
this._workingBee = bee
|
|
70
80
|
this._workingView = handlers.open ? handlers.open(this._workingBee, this) : this._workingBee
|
|
71
81
|
|
|
72
82
|
this._appending = []
|
|
73
83
|
this._draining = null
|
|
74
84
|
|
|
85
|
+
this._bootGuard = new ReadyGuard()
|
|
75
86
|
this._bootingState = null
|
|
76
87
|
this._bootingAll = null
|
|
77
88
|
|
|
@@ -81,13 +92,16 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
81
92
|
this._needsUpdate = false
|
|
82
93
|
this._updateLocalCore = null
|
|
83
94
|
this._host = new ApplyCalls(this)
|
|
95
|
+
this._notifyHandler = null
|
|
84
96
|
|
|
85
97
|
this.interrupted = null
|
|
86
98
|
this._interrupting = false
|
|
87
99
|
this._onErrorBound = this._onError.bind(this)
|
|
100
|
+
this._bumpSoonBound = this.bumpSoon.bind(this)
|
|
88
101
|
|
|
89
|
-
this._wakeup = new AutobeeWakeup(this, handlers)
|
|
90
102
|
this.wakeupCapability = null
|
|
103
|
+
this._wakeup = new AutobeeWakeup(this, handlers)
|
|
104
|
+
this._previousDrain = 0
|
|
91
105
|
|
|
92
106
|
this.ready().catch(noop)
|
|
93
107
|
}
|
|
@@ -140,7 +154,7 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
140
154
|
return keys
|
|
141
155
|
}
|
|
142
156
|
|
|
143
|
-
|
|
157
|
+
getWriterViews(key) {
|
|
144
158
|
const id = b4a.toString(key, 'hex')
|
|
145
159
|
const w = this.writers.active.get(id)
|
|
146
160
|
if (!w) return []
|
|
@@ -160,6 +174,7 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
160
174
|
|
|
161
175
|
async _close() {
|
|
162
176
|
this._interrupting = true
|
|
177
|
+
if (this._notifyHandler) this._notifyHandler.destroy()
|
|
163
178
|
if (this._draining) await this._draining
|
|
164
179
|
|
|
165
180
|
if (this._handlers.close) await this._handlers.close(this.view)
|
|
@@ -215,6 +230,8 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
215
230
|
}
|
|
216
231
|
|
|
217
232
|
async _bootState() {
|
|
233
|
+
if (!this._bootGuard.enter()) return this._bootGuard.ready()
|
|
234
|
+
|
|
218
235
|
const result = await boot(this.store, this.key, {
|
|
219
236
|
encryptionKey: this.encryptionKey,
|
|
220
237
|
keyPair: this.keyPair
|
|
@@ -244,6 +261,13 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
244
261
|
|
|
245
262
|
this._registerWakeup()
|
|
246
263
|
|
|
264
|
+
if (this.bootstrap !== this.local) {
|
|
265
|
+
await this.bootstrap.setGroup(this.wakeupCapability.discoveryKey)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
this._notifyHandler = this.store.notifyGroup(this.wakeupCapability.discoveryKey)
|
|
269
|
+
this._notifyHandler.on('update', this._bumpSoonBound)
|
|
270
|
+
|
|
247
271
|
const system = result.system || EMPTY_HEAD
|
|
248
272
|
|
|
249
273
|
await this.system.boot(system)
|
|
@@ -256,10 +280,14 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
256
280
|
this.bee.move(view)
|
|
257
281
|
|
|
258
282
|
await this.writers.updateLocalState()
|
|
283
|
+
|
|
284
|
+
this._bootGuard.exit()
|
|
285
|
+
|
|
286
|
+
return this._bootGuard.ready()
|
|
259
287
|
}
|
|
260
288
|
|
|
261
289
|
async _bootAll() {
|
|
262
|
-
await this.
|
|
290
|
+
if (!this._bootGuard.opened) await this._bootGuard.ready()
|
|
263
291
|
|
|
264
292
|
for await (const node of this.system.list()) {
|
|
265
293
|
await this.writers.add(node.key)
|
|
@@ -272,7 +300,10 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
272
300
|
}
|
|
273
301
|
|
|
274
302
|
async _bump() {
|
|
303
|
+
if (!this._bootGuard.opened) await this._bootGuard.ready()
|
|
304
|
+
|
|
275
305
|
await this._flushWakeup()
|
|
306
|
+
|
|
276
307
|
this.bumping++
|
|
277
308
|
|
|
278
309
|
if (!this._draining) {
|
|
@@ -327,18 +358,30 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
327
358
|
}
|
|
328
359
|
|
|
329
360
|
async _drain() {
|
|
330
|
-
if (this.
|
|
331
|
-
|
|
361
|
+
if (this.fastForwardBoot) {
|
|
362
|
+
this._initFastForward(this.fastForwardBoot)
|
|
363
|
+
this.fastForwardBoot = null
|
|
332
364
|
}
|
|
333
365
|
|
|
334
366
|
const changes = this._hasUpdate ? new UpdateChanges(this) : null
|
|
335
367
|
if (changes) changes.track()
|
|
336
368
|
|
|
369
|
+
// Anything expecting work to be done during bumpSoon should do it here
|
|
337
370
|
while (!this._interrupting && this.bumping > 0) {
|
|
338
|
-
if (this._interrupting)
|
|
371
|
+
if (this._interrupting) break
|
|
372
|
+
|
|
373
|
+
// Ensure we catch updates during the drain (i.e. setLocal will bump)
|
|
374
|
+
if (this._updateLocalCore !== null) {
|
|
375
|
+
await this._rotateLocalWriter(this._updateLocalCore)
|
|
376
|
+
}
|
|
339
377
|
|
|
340
378
|
try {
|
|
341
379
|
while (!this._interrupting) {
|
|
380
|
+
if (this.fastForwardTo !== null) {
|
|
381
|
+
await this._applyFastForward()
|
|
382
|
+
break // revaluate conditions...
|
|
383
|
+
}
|
|
384
|
+
|
|
342
385
|
if (!(await this._bumpPendingWriters())) break
|
|
343
386
|
this._needsUpdate = true
|
|
344
387
|
}
|
|
@@ -361,6 +404,14 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
361
404
|
async _flushWakeup() {
|
|
362
405
|
const hints = this._wakeup.flush()
|
|
363
406
|
|
|
407
|
+
for await (const key of this._notifyHandler.updates({ since: this.previousDrain })) {
|
|
408
|
+
const hex = b4a.toString(key, 'hex')
|
|
409
|
+
hints.set(hex, -1)
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
this.previousDrain = Date.now()
|
|
413
|
+
this.queueWakeupFastForward(hints).catch(noop)
|
|
414
|
+
|
|
364
415
|
for (const [hex, length] of hints) {
|
|
365
416
|
const key = b4a.from(hex, 'hex')
|
|
366
417
|
if (this.writers.has(hex)) continue
|
|
@@ -372,6 +423,25 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
372
423
|
}
|
|
373
424
|
}
|
|
374
425
|
|
|
426
|
+
_initFastForward({ key, length }) {
|
|
427
|
+
this.moveTo({ key, length })
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
async _getOplog(key, length) {
|
|
431
|
+
const core = this.openCore(key)
|
|
432
|
+
await core.ready()
|
|
433
|
+
|
|
434
|
+
const target = length >= 0 ? length : core.length
|
|
435
|
+
if (target === 0) return null
|
|
436
|
+
|
|
437
|
+
const buf = await core.get(target - 1)
|
|
438
|
+
await core.close()
|
|
439
|
+
|
|
440
|
+
if (buf === null) return null
|
|
441
|
+
|
|
442
|
+
return encoding.decodeOplog(buf)
|
|
443
|
+
}
|
|
444
|
+
|
|
375
445
|
_update(changes) {
|
|
376
446
|
this._needsUpdate = false
|
|
377
447
|
this.bee.update(this._workingBee.root)
|
|
@@ -407,7 +477,7 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
407
477
|
|
|
408
478
|
let runs = 0
|
|
409
479
|
while (!this._interrupting && this.appending && runs++ < 16) await this.update()
|
|
410
|
-
|
|
480
|
+
this.bumpSoon()
|
|
411
481
|
}
|
|
412
482
|
|
|
413
483
|
async _rotateLocalWriter(newLocal) {
|
|
@@ -573,6 +643,10 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
573
643
|
this._workingBee.move(t.view)
|
|
574
644
|
}
|
|
575
645
|
|
|
646
|
+
return this._processApplyBatch(t)
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
async _processApplyBatch(t) {
|
|
576
650
|
// first writer is always added with full permissions
|
|
577
651
|
if (this.system.isGenesis()) {
|
|
578
652
|
await this._host.addWriter(t.tip[0][0].key)
|
|
@@ -623,7 +697,7 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
623
697
|
}
|
|
624
698
|
|
|
625
699
|
async wakeup({ key, length }) {
|
|
626
|
-
await this.
|
|
700
|
+
if (!this._bootGuard.opened) await this._bootGuard.ready()
|
|
627
701
|
await this.writers.wakeup(key, length)
|
|
628
702
|
await this._bump()
|
|
629
703
|
}
|
|
@@ -655,8 +729,119 @@ module.exports = class Autobee extends ReadyResource {
|
|
|
655
729
|
await this.writers.flushLocal(this._workingBee.head())
|
|
656
730
|
}
|
|
657
731
|
|
|
658
|
-
|
|
659
|
-
|
|
732
|
+
moveTo(head, tip) {
|
|
733
|
+
if (this.fastForwardTo !== null || this.fastForwarding !== null) return null
|
|
734
|
+
return this._runFastForward(new FastForward(this, head, tip)).catch(noop)
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
async queueWakeupFastForward(hints) {
|
|
738
|
+
if (!this._handlers.onwakeup) return false
|
|
739
|
+
if (!hints.size || this.fastForwarding || this.fastForwardTo || this.fastForwardBoot) {
|
|
740
|
+
return false
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
const promises = []
|
|
744
|
+
for (const [hex, length] of hints) {
|
|
745
|
+
if (length === 0) continue
|
|
746
|
+
const key = b4a.from(hex, 'hex')
|
|
747
|
+
promises.push(this._getOplog(key, length))
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
const ops = await Promise.all(promises)
|
|
751
|
+
if (this.fastForwarding || this.fastForwardTo) return false
|
|
752
|
+
|
|
753
|
+
let best = null
|
|
754
|
+
let bestFlushes = -1
|
|
755
|
+
|
|
756
|
+
for (const msg of ops) {
|
|
757
|
+
if (msg === null) continue
|
|
758
|
+
|
|
759
|
+
if (msg.views && msg.views.flushes > bestFlushes) {
|
|
760
|
+
bestFlushes = msg.views.flushes
|
|
761
|
+
best = msg.views
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
if (best === null || bestFlushes - this.system.flushes < MIN_FF_GAP) return false
|
|
766
|
+
|
|
767
|
+
const view = this.bee.checkout(best.view)
|
|
768
|
+
|
|
769
|
+
let trusted = null
|
|
770
|
+
try {
|
|
771
|
+
trusted = await this._handlers.onwakeup(view, this)
|
|
772
|
+
if (!trusted || this.fastForwarding || this.fastForwardTo) return false
|
|
773
|
+
} finally {
|
|
774
|
+
view.close()
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
const oplog = await this._getOplog(trusted.key, trusted.length)
|
|
778
|
+
|
|
779
|
+
return this.moveTo(oplog.views.system, {
|
|
780
|
+
system: best.system,
|
|
781
|
+
verified: {
|
|
782
|
+
node: trusted,
|
|
783
|
+
flushes: oplog.views.flushes
|
|
784
|
+
}
|
|
785
|
+
})
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
async _runFastForward(ff) {
|
|
789
|
+
this.fastForwarding = ff
|
|
790
|
+
|
|
791
|
+
const result = await ff.upgrade()
|
|
792
|
+
await ff.close()
|
|
793
|
+
|
|
794
|
+
if (this.fastForwarding === ff) this.fastForwarding = null
|
|
795
|
+
|
|
796
|
+
if (!result) return null
|
|
797
|
+
|
|
798
|
+
this.fastForwardTo = result
|
|
799
|
+
this.fastForward = rrp()
|
|
800
|
+
|
|
801
|
+
this.bumpSoon()
|
|
802
|
+
|
|
803
|
+
return this.fastForward.promise
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
async _applyFastForward() {
|
|
807
|
+
const changes = this._hasUpdate ? new UpdateChanges(this) : null
|
|
808
|
+
if (changes) changes.track(this._applyState)
|
|
809
|
+
|
|
810
|
+
const { head, tip } = this.fastForwardTo
|
|
811
|
+
|
|
812
|
+
const from = this.system.bee.head()
|
|
813
|
+
const to = head
|
|
814
|
+
|
|
815
|
+
this.system.bee.move(head)
|
|
816
|
+
await this.system.reset()
|
|
817
|
+
|
|
818
|
+
this.bee.move(this.system.view)
|
|
819
|
+
this._workingBee.move(this.system.view)
|
|
820
|
+
|
|
821
|
+
this.fastForwardTo = null
|
|
822
|
+
|
|
823
|
+
await this.writers.refresh()
|
|
824
|
+
|
|
825
|
+
if (changes) {
|
|
826
|
+
changes.finalise()
|
|
827
|
+
await this._handlers.update(this.view, changes)
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
this.emit('move-to', to, from)
|
|
831
|
+
this.fastForward.resolve({ to, from })
|
|
832
|
+
|
|
833
|
+
// tip is null when handlers.fastForward set
|
|
834
|
+
if (!tip) return
|
|
835
|
+
|
|
836
|
+
return this._reapply(tip)
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
async _reapply({ system, verified }) {
|
|
840
|
+
const sys = this.system.bee.checkout(system)
|
|
841
|
+
const t = await topo.rollback(this, sys, verified)
|
|
842
|
+
await sys.close()
|
|
843
|
+
|
|
844
|
+
return this._processApplyBatch(t)
|
|
660
845
|
}
|
|
661
846
|
}
|
|
662
847
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const safetyCatch = require('safety-catch')
|
|
2
|
+
|
|
3
|
+
const System = require('./system.js')
|
|
4
|
+
|
|
5
|
+
const DEFAULT_OP_TIMEOUT = 5_000
|
|
6
|
+
|
|
7
|
+
module.exports = class FastForward {
|
|
8
|
+
constructor(auto, head, tip, { timeout = DEFAULT_OP_TIMEOUT } = {}) {
|
|
9
|
+
this.auto = auto
|
|
10
|
+
this.system = new System(auto.store.namespace('fast-forward'), null, {
|
|
11
|
+
getEncryptionProvider: this.auto._getEncryptionProviderBound,
|
|
12
|
+
encrypted: this.encrypted
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
this.head = head
|
|
16
|
+
this.timeout = timeout
|
|
17
|
+
this.tip = tip || null
|
|
18
|
+
this.destroyed = false
|
|
19
|
+
this.upgrading = null
|
|
20
|
+
this.failed = false
|
|
21
|
+
this.cores = []
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async upgrade() {
|
|
25
|
+
try {
|
|
26
|
+
if (!this.upgrading) this.upgrading = this._upgrade()
|
|
27
|
+
|
|
28
|
+
if (!(await this.upgrading)) return null
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
head: this.head,
|
|
32
|
+
tip: this.tip
|
|
33
|
+
}
|
|
34
|
+
} catch (err) {
|
|
35
|
+
safetyCatch(err)
|
|
36
|
+
this.failed = true
|
|
37
|
+
return null
|
|
38
|
+
} finally {
|
|
39
|
+
await this.close()
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async _upgrade() {
|
|
44
|
+
await this.system.boot(this.head)
|
|
45
|
+
|
|
46
|
+
const promises = []
|
|
47
|
+
|
|
48
|
+
// ensure local key is locally available always
|
|
49
|
+
promises.push(this.system.get(this.auto.local.key, { timeout: this.timeout }))
|
|
50
|
+
|
|
51
|
+
const view = this.auto.store.get({ key: this.system.view.key, active: true })
|
|
52
|
+
this.cores.push(view)
|
|
53
|
+
|
|
54
|
+
promises.push(view.get(this.system.view.length - 1, { timeout: this.timeout }))
|
|
55
|
+
|
|
56
|
+
for (const head of this.system.heads) {
|
|
57
|
+
promises.push(this.system.get(head.key, { timeout: this.timeout }))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
await Promise.all(promises)
|
|
61
|
+
if (this.destroyed) return false
|
|
62
|
+
|
|
63
|
+
return true
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async close() {
|
|
67
|
+
this.destroyed = true
|
|
68
|
+
if (this.system) await this.system.close()
|
|
69
|
+
for (const core of this.cores) await core.close()
|
|
70
|
+
}
|
|
71
|
+
}
|
package/lib/topo.js
CHANGED
|
@@ -5,8 +5,8 @@ const asserts = require('./asserts.js')
|
|
|
5
5
|
|
|
6
6
|
const EMPTY_HEAD = { length: 0, key: null }
|
|
7
7
|
|
|
8
|
-
exports.replay = replay
|
|
9
8
|
exports.sort = sort
|
|
9
|
+
exports.rollback = rollback
|
|
10
10
|
|
|
11
11
|
exports.isLinking = isLinking
|
|
12
12
|
exports.isLinkingAll = isLinkingAll
|
|
@@ -29,17 +29,29 @@ class Clock {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
async function
|
|
33
|
-
const
|
|
34
|
-
const
|
|
32
|
+
async function rollback(auto, system, verified) {
|
|
33
|
+
const tip = []
|
|
34
|
+
const ch = system.createChangesStream()
|
|
35
35
|
|
|
36
36
|
for await (const data of ch) {
|
|
37
37
|
const { ref, info } = getOplog(data)
|
|
38
|
-
|
|
38
|
+
if (sameNode(ref.oplog, verified.node)) {
|
|
39
|
+
asserts.assert(info.flushes === verified.flushes, 'Expect tip to be continuous')
|
|
40
|
+
break
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
tip.push(ref)
|
|
39
44
|
}
|
|
40
45
|
|
|
41
|
-
const inflated = await inflate(auto,
|
|
42
|
-
|
|
46
|
+
const inflated = await inflate(auto, tip)
|
|
47
|
+
|
|
48
|
+
// @todo: verify sort
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
undo: null,
|
|
52
|
+
view: null,
|
|
53
|
+
tip: inflated.map(getBatch)
|
|
54
|
+
}
|
|
43
55
|
}
|
|
44
56
|
|
|
45
57
|
async function sort(auto, batch) {
|
|
@@ -269,3 +281,11 @@ function isLinkingAll(node, heads) {
|
|
|
269
281
|
|
|
270
282
|
return true
|
|
271
283
|
}
|
|
284
|
+
|
|
285
|
+
function sameNode(a, b) {
|
|
286
|
+
return b4a.equals(a.key, b.key) && a.length === b.length
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function getBatch(b) {
|
|
290
|
+
return b.batch
|
|
291
|
+
}
|
package/lib/writers.js
CHANGED
|
@@ -37,7 +37,7 @@ class ActiveWriters {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
bump() {
|
|
40
|
-
this.auto.
|
|
40
|
+
this.auto.bumpSoon()
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
async wakeup(key, length) {
|
|
@@ -66,6 +66,7 @@ class ActiveWriters {
|
|
|
66
66
|
|
|
67
67
|
this.localWriter = new Writer(this, this.auto.system, true, core, b4a.toString(core.key, 'hex'))
|
|
68
68
|
this.localWriter.addPending()
|
|
69
|
+
this.auto.emit('writer', this.localWriter)
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
clearLocal() {
|
|
@@ -76,6 +77,20 @@ class ActiveWriters {
|
|
|
76
77
|
return this.localWriter.flush(head)
|
|
77
78
|
}
|
|
78
79
|
|
|
80
|
+
async refresh() {
|
|
81
|
+
if (this.localWriter && !this.localWriter.closed) {
|
|
82
|
+
await this.updateLocalState()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
for (const writer of this.active.values()) {
|
|
86
|
+
await writer.update()
|
|
87
|
+
|
|
88
|
+
if (writer !== this.localWriter && !writer.isIndexer) {
|
|
89
|
+
await writer.detachAndClose()
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
79
94
|
async updateLocalState() {
|
|
80
95
|
const w = this.localWriter
|
|
81
96
|
const bootstrapping = w.core.length === 0 && b4a.equals(this.auto.key, w.core.key)
|
|
@@ -96,7 +111,8 @@ class ActiveWriters {
|
|
|
96
111
|
}
|
|
97
112
|
|
|
98
113
|
async add(key) {
|
|
99
|
-
|
|
114
|
+
const local = b4a.equals(key, this.auto.local.key)
|
|
115
|
+
if (local) await this.updateLocalState()
|
|
100
116
|
|
|
101
117
|
const id = b4a.toString(key, 'hex')
|
|
102
118
|
let w = this.active.get(id)
|
|
@@ -109,8 +125,10 @@ class ActiveWriters {
|
|
|
109
125
|
|
|
110
126
|
const core = this.auto.store.get({
|
|
111
127
|
key,
|
|
112
|
-
encryption
|
|
128
|
+
encryption,
|
|
129
|
+
group: local ? null : this.auto.wakeupCapability.discoveryKey
|
|
113
130
|
})
|
|
131
|
+
|
|
114
132
|
await core.ready()
|
|
115
133
|
await core.setUserData('referrer', this.auto.key)
|
|
116
134
|
|
|
@@ -239,6 +257,7 @@ class Writer {
|
|
|
239
257
|
if (this.isAttached) return
|
|
240
258
|
this.isAttached = true
|
|
241
259
|
this.writers.active.set(this.id, this)
|
|
260
|
+
this.writers.auto.emit('writer', this)
|
|
242
261
|
this.addPending()
|
|
243
262
|
}
|
|
244
263
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autobee",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Bee based autobase",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Holepunch Inc.",
|
|
@@ -28,15 +28,17 @@
|
|
|
28
28
|
"b4a": "^1.8.0",
|
|
29
29
|
"compact-encoding": "^2.18.0",
|
|
30
30
|
"hyperbee2": "^2.8.0",
|
|
31
|
-
"hypercore": "^11.
|
|
31
|
+
"hypercore": "^11.33.0",
|
|
32
32
|
"hypercore-id-encoding": "^1.3.0",
|
|
33
33
|
"hyperschema": "^1.20.1",
|
|
34
|
+
"ready-guard": "^1.0.0",
|
|
34
35
|
"ready-resource": "^1.2.0",
|
|
36
|
+
"resolve-reject-promise": "^1.1.0",
|
|
35
37
|
"safety-catch": "^1.0.3"
|
|
36
38
|
},
|
|
37
39
|
"devDependencies": {
|
|
38
40
|
"brittle": "^3.19.1",
|
|
39
|
-
"corestore": "^7.
|
|
41
|
+
"corestore": "^7.10.0",
|
|
40
42
|
"hypercore-crypto": "^3.6.1",
|
|
41
43
|
"lunte": "^1.6.0",
|
|
42
44
|
"prettier": "^3.8.1",
|