corestore 6.0.1-alpha.8 → 6.0.1-alpha.9

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.
Files changed (3) hide show
  1. package/index.js +31 -25
  2. package/package.json +2 -1
  3. package/test/all.js +40 -0
package/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const { EventEmitter } = require('events')
2
+ const safetyCatch = require('safety-catch')
2
3
  const crypto = require('hypercore-crypto')
3
4
  const sodium = require('sodium-universal')
4
5
  const Hypercore = require('hypercore')
@@ -37,11 +38,11 @@ module.exports = class Corestore extends EventEmitter {
37
38
  }
38
39
 
39
40
  async _generateKeys (opts) {
40
- if (opts.discoveryKey) {
41
+ if (opts._discoveryKey) {
41
42
  return {
42
43
  keyPair: null,
43
44
  sign: null,
44
- discoveryKey: opts.discoveryKey
45
+ discoveryKey: opts._discoveryKey
45
46
  }
46
47
  }
47
48
  if (!opts.name) {
@@ -94,8 +95,10 @@ module.exports = class Corestore extends EventEmitter {
94
95
 
95
96
  while (this.cores.has(id)) {
96
97
  const existing = this.cores.get(id)
97
- if (existing) {
98
- if (!existing.closing) return { from: existing, keyPair, sign }
98
+ if (existing.opened && !existing.closing) return { from: existing, keyPair, sign }
99
+ if (!existing.opened) {
100
+ await existing.ready().catch(safetyCatch)
101
+ } else if (existing.closing) {
99
102
  await existing.close()
100
103
  }
101
104
  }
@@ -110,22 +113,28 @@ module.exports = class Corestore extends EventEmitter {
110
113
 
111
114
  const storageRoot = [CORES_DIR, id.slice(0, 2), id.slice(2, 4), id].join('/')
112
115
  const core = new Hypercore(p => this.storage(storageRoot + '/' + p), {
116
+ _preready: this._preready.bind(this),
113
117
  autoClose: true,
114
118
  encryptionKey: opts.encryptionKey || null,
115
- keyPair: {
116
- publicKey: keyPair.publicKey,
117
- secretKey: null
118
- },
119
119
  userData,
120
120
  sign: null,
121
- _preready: this._preready.bind(this),
122
- createIfMissing: !!opts.keyPair
121
+ createIfMissing: !opts._discoveryKey,
122
+ keyPair: keyPair && keyPair.publicKey
123
+ ? {
124
+ publicKey: keyPair.publicKey,
125
+ secretKey: null
126
+ }
127
+ : null
123
128
  })
124
129
 
125
130
  this.cores.set(id, core)
126
- for (const { stream } of this._replicationStreams) {
127
- core.replicate(stream)
128
- }
131
+ core.ready().then(() => {
132
+ for (const { stream } of this._replicationStreams) {
133
+ core.replicate(stream)
134
+ }
135
+ }, () => {
136
+ this.cores.delete(id)
137
+ })
129
138
  core.once('close', () => {
130
139
  this.cores.delete(id)
131
140
  })
@@ -145,18 +154,16 @@ module.exports = class Corestore extends EventEmitter {
145
154
 
146
155
  replicate (isInitiator, opts) {
147
156
  const isExternal = isStream(isInitiator) || !!(opts && opts.stream)
148
- const stream = Hypercore.createProtocolStream(isInitiator, opts)
157
+ const stream = Hypercore.createProtocolStream(isInitiator, {
158
+ ...opts,
159
+ ondiscoverykey: discoveryKey => {
160
+ const core = this.get({ _discoveryKey: discoveryKey })
161
+ return core.ready().catch(safetyCatch)
162
+ }
163
+ })
149
164
  for (const core of this.cores.values()) {
150
- core.replicate(stream)
165
+ if (core.opened) core.replicate(stream) // If the core is not opened, it will be replicated in preload.
151
166
  }
152
- stream.on('discovery-key', discoveryKey => {
153
- const core = this.get({ discoveryKey })
154
- core.ready().then(() => {
155
- core.replicate(stream)
156
- }, () => {
157
- stream.close(discoveryKey)
158
- })
159
- })
160
167
  const streamRecord = { stream, isExternal }
161
168
  this._replicationStreams.push(streamRecord)
162
169
  stream.once('close', () => {
@@ -216,8 +223,7 @@ function validateGetOptions (opts) {
216
223
  if (opts.name && opts.secretKey) throw new Error('Cannot provide both a name and a secret key')
217
224
  if (opts.publicKey && !Buffer.isBuffer(opts.publicKey)) throw new Error('publicKey option must be a Buffer')
218
225
  if (opts.secretKey && !Buffer.isBuffer(opts.secretKey)) throw new Error('secretKey option must be a Buffer')
219
- if (opts.discoveryKey && !Buffer.isBuffer(opts.discoveryKey)) throw new Error('discoveryKey option must be a Buffer')
220
- if (!opts.name && !opts.publicKey) throw new Error('Must provide either a name or a publicKey')
226
+ if (!opts._discoveryKey && (!opts.name && !opts.publicKey)) throw new Error('Must provide either a name or a publicKey')
221
227
  return opts
222
228
  }
223
229
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "corestore",
3
- "version": "6.0.1-alpha.8",
3
+ "version": "6.0.1-alpha.9",
4
4
  "description": "A Hypercore factory that simplifies managing collections of cores.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -31,6 +31,7 @@
31
31
  "derive-key": "^1.0.1",
32
32
  "hypercore": "next",
33
33
  "hypercore-crypto": "^2.3.0",
34
+ "safety-catch": "^1.0.1",
34
35
  "sodium-universal": "^3.0.4"
35
36
  }
36
37
  }
package/test/all.js CHANGED
@@ -77,6 +77,46 @@ test('basic replication', async function (t) {
77
77
  t.alike(await core4.get(0), Buffer.from('world'))
78
78
  })
79
79
 
80
+ test('replicating cores created after replication begins', async function (t) {
81
+ const store1 = new Corestore(ram)
82
+ const store2 = new Corestore(ram)
83
+
84
+ const s = store1.replicate(true, { live: true })
85
+ s.pipe(store2.replicate(false, { live: true })).pipe(s)
86
+
87
+ const core1 = store1.get({ name: 'core-1' })
88
+ const core2 = store1.get({ name: 'core-2' })
89
+ await core1.append('hello')
90
+ await core2.append('world')
91
+
92
+ const core3 = store2.get({ key: core1.key })
93
+ const core4 = store2.get({ key: core2.key })
94
+
95
+ t.alike(await core3.get(0), Buffer.from('hello'))
96
+ t.alike(await core4.get(0), Buffer.from('world'))
97
+ })
98
+
99
+ test('replicating cores using discovery key hook', async function (t) {
100
+ const dir = await tmp.dir({ unsafeCleanup: true })
101
+ let store1 = new Corestore(dir.path)
102
+ const store2 = new Corestore(ram)
103
+
104
+ const core = store1.get({ name: 'main' })
105
+ await core.append('hello')
106
+ const key = core.key
107
+
108
+ await store1.close()
109
+ store1 = new Corestore(dir.path)
110
+
111
+ const s = store1.replicate(true, { live: true })
112
+ s.pipe(store2.replicate(false, { live: true })).pipe(s)
113
+
114
+ const core2 = store2.get(key)
115
+ t.alike(await core2.get(0), Buffer.from('hello'))
116
+
117
+ await dir.cleanup()
118
+ })
119
+
80
120
  test('nested namespaces', async function (t) {
81
121
  const store = new Corestore(ram)
82
122
  const ns1a = store.namespace('ns1').namespace('a')