libp2p 0.35.8 → 0.36.0

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 (107) hide show
  1. package/dist/index.min.js +55 -0
  2. package/dist/src/circuit/auto-relay.d.ts +8 -10
  3. package/dist/src/circuit/auto-relay.d.ts.map +1 -1
  4. package/dist/src/config.d.ts +2 -0
  5. package/dist/src/config.d.ts.map +1 -1
  6. package/dist/src/connection-manager/auto-dialler.d.ts +1 -1
  7. package/dist/src/connection-manager/auto-dialler.d.ts.map +1 -1
  8. package/dist/src/connection-manager/index.d.ts +1 -2
  9. package/dist/src/connection-manager/index.d.ts.map +1 -1
  10. package/dist/src/content-routing/utils.d.ts +3 -3
  11. package/dist/src/content-routing/utils.d.ts.map +1 -1
  12. package/dist/src/dialer/dial-request.d.ts.map +1 -1
  13. package/dist/src/dialer/index.d.ts +12 -7
  14. package/dist/src/dialer/index.d.ts.map +1 -1
  15. package/dist/src/errors.d.ts +2 -0
  16. package/dist/src/fetch/constants.d.ts +2 -0
  17. package/dist/src/fetch/constants.d.ts.map +1 -0
  18. package/dist/src/fetch/index.d.ts +76 -0
  19. package/dist/src/fetch/index.d.ts.map +1 -0
  20. package/dist/src/fetch/proto.d.ts +134 -0
  21. package/dist/src/identify/index.d.ts +4 -4
  22. package/dist/src/identify/index.d.ts.map +1 -1
  23. package/dist/src/index.d.ts +116 -7
  24. package/dist/src/index.d.ts.map +1 -1
  25. package/dist/src/metrics/index.d.ts +9 -4
  26. package/dist/src/metrics/index.d.ts.map +1 -1
  27. package/dist/src/metrics/tracked-map.d.ts +6 -1
  28. package/dist/src/metrics/tracked-map.d.ts.map +1 -1
  29. package/dist/src/peer-routing.d.ts +1 -1
  30. package/dist/src/peer-routing.d.ts.map +1 -1
  31. package/dist/src/peer-store/address-book.d.ts +30 -84
  32. package/dist/src/peer-store/address-book.d.ts.map +1 -1
  33. package/dist/src/peer-store/index.d.ts +28 -94
  34. package/dist/src/peer-store/index.d.ts.map +1 -1
  35. package/dist/src/peer-store/key-book.d.ts +31 -15
  36. package/dist/src/peer-store/key-book.d.ts.map +1 -1
  37. package/dist/src/peer-store/metadata-book.d.ts +33 -29
  38. package/dist/src/peer-store/metadata-book.d.ts.map +1 -1
  39. package/dist/src/peer-store/pb/peer.d.ts +222 -0
  40. package/dist/src/peer-store/proto-book.d.ts +27 -28
  41. package/dist/src/peer-store/proto-book.d.ts.map +1 -1
  42. package/dist/src/peer-store/store.d.ts +73 -0
  43. package/dist/src/peer-store/store.d.ts.map +1 -0
  44. package/dist/src/peer-store/types.d.ts +202 -0
  45. package/dist/src/peer-store/types.d.ts.map +1 -0
  46. package/dist/src/ping/index.d.ts.map +1 -1
  47. package/dist/src/record/peer-record/index.d.ts +2 -2
  48. package/dist/src/record/peer-record/index.d.ts.map +1 -1
  49. package/dist/src/registrar.d.ts +5 -5
  50. package/dist/src/registrar.d.ts.map +1 -1
  51. package/dist/src/types.d.ts +90 -0
  52. package/dist/src/types.d.ts.map +1 -0
  53. package/dist/src/upgrader.d.ts +8 -2
  54. package/dist/src/upgrader.d.ts.map +1 -1
  55. package/package.json +23 -26
  56. package/src/circuit/auto-relay.js +52 -38
  57. package/src/config.js +2 -0
  58. package/src/connection-manager/auto-dialler.js +20 -8
  59. package/src/connection-manager/index.js +42 -22
  60. package/src/content-routing/utils.js +4 -4
  61. package/src/dialer/dial-request.js +4 -1
  62. package/src/dialer/index.js +38 -8
  63. package/src/errors.js +2 -0
  64. package/src/fetch/README.md +36 -0
  65. package/src/fetch/constants.js +6 -0
  66. package/src/fetch/index.js +159 -0
  67. package/src/fetch/proto.d.ts +134 -0
  68. package/src/fetch/proto.js +333 -0
  69. package/src/fetch/proto.proto +15 -0
  70. package/src/identify/index.js +47 -38
  71. package/src/index.js +72 -27
  72. package/src/metrics/index.js +15 -8
  73. package/src/metrics/tracked-map.js +40 -14
  74. package/src/peer-routing.js +4 -1
  75. package/src/peer-store/address-book.js +254 -226
  76. package/src/peer-store/index.js +79 -110
  77. package/src/peer-store/key-book.js +99 -54
  78. package/src/peer-store/metadata-book.js +171 -101
  79. package/src/peer-store/pb/peer.d.ts +222 -0
  80. package/src/peer-store/pb/peer.js +643 -0
  81. package/src/peer-store/pb/peer.proto +31 -0
  82. package/src/peer-store/proto-book.js +171 -105
  83. package/src/peer-store/store.js +263 -0
  84. package/src/peer-store/types.ts +245 -0
  85. package/src/ping/index.js +6 -0
  86. package/src/record/peer-record/index.js +1 -1
  87. package/src/record/utils.js +1 -1
  88. package/src/registrar.js +4 -4
  89. package/src/types.ts +98 -0
  90. package/src/upgrader.js +32 -2
  91. package/dist/src/peer-store/book.d.ts +0 -81
  92. package/dist/src/peer-store/book.d.ts.map +0 -1
  93. package/dist/src/peer-store/persistent/consts.d.ts +0 -6
  94. package/dist/src/peer-store/persistent/consts.d.ts.map +0 -1
  95. package/dist/src/peer-store/persistent/index.d.ts +0 -129
  96. package/dist/src/peer-store/persistent/index.d.ts.map +0 -1
  97. package/dist/src/peer-store/persistent/pb/address-book.d.ts +0 -198
  98. package/dist/src/peer-store/persistent/pb/proto-book.d.ts +0 -59
  99. package/src/peer-store/book.js +0 -124
  100. package/src/peer-store/persistent/consts.js +0 -15
  101. package/src/peer-store/persistent/index.js +0 -408
  102. package/src/peer-store/persistent/pb/address-book.d.ts +0 -198
  103. package/src/peer-store/persistent/pb/address-book.js +0 -522
  104. package/src/peer-store/persistent/pb/address-book.proto +0 -27
  105. package/src/peer-store/persistent/pb/proto-book.d.ts +0 -59
  106. package/src/peer-store/persistent/pb/proto-book.js +0 -157
  107. package/src/peer-store/persistent/pb/proto-book.proto +0 -5
@@ -1,74 +1,43 @@
1
1
  'use strict'
2
2
 
3
3
  const debug = require('debug')
4
- const log = Object.assign(debug('libp2p:peer-store:address-book'), {
5
- error: debug('libp2p:peer-store:address-book:err')
6
- })
7
4
  const errcode = require('err-code')
8
-
9
5
  const { Multiaddr } = require('multiaddr')
10
6
  const PeerId = require('peer-id')
11
-
12
- const Book = require('./book')
7
+ const { codes } = require('../errors')
13
8
  const PeerRecord = require('../record/peer-record')
14
-
15
- const {
16
- codes: { ERR_INVALID_PARAMETERS }
17
- } = require('../errors')
18
9
  const Envelope = require('../record/envelope')
10
+ const { pipe } = require('it-pipe')
11
+ const all = require('it-all')
12
+ const filter = require('it-filter')
13
+ const map = require('it-map')
14
+ const each = require('it-foreach')
19
15
 
20
16
  /**
21
- * @typedef {import('./')} PeerStore
17
+ * @typedef {import('./types').PeerStore} PeerStore
18
+ * @typedef {import('./types').Address} Address
19
+ * @typedef {import('./types').AddressBook} AddressBook
22
20
  */
23
21
 
24
- /**
25
- * @typedef {Object} Address
26
- * @property {Multiaddr} multiaddr peer multiaddr.
27
- * @property {boolean} isCertified obtained from a signed peer record.
28
- *
29
- * @typedef {Object} CertifiedRecord
30
- * @property {Uint8Array} raw raw envelope.
31
- * @property {number} seqNumber seq counter.
32
- *
33
- * @typedef {Object} Entry
34
- * @property {Address[]} addresses peer Addresses.
35
- * @property {CertifiedRecord} record certified peer record.
36
- */
22
+ const log = Object.assign(debug('libp2p:peer-store:address-book'), {
23
+ error: debug('libp2p:peer-store:address-book:err')
24
+ })
25
+
26
+ const EVENT_NAME = 'change:multiaddrs'
37
27
 
38
28
  /**
39
- * @extends {Book}
29
+ * @implements {AddressBook}
40
30
  */
41
- class AddressBook extends Book {
31
+ class PeerStoreAddressBook {
42
32
  /**
43
- * The AddressBook is responsible for keeping the known multiaddrs of a peer.
44
- *
45
- * @class
46
- * @param {PeerStore} peerStore
33
+ * @param {PeerStore["emit"]} emit
34
+ * @param {import('./types').Store} store
35
+ * @param {(peerId: PeerId, multiaddr: Multiaddr) => Promise<boolean>} addressFilter
47
36
  */
48
- constructor (peerStore) {
49
- /**
50
- * PeerStore Event emitter, used by the AddressBook to emit:
51
- * "peer" - emitted when a peer is discovered by the node.
52
- * "change:multiaddrs" - emitted when the known multiaddrs of a peer change.
53
- */
54
- super({
55
- peerStore,
56
- eventName: 'change:multiaddrs',
57
- eventProperty: 'multiaddrs',
58
- eventTransformer: (data) => {
59
- if (!data.addresses) {
60
- return []
61
- }
62
- return data.addresses.map((/** @type {Address} */ address) => address.multiaddr)
63
- }
64
- })
65
-
66
- /**
67
- * Map known peers to their known Address Entries.
68
- *
69
- * @type {Map<string, Entry>}
70
- */
71
- this.data = new Map()
37
+ constructor (emit, store, addressFilter) {
38
+ this._emit = emit
39
+ this._store = store
40
+ this._addressFilter = addressFilter
72
41
  }
73
42
 
74
43
  /**
@@ -77,69 +46,90 @@ class AddressBook extends Book {
77
46
  * into the AddressBook.
78
47
  *
79
48
  * @param {Envelope} envelope
80
- * @returns {boolean}
81
49
  */
82
- consumePeerRecord (envelope) {
83
- let peerRecord
50
+ async consumePeerRecord (envelope) {
51
+ log('consumePeerRecord await write lock')
52
+ const release = await this._store.lock.writeLock()
53
+ log('consumePeerRecord got write lock')
54
+
55
+ let peerId
56
+ let updatedPeer
57
+
84
58
  try {
85
- peerRecord = PeerRecord.createFromProtobuf(envelope.payload)
86
- } catch (/** @type {any} */ err) {
87
- log.error('invalid peer record received')
88
- return false
89
- }
59
+ let peerRecord
60
+ try {
61
+ peerRecord = PeerRecord.createFromProtobuf(envelope.payload)
62
+ } catch (/** @type {any} */ err) {
63
+ log.error('invalid peer record received')
64
+ return false
65
+ }
90
66
 
91
- // Verify peerId
92
- if (!peerRecord.peerId.equals(envelope.peerId)) {
93
- log('signing key does not match PeerId in the PeerRecord')
94
- return false
95
- }
67
+ peerId = peerRecord.peerId
68
+ const multiaddrs = peerRecord.multiaddrs
96
69
 
97
- // ensure the record has multiaddrs
98
- if (!peerRecord.multiaddrs || !peerRecord.multiaddrs.length) {
99
- return false
100
- }
70
+ // Verify peerId
71
+ if (!peerId.equals(envelope.peerId)) {
72
+ log('signing key does not match PeerId in the PeerRecord')
73
+ return false
74
+ }
101
75
 
102
- const peerId = peerRecord.peerId
103
- const id = peerId.toB58String()
104
- const entry = this.data.get(id) || { record: undefined }
105
- const storedRecord = entry.record
76
+ // ensure the record has multiaddrs
77
+ if (!multiaddrs || !multiaddrs.length) {
78
+ return false
79
+ }
106
80
 
107
- // ensure seq is greater than, or equal to, the last received
108
- if (storedRecord && storedRecord.seqNumber >= peerRecord.seqNumber) {
109
- return false
110
- }
81
+ if (await this._store.has(peerId)) {
82
+ const peer = await this._store.load(peerId)
111
83
 
112
- const addresses = this._toAddresses(peerRecord.multiaddrs, true)
84
+ if (peer.peerRecordEnvelope) {
85
+ const storedEnvelope = await Envelope.createFromProtobuf(peer.peerRecordEnvelope)
86
+ const storedRecord = PeerRecord.createFromProtobuf(storedEnvelope.payload)
113
87
 
114
- // Replace unsigned addresses by the new ones from the record
115
- // TODO: Once we have ttls for the addresses, we should merge these in.
116
- this._setData(peerId, {
117
- addresses,
118
- record: {
119
- raw: envelope.marshal(),
120
- seqNumber: peerRecord.seqNumber
88
+ // ensure seq is greater than, or equal to, the last received
89
+ if (storedRecord.seqNumber >= peerRecord.seqNumber) {
90
+ return false
91
+ }
92
+ }
121
93
  }
122
- })
123
- log(`stored provided peer record for ${id}`)
94
+
95
+ // Replace unsigned addresses by the new ones from the record
96
+ // TODO: Once we have ttls for the addresses, we should merge these in
97
+ updatedPeer = await this._store.patchOrCreate(peerId, {
98
+ addresses: await filterMultiaddrs(peerId, multiaddrs, this._addressFilter, true),
99
+ peerRecordEnvelope: envelope.marshal()
100
+ })
101
+
102
+ log(`stored provided peer record for ${peerRecord.peerId.toB58String()}`)
103
+ } finally {
104
+ log('consumePeerRecord release write lock')
105
+ release()
106
+ }
107
+
108
+ this._emit(EVENT_NAME, { peerId, multiaddrs: updatedPeer.addresses.map(({ multiaddr }) => multiaddr) })
124
109
 
125
110
  return true
126
111
  }
127
112
 
128
113
  /**
129
- * Get the raw Envelope for a peer. Returns
130
- * undefined if no Envelope is found.
131
- *
132
114
  * @param {PeerId} peerId
133
- * @returns {Uint8Array|undefined}
134
115
  */
135
- getRawEnvelope (peerId) {
136
- const entry = this.data.get(peerId.toB58String())
116
+ async getRawEnvelope (peerId) {
117
+ log('getRawEnvelope await read lock')
118
+ const release = await this._store.lock.readLock()
119
+ log('getRawEnvelope got read lock')
137
120
 
138
- if (!entry || !entry.record || !entry.record.raw) {
139
- return undefined
140
- }
121
+ try {
122
+ const peer = await this._store.load(peerId)
141
123
 
142
- return entry.record.raw
124
+ return peer.peerRecordEnvelope
125
+ } catch (/** @type {any} */ err) {
126
+ if (err.code !== codes.ERR_NOT_FOUND) {
127
+ throw err
128
+ }
129
+ } finally {
130
+ log('getRawEnvelope release read lock')
131
+ release()
132
+ }
143
133
  }
144
134
 
145
135
  /**
@@ -147,10 +137,9 @@ class AddressBook extends Book {
147
137
  * Returns undefined if no record exists.
148
138
  *
149
139
  * @param {PeerId} peerId
150
- * @returns {Promise<Envelope|void>|undefined}
151
140
  */
152
- getPeerRecord (peerId) {
153
- const raw = this.getRawEnvelope(peerId)
141
+ async getPeerRecord (peerId) {
142
+ const raw = await this.getRawEnvelope(peerId)
154
143
 
155
144
  if (!raw) {
156
145
  return undefined
@@ -160,186 +149,199 @@ class AddressBook extends Book {
160
149
  }
161
150
 
162
151
  /**
163
- * Set known multiaddrs of a provided peer.
164
- * This will replace previously stored multiaddrs, if available.
165
- * Replacing stored multiaddrs might result in losing obtained certified addresses.
166
- * If you are not sure, it's recommended to use `add` instead.
167
- *
168
- * @override
169
152
  * @param {PeerId} peerId
170
- * @param {Multiaddr[]} multiaddrs
171
- * @returns {AddressBook}
172
153
  */
173
- set (peerId, multiaddrs) {
154
+ async get (peerId) {
174
155
  if (!PeerId.isPeerId(peerId)) {
175
156
  log.error('peerId must be an instance of peer-id to store data')
176
- throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
177
- }
178
-
179
- const addresses = this._toAddresses(multiaddrs)
180
-
181
- // Not replace multiaddrs
182
- if (!addresses.length) {
183
- return this
157
+ throw errcode(new Error('peerId must be an instance of peer-id'), codes.ERR_INVALID_PARAMETERS)
184
158
  }
185
159
 
186
- const id = peerId.toB58String()
187
- const entry = this.data.get(id)
160
+ log('get wait for read lock')
161
+ const release = await this._store.lock.readLock()
162
+ log('get got read lock')
188
163
 
189
- // Already knows the peer
190
- if (entry && entry.addresses && entry.addresses.length === addresses.length) {
191
- const intersection = entry.addresses.filter((addr) => addresses.some((newAddr) => addr.multiaddr.equals(newAddr.multiaddr)))
164
+ try {
165
+ const peer = await this._store.load(peerId)
192
166
 
193
- // Are new addresses equal to the old ones?
194
- // If yes, no changes needed!
195
- if (intersection.length === entry.addresses.length) {
196
- log(`the addresses provided to store are equal to the already stored for ${id}`)
197
- return this
167
+ return peer.addresses
168
+ } catch (/** @type {any} */ err) {
169
+ if (err.code !== codes.ERR_NOT_FOUND) {
170
+ throw err
198
171
  }
172
+ } finally {
173
+ log('get release read lock')
174
+ release()
199
175
  }
200
176
 
201
- this._setData(peerId, {
202
- addresses,
203
- record: entry && entry.record
204
- })
205
- log(`stored provided multiaddrs for ${id}`)
206
-
207
- // Notify the existance of a new peer
208
- if (!entry) {
209
- this._ps.emit('peer', peerId)
210
- }
211
-
212
- return this
177
+ return []
213
178
  }
214
179
 
215
180
  /**
216
- * Add known addresses of a provided peer.
217
- * If the peer is not known, it is set with the given addresses.
218
- *
219
181
  * @param {PeerId} peerId
220
182
  * @param {Multiaddr[]} multiaddrs
221
- * @returns {AddressBook}
222
183
  */
223
- add (peerId, multiaddrs) {
184
+ async set (peerId, multiaddrs) {
224
185
  if (!PeerId.isPeerId(peerId)) {
225
186
  log.error('peerId must be an instance of peer-id to store data')
226
- throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
187
+ throw errcode(new Error('peerId must be an instance of peer-id'), codes.ERR_INVALID_PARAMETERS)
227
188
  }
228
189
 
229
- const addresses = this._toAddresses(multiaddrs)
230
- const id = peerId.toB58String()
231
-
232
- // No addresses to be added
233
- if (!addresses.length) {
234
- return this
190
+ if (!Array.isArray(multiaddrs)) {
191
+ log.error('multiaddrs must be an array of Multiaddrs')
192
+ throw errcode(new Error('multiaddrs must be an array of Multiaddrs'), codes.ERR_INVALID_PARAMETERS)
235
193
  }
236
194
 
237
- const entry = this.data.get(id)
195
+ log('set await write lock')
196
+ const release = await this._store.lock.writeLock()
197
+ log('set got write lock')
238
198
 
239
- if (entry && entry.addresses) {
240
- // Add recorded uniquely to the new array (Union)
241
- entry.addresses.forEach((addr) => {
242
- if (!addresses.find(r => r.multiaddr.equals(addr.multiaddr))) {
243
- addresses.push(addr)
244
- }
245
- })
199
+ let hasPeer = false
200
+ let updatedPeer
201
+
202
+ try {
203
+ const addresses = await filterMultiaddrs(peerId, multiaddrs, this._addressFilter)
246
204
 
247
- // If the recorded length is equal to the new after the unique union
248
- // The content is the same, no need to update.
249
- if (entry.addresses.length === addresses.length) {
250
- log(`the addresses provided to store are already stored for ${id}`)
251
- return this
205
+ // No valid addresses found
206
+ if (!addresses.length) {
207
+ return
252
208
  }
253
- }
254
209
 
255
- this._setData(peerId, {
256
- addresses,
257
- record: entry && entry.record
258
- })
210
+ try {
211
+ const peer = await this._store.load(peerId)
212
+ hasPeer = true
213
+
214
+ if (new Set([
215
+ ...addresses.map(({ multiaddr }) => multiaddr.toString()),
216
+ ...peer.addresses.map(({ multiaddr }) => multiaddr.toString())
217
+ ]).size === peer.addresses.length && addresses.length === peer.addresses.length) {
218
+ // not changing anything, no need to update
219
+ return
220
+ }
221
+ } catch (/** @type {any} */ err) {
222
+ if (err.code !== codes.ERR_NOT_FOUND) {
223
+ throw err
224
+ }
225
+ }
259
226
 
260
- log(`added provided multiaddrs for ${id}`)
227
+ updatedPeer = await this._store.patchOrCreate(peerId, { addresses })
261
228
 
262
- // Notify the existance of a new peer
263
- if (!(entry && entry.addresses)) {
264
- this._ps.emit('peer', peerId)
229
+ log(`set multiaddrs for ${peerId.toB58String()}`)
230
+ } finally {
231
+ log('set release write lock')
232
+ release()
265
233
  }
266
234
 
267
- return this
235
+ this._emit(EVENT_NAME, { peerId, multiaddrs: updatedPeer.addresses.map(addr => addr.multiaddr) })
236
+
237
+ // Notify the existence of a new peer
238
+ if (!hasPeer) {
239
+ this._emit('peer', peerId)
240
+ }
268
241
  }
269
242
 
270
243
  /**
271
- * Get the known data of a provided peer.
272
- *
273
- * @override
274
244
  * @param {PeerId} peerId
275
- * @returns {Address[]|undefined}
245
+ * @param {Multiaddr[]} multiaddrs
276
246
  */
277
- get (peerId) {
247
+ async add (peerId, multiaddrs) {
278
248
  if (!PeerId.isPeerId(peerId)) {
279
- throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
249
+ log.error('peerId must be an instance of peer-id to store data')
250
+ throw errcode(new Error('peerId must be an instance of peer-id'), codes.ERR_INVALID_PARAMETERS)
280
251
  }
281
252
 
282
- const entry = this.data.get(peerId.toB58String())
253
+ if (!Array.isArray(multiaddrs)) {
254
+ log.error('multiaddrs must be an array of Multiaddrs')
255
+ throw errcode(new Error('multiaddrs must be an array of Multiaddrs'), codes.ERR_INVALID_PARAMETERS)
256
+ }
283
257
 
284
- return entry && entry.addresses ? [...entry.addresses] : undefined
285
- }
258
+ log('add await write lock')
259
+ const release = await this._store.lock.writeLock()
260
+ log('add got write lock')
286
261
 
287
- /**
288
- * Transforms received multiaddrs into Address.
289
- *
290
- * @private
291
- * @param {Multiaddr[]} multiaddrs
292
- * @param {boolean} [isCertified]
293
- * @returns {Address[]}
294
- */
295
- _toAddresses (multiaddrs, isCertified = false) {
296
- if (!multiaddrs) {
297
- log.error('multiaddrs must be provided to store data')
298
- throw errcode(new Error('multiaddrs must be provided'), ERR_INVALID_PARAMETERS)
299
- }
262
+ let hasPeer
263
+ let updatedPeer
300
264
 
301
- // create Address for each address
302
- /** @type {Address[]} */
303
- const addresses = []
304
- multiaddrs.forEach((addr) => {
305
- if (!Multiaddr.isMultiaddr(addr)) {
306
- log.error(`multiaddr ${addr} must be an instance of multiaddr`)
307
- throw errcode(new Error(`multiaddr ${addr} must be an instance of multiaddr`), ERR_INVALID_PARAMETERS)
265
+ try {
266
+ const addresses = await filterMultiaddrs(peerId, multiaddrs, this._addressFilter)
267
+
268
+ // No valid addresses found
269
+ if (!addresses.length) {
270
+ return
308
271
  }
309
272
 
310
- // Guarantee no replicates
311
- if (!addresses.find((a) => a.multiaddr.equals(addr))) {
312
- addresses.push({
313
- multiaddr: addr,
314
- isCertified
315
- })
273
+ try {
274
+ const peer = await this._store.load(peerId)
275
+ hasPeer = true
276
+
277
+ if (new Set([
278
+ ...addresses.map(({ multiaddr }) => multiaddr.toString()),
279
+ ...peer.addresses.map(({ multiaddr }) => multiaddr.toString())
280
+ ]).size === peer.addresses.length) {
281
+ return
282
+ }
283
+ } catch (/** @type {any} */ err) {
284
+ if (err.code !== codes.ERR_NOT_FOUND) {
285
+ throw err
286
+ }
316
287
  }
317
- })
318
288
 
319
- return addresses
289
+ updatedPeer = await this._store.mergeOrCreate(peerId, { addresses })
290
+
291
+ log(`added multiaddrs for ${peerId}`)
292
+ } finally {
293
+ log('set release write lock')
294
+ release()
295
+ }
296
+
297
+ this._emit(EVENT_NAME, { peerId, multiaddrs: updatedPeer.addresses.map(addr => addr.multiaddr) })
298
+
299
+ // Notify the existence of a new peer
300
+ if (!hasPeer) {
301
+ this._emit('peer', peerId)
302
+ }
320
303
  }
321
304
 
322
305
  /**
323
- * Get the known multiaddrs for a given peer. All returned multiaddrs
324
- * will include the encapsulated `PeerId` of the peer.
325
- * Returns `undefined` if there are no known multiaddrs for the given peer.
326
- *
327
306
  * @param {PeerId} peerId
328
- * @param {(addresses: Address[]) => Address[]} [addressSorter]
329
- * @returns {Multiaddr[]|undefined}
330
307
  */
331
- getMultiaddrsForPeer (peerId, addressSorter = (ms) => ms) {
308
+ async delete (peerId) {
332
309
  if (!PeerId.isPeerId(peerId)) {
333
- throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
310
+ log.error('peerId must be an instance of peer-id to store data')
311
+ throw errcode(new Error('peerId must be an instance of peer-id'), codes.ERR_INVALID_PARAMETERS)
334
312
  }
335
313
 
336
- const entry = this.data.get(peerId.toB58String())
337
- if (!entry || !entry.addresses) {
338
- return undefined
314
+ log('delete await write lock')
315
+ const release = await this._store.lock.writeLock()
316
+ log('delete got write lock')
317
+
318
+ let has
319
+
320
+ try {
321
+ has = await this._store.has(peerId)
322
+
323
+ await this._store.patchOrCreate(peerId, {
324
+ addresses: []
325
+ })
326
+ } finally {
327
+ log('delete release write lock')
328
+ release()
339
329
  }
340
330
 
331
+ if (has) {
332
+ this._emit(EVENT_NAME, { peerId, multiaddrs: [] })
333
+ }
334
+ }
335
+
336
+ /**
337
+ * @param {PeerId} peerId
338
+ * @param {(addresses: Address[]) => Address[]} [addressSorter]
339
+ */
340
+ async getMultiaddrsForPeer (peerId, addressSorter = (ms) => ms) {
341
+ const addresses = await this.get(peerId)
342
+
341
343
  return addressSorter(
342
- entry.addresses || []
344
+ addresses
343
345
  ).map((address) => {
344
346
  const multiaddr = address.multiaddr
345
347
 
@@ -351,4 +353,30 @@ class AddressBook extends Book {
351
353
  }
352
354
  }
353
355
 
354
- module.exports = AddressBook
356
+ /**
357
+ * @param {PeerId} peerId
358
+ * @param {Multiaddr[]} multiaddrs
359
+ * @param {(peerId: PeerId, multiaddr: Multiaddr) => Promise<boolean>} addressFilter
360
+ * @param {boolean} isCertified
361
+ */
362
+ function filterMultiaddrs (peerId, multiaddrs, addressFilter, isCertified = false) {
363
+ return pipe(
364
+ multiaddrs,
365
+ (source) => each(source, (multiaddr) => {
366
+ if (!Multiaddr.isMultiaddr(multiaddr)) {
367
+ log.error('multiaddr must be an instance of Multiaddr')
368
+ throw errcode(new Error('multiaddr must be an instance of Multiaddr'), codes.ERR_INVALID_PARAMETERS)
369
+ }
370
+ }),
371
+ (source) => filter(source, (multiaddr) => addressFilter(peerId, multiaddr)),
372
+ (source) => map(source, (multiaddr) => {
373
+ return {
374
+ multiaddr: new Multiaddr(multiaddr.toString()),
375
+ isCertified
376
+ }
377
+ }),
378
+ (source) => all(source)
379
+ )
380
+ }
381
+
382
+ module.exports = PeerStoreAddressBook