@libp2p/kad-dht 0.28.6

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 (166) hide show
  1. package/LICENSE +4 -0
  2. package/README.md +105 -0
  3. package/dist/src/constants.d.ts +20 -0
  4. package/dist/src/constants.d.ts.map +1 -0
  5. package/dist/src/constants.js +34 -0
  6. package/dist/src/constants.js.map +1 -0
  7. package/dist/src/content-fetching/index.d.ts +55 -0
  8. package/dist/src/content-fetching/index.d.ts.map +1 -0
  9. package/dist/src/content-fetching/index.js +190 -0
  10. package/dist/src/content-fetching/index.js.map +1 -0
  11. package/dist/src/content-routing/index.d.ts +42 -0
  12. package/dist/src/content-routing/index.d.ts.map +1 -0
  13. package/dist/src/content-routing/index.js +129 -0
  14. package/dist/src/content-routing/index.js.map +1 -0
  15. package/dist/src/dual-kad-dht.d.ts +65 -0
  16. package/dist/src/dual-kad-dht.d.ts.map +1 -0
  17. package/dist/src/dual-kad-dht.js +191 -0
  18. package/dist/src/dual-kad-dht.js.map +1 -0
  19. package/dist/src/index.d.ts +4 -0
  20. package/dist/src/index.d.ts.map +1 -0
  21. package/dist/src/index.js +15 -0
  22. package/dist/src/index.js.map +1 -0
  23. package/dist/src/kad-dht.d.ts +131 -0
  24. package/dist/src/kad-dht.d.ts.map +1 -0
  25. package/dist/src/kad-dht.js +268 -0
  26. package/dist/src/kad-dht.js.map +1 -0
  27. package/dist/src/message/dht.d.ts +297 -0
  28. package/dist/src/message/dht.js +921 -0
  29. package/dist/src/message/index.d.ts +32 -0
  30. package/dist/src/message/index.d.ts.map +1 -0
  31. package/dist/src/message/index.js +81 -0
  32. package/dist/src/message/index.js.map +1 -0
  33. package/dist/src/network.d.ts +60 -0
  34. package/dist/src/network.d.ts.map +1 -0
  35. package/dist/src/network.js +124 -0
  36. package/dist/src/network.js.map +1 -0
  37. package/dist/src/peer-list/index.d.ts +29 -0
  38. package/dist/src/peer-list/index.d.ts.map +1 -0
  39. package/dist/src/peer-list/index.js +44 -0
  40. package/dist/src/peer-list/index.js.map +1 -0
  41. package/dist/src/peer-list/peer-distance-list.d.ts +34 -0
  42. package/dist/src/peer-list/peer-distance-list.d.ts.map +1 -0
  43. package/dist/src/peer-list/peer-distance-list.js +64 -0
  44. package/dist/src/peer-list/peer-distance-list.js.map +1 -0
  45. package/dist/src/peer-routing/index.d.ts +71 -0
  46. package/dist/src/peer-routing/index.d.ts.map +1 -0
  47. package/dist/src/peer-routing/index.js +256 -0
  48. package/dist/src/peer-routing/index.js.map +1 -0
  49. package/dist/src/providers.d.ts +64 -0
  50. package/dist/src/providers.d.ts.map +1 -0
  51. package/dist/src/providers.js +208 -0
  52. package/dist/src/providers.js.map +1 -0
  53. package/dist/src/query/events.d.ts +46 -0
  54. package/dist/src/query/events.d.ts.map +1 -0
  55. package/dist/src/query/events.js +73 -0
  56. package/dist/src/query/events.js.map +1 -0
  57. package/dist/src/query/manager.d.ts +40 -0
  58. package/dist/src/query/manager.d.ts.map +1 -0
  59. package/dist/src/query/manager.js +140 -0
  60. package/dist/src/query/manager.js.map +1 -0
  61. package/dist/src/query/query-path.d.ts +58 -0
  62. package/dist/src/query/query-path.d.ts.map +1 -0
  63. package/dist/src/query/query-path.js +171 -0
  64. package/dist/src/query/query-path.js.map +1 -0
  65. package/dist/src/query/types.d.ts +16 -0
  66. package/dist/src/query/types.d.ts.map +1 -0
  67. package/dist/src/query/types.js +2 -0
  68. package/dist/src/query/types.js.map +1 -0
  69. package/dist/src/query-self.d.ts +31 -0
  70. package/dist/src/query-self.d.ts.map +1 -0
  71. package/dist/src/query-self.js +73 -0
  72. package/dist/src/query-self.js.map +1 -0
  73. package/dist/src/routing-table/generated-prefix-list-browser.d.ts +3 -0
  74. package/dist/src/routing-table/generated-prefix-list-browser.d.ts.map +1 -0
  75. package/dist/src/routing-table/generated-prefix-list-browser.js +1027 -0
  76. package/dist/src/routing-table/generated-prefix-list-browser.js.map +1 -0
  77. package/dist/src/routing-table/generated-prefix-list.d.ts +3 -0
  78. package/dist/src/routing-table/generated-prefix-list.d.ts.map +1 -0
  79. package/dist/src/routing-table/generated-prefix-list.js +4099 -0
  80. package/dist/src/routing-table/generated-prefix-list.js.map +1 -0
  81. package/dist/src/routing-table/index.d.ts +91 -0
  82. package/dist/src/routing-table/index.d.ts.map +1 -0
  83. package/dist/src/routing-table/index.js +183 -0
  84. package/dist/src/routing-table/index.js.map +1 -0
  85. package/dist/src/routing-table/refresh.d.ts +50 -0
  86. package/dist/src/routing-table/refresh.d.ts.map +1 -0
  87. package/dist/src/routing-table/refresh.js +204 -0
  88. package/dist/src/routing-table/refresh.js.map +1 -0
  89. package/dist/src/routing-table/types.d.ts +24 -0
  90. package/dist/src/routing-table/types.d.ts.map +1 -0
  91. package/dist/src/rpc/handlers/add-provider.d.ts +13 -0
  92. package/dist/src/rpc/handlers/add-provider.d.ts.map +1 -0
  93. package/dist/src/rpc/handlers/add-provider.js +42 -0
  94. package/dist/src/rpc/handlers/add-provider.js.map +1 -0
  95. package/dist/src/rpc/handlers/find-node.d.ts +18 -0
  96. package/dist/src/rpc/handlers/find-node.d.ts.map +1 -0
  97. package/dist/src/rpc/handlers/find-node.js +32 -0
  98. package/dist/src/rpc/handlers/find-node.js.map +1 -0
  99. package/dist/src/rpc/handlers/get-providers.d.ts +24 -0
  100. package/dist/src/rpc/handlers/get-providers.d.ts.map +1 -0
  101. package/dist/src/rpc/handlers/get-providers.js +60 -0
  102. package/dist/src/rpc/handlers/get-providers.js.map +1 -0
  103. package/dist/src/rpc/handlers/get-value.d.ts +27 -0
  104. package/dist/src/rpc/handlers/get-value.d.ts.map +1 -0
  105. package/dist/src/rpc/handlers/get-value.js +94 -0
  106. package/dist/src/rpc/handlers/get-value.js.map +1 -0
  107. package/dist/src/rpc/handlers/index.d.ts +13 -0
  108. package/dist/src/rpc/handlers/index.d.ts.map +1 -0
  109. package/dist/src/rpc/handlers/ping.d.ts +7 -0
  110. package/dist/src/rpc/handlers/ping.d.ts.map +1 -0
  111. package/dist/src/rpc/handlers/ping.js +9 -0
  112. package/dist/src/rpc/handlers/ping.js.map +1 -0
  113. package/dist/src/rpc/handlers/put-value.d.ts +18 -0
  114. package/dist/src/rpc/handlers/put-value.d.ts.map +1 -0
  115. package/dist/src/rpc/handlers/put-value.js +35 -0
  116. package/dist/src/rpc/handlers/put-value.js.map +1 -0
  117. package/dist/src/rpc/index.d.ts +38 -0
  118. package/dist/src/rpc/index.d.ts.map +1 -0
  119. package/dist/src/rpc/index.js +75 -0
  120. package/dist/src/rpc/index.js.map +1 -0
  121. package/dist/src/rpc/types.d.ts +6 -0
  122. package/dist/src/rpc/types.d.ts.map +1 -0
  123. package/dist/src/topology-listener.d.ts +33 -0
  124. package/dist/src/topology-listener.d.ts.map +1 -0
  125. package/dist/src/topology-listener.js +50 -0
  126. package/dist/src/topology-listener.js.map +1 -0
  127. package/dist/src/types.d.ts +143 -0
  128. package/dist/src/types.d.ts.map +1 -0
  129. package/dist/src/utils.d.ts +33 -0
  130. package/dist/src/utils.d.ts.map +1 -0
  131. package/dist/src/utils.js +89 -0
  132. package/dist/src/utils.js.map +1 -0
  133. package/package.json +200 -0
  134. package/src/constants.ts +50 -0
  135. package/src/content-fetching/index.ts +276 -0
  136. package/src/content-routing/index.ts +202 -0
  137. package/src/dual-kad-dht.ts +257 -0
  138. package/src/index.ts +21 -0
  139. package/src/kad-dht.ts +396 -0
  140. package/src/message/dht.d.ts +297 -0
  141. package/src/message/dht.js +921 -0
  142. package/src/message/dht.proto +75 -0
  143. package/src/message/index.ts +111 -0
  144. package/src/network.ts +185 -0
  145. package/src/peer-list/index.ts +54 -0
  146. package/src/peer-list/peer-distance-list.ts +93 -0
  147. package/src/peer-routing/index.ts +332 -0
  148. package/src/providers.ts +278 -0
  149. package/src/query/events.ts +126 -0
  150. package/src/query/manager.ts +188 -0
  151. package/src/query/query-path.ts +263 -0
  152. package/src/query/types.ts +22 -0
  153. package/src/query-self.ts +106 -0
  154. package/src/routing-table/generated-prefix-list-browser.ts +1026 -0
  155. package/src/routing-table/generated-prefix-list.ts +4098 -0
  156. package/src/routing-table/index.ts +265 -0
  157. package/src/routing-table/refresh.ts +263 -0
  158. package/src/rpc/handlers/add-provider.ts +63 -0
  159. package/src/rpc/handlers/find-node.ts +57 -0
  160. package/src/rpc/handlers/get-providers.ts +95 -0
  161. package/src/rpc/handlers/get-value.ts +130 -0
  162. package/src/rpc/handlers/ping.ts +13 -0
  163. package/src/rpc/handlers/put-value.ts +58 -0
  164. package/src/rpc/index.ts +118 -0
  165. package/src/topology-listener.ts +78 -0
  166. package/src/utils.ts +108 -0
@@ -0,0 +1,276 @@
1
+ import errcode from 'err-code'
2
+ import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
3
+ import { Libp2pRecord } from '@libp2p/record'
4
+ import { verifyRecord } from '@libp2p/record/validators'
5
+ import { bestRecord } from '@libp2p/record/selectors'
6
+ import parallel from 'it-parallel'
7
+ import map from 'it-map'
8
+ import {
9
+ valueEvent,
10
+ queryErrorEvent
11
+ } from '../query/events.js'
12
+ import { Message, MESSAGE_TYPE } from '../message/index.js'
13
+ import { pipe } from 'it-pipe'
14
+ import {
15
+ ALPHA
16
+ } from '../constants.js'
17
+ import { createPutRecord, convertBuffer, bufferToRecordKey } from '../utils.js'
18
+ import { logger } from '@libp2p/logger'
19
+ import type { PeerId } from '@libp2p/interfaces/peer-id'
20
+ import type { Validators, Selectors, ValueEvent, QueryOptions } from '@libp2p/interfaces/dht'
21
+ import type { Datastore } from 'interface-datastore'
22
+ import type { PeerRouting } from '../peer-routing/index.js'
23
+ import type { QueryManager } from '../query/manager.js'
24
+ import type { RoutingTable } from '../routing-table/index.js'
25
+ import type { Network } from '../network.js'
26
+ import type { Logger } from '@libp2p/logger'
27
+ import type { AbortOptions } from '@libp2p/interfaces'
28
+ import type { QueryFunc } from '../query/types.js'
29
+
30
+ export interface ContentFetchingOptions {
31
+ peerId: PeerId
32
+ datastore: Datastore
33
+ validators: Validators
34
+ selectors: Selectors
35
+ peerRouting: PeerRouting
36
+ queryManager: QueryManager
37
+ routingTable: RoutingTable
38
+ network: Network
39
+ lan: boolean
40
+ }
41
+
42
+ export class ContentFetching {
43
+ private readonly log: Logger
44
+ private readonly peerId: PeerId
45
+ private readonly datastore: Datastore
46
+ private readonly validators: Validators
47
+ private readonly selectors: Selectors
48
+ private readonly peerRouting: PeerRouting
49
+ private readonly queryManager: QueryManager
50
+ private readonly routingTable: RoutingTable
51
+ private readonly network: Network
52
+
53
+ constructor (options: ContentFetchingOptions) {
54
+ const { peerId, datastore, validators, selectors, peerRouting, queryManager, routingTable, network, lan } = options
55
+ this.log = logger(`libp2p:kad-dht:${lan ? 'lan' : 'wan'}:content-fetching:${peerId.toString()}`)
56
+ this.peerId = peerId
57
+ this.datastore = datastore
58
+ this.validators = validators
59
+ this.selectors = selectors
60
+ this.peerRouting = peerRouting
61
+ this.queryManager = queryManager
62
+ this.routingTable = routingTable
63
+ this.network = network
64
+ }
65
+
66
+ async putLocal (key: Uint8Array, rec: Uint8Array) { // eslint-disable-line require-await
67
+ const dsKey = bufferToRecordKey(key)
68
+ await this.datastore.put(dsKey, rec)
69
+ }
70
+
71
+ /**
72
+ * Attempt to retrieve the value for the given key from
73
+ * the local datastore
74
+ */
75
+ async getLocal (key: Uint8Array) {
76
+ this.log('getLocal %b', key)
77
+
78
+ const dsKey = bufferToRecordKey(key)
79
+
80
+ this.log('fetching record for key %k', dsKey)
81
+
82
+ const raw = await this.datastore.get(dsKey)
83
+ this.log('found %k in local datastore', dsKey)
84
+
85
+ const rec = Libp2pRecord.deserialize(raw)
86
+
87
+ await verifyRecord(this.validators, rec)
88
+
89
+ return rec
90
+ }
91
+
92
+ /**
93
+ * Send the best record found to any peers that have an out of date record
94
+ */
95
+ async * sendCorrectionRecord (key: Uint8Array, vals: ValueEvent[], best: Uint8Array, options: AbortOptions = {}) {
96
+ this.log('sendCorrection for %b', key)
97
+ const fixupRec = await createPutRecord(key, best)
98
+
99
+ for (const { value, from } of vals) {
100
+ // no need to do anything
101
+ if (uint8ArrayEquals(value, best)) {
102
+ this.log('record was ok')
103
+ continue
104
+ }
105
+
106
+ // correct ourself
107
+ if (this.peerId.equals(from)) {
108
+ try {
109
+ const dsKey = bufferToRecordKey(key)
110
+ this.log(`Storing corrected record for key ${dsKey.toString()}`)
111
+ await this.datastore.put(dsKey, fixupRec)
112
+ } catch (err: any) {
113
+ this.log.error('Failed error correcting self', err)
114
+ }
115
+
116
+ continue
117
+ }
118
+
119
+ // send correction
120
+ let sentCorrection = false
121
+ const request = new Message(MESSAGE_TYPE.PUT_VALUE, key, 0)
122
+ request.record = Libp2pRecord.deserialize(fixupRec)
123
+
124
+ for await (const event of this.network.sendRequest(from, request, options)) {
125
+ if (event.name === 'PEER_RESPONSE' && (event.record != null) && uint8ArrayEquals(event.record.value, Libp2pRecord.deserialize(fixupRec).value)) {
126
+ sentCorrection = true
127
+ }
128
+
129
+ yield event
130
+ }
131
+
132
+ if (!sentCorrection) {
133
+ yield queryErrorEvent({ from, error: errcode(new Error('value not put correctly'), 'ERR_PUT_VALUE_INVALID') })
134
+ }
135
+
136
+ this.log.error('Failed error correcting entry')
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Store the given key/value pair in the DHT
142
+ */
143
+ async * put (key: Uint8Array, value: Uint8Array, options: AbortOptions = {}) {
144
+ this.log('put key %b value %b', key, value)
145
+
146
+ // create record in the dht format
147
+ const record = await createPutRecord(key, value)
148
+
149
+ // store the record locally
150
+ const dsKey = bufferToRecordKey(key)
151
+ this.log(`storing record for key ${dsKey.toString()}`)
152
+ await this.datastore.put(dsKey, record)
153
+
154
+ // put record to the closest peers
155
+ yield * pipe(
156
+ this.peerRouting.getClosestPeers(key, { signal: options.signal }),
157
+ (source) => map(source, (event) => {
158
+ return async () => {
159
+ if (event.name !== 'FINAL_PEER') {
160
+ return [event]
161
+ }
162
+
163
+ const events = []
164
+
165
+ const msg = new Message(MESSAGE_TYPE.PUT_VALUE, key, 0)
166
+ msg.record = Libp2pRecord.deserialize(record)
167
+
168
+ for await (const putEvent of this.network.sendRequest(event.peer.id, msg, options)) {
169
+ events.push(putEvent)
170
+
171
+ if (putEvent.name !== 'PEER_RESPONSE') {
172
+ continue
173
+ }
174
+
175
+ if (!(putEvent.record != null && uint8ArrayEquals(putEvent.record.value, Libp2pRecord.deserialize(record).value))) {
176
+ events.push(queryErrorEvent({ from: event.peer.id, error: errcode(new Error('value not put correctly'), 'ERR_PUT_VALUE_INVALID') }))
177
+ }
178
+ }
179
+
180
+ return events
181
+ }
182
+ }),
183
+ (source) => parallel(source, {
184
+ ordered: false,
185
+ concurrency: ALPHA
186
+ }),
187
+ async function * (source) {
188
+ for await (const events of source) {
189
+ yield * events
190
+ }
191
+ }
192
+ )
193
+ }
194
+
195
+ /**
196
+ * Get the value to the given key
197
+ */
198
+ async * get (key: Uint8Array, options: QueryOptions = {}) {
199
+ this.log('get %b', key)
200
+
201
+ const vals: ValueEvent[] = []
202
+
203
+ for await (const event of this.getMany(key, options)) {
204
+ if (event.name === 'VALUE') {
205
+ vals.push(event)
206
+ }
207
+
208
+ yield event
209
+ }
210
+
211
+ if (vals.length === 0) {
212
+ return
213
+ }
214
+
215
+ const records = vals.map((v) => v.value)
216
+ let i = 0
217
+
218
+ try {
219
+ i = bestRecord(this.selectors, key, records)
220
+ } catch (err: any) {
221
+ // Assume the first record if no selector available
222
+ if (err.code !== 'ERR_NO_SELECTOR_FUNCTION_FOR_RECORD_KEY') {
223
+ throw err
224
+ }
225
+ }
226
+
227
+ const best = records[i]
228
+ this.log('GetValue %b %b', key, best)
229
+
230
+ if (best == null) {
231
+ throw errcode(new Error('best value was not found'), 'ERR_NOT_FOUND')
232
+ }
233
+
234
+ yield * this.sendCorrectionRecord(key, vals, best, options)
235
+
236
+ yield vals[i]
237
+ }
238
+
239
+ /**
240
+ * Get the `n` values to the given key without sorting
241
+ */
242
+ async * getMany (key: Uint8Array, options: QueryOptions = {}) {
243
+ this.log('getMany values for %b', key)
244
+
245
+ try {
246
+ const localRec = await this.getLocal(key)
247
+
248
+ yield valueEvent({
249
+ value: localRec.value,
250
+ from: this.peerId
251
+ })
252
+ } catch (err: any) {
253
+ this.log('error getting local value for %b', key, err)
254
+ }
255
+
256
+ const id = await convertBuffer(key)
257
+ const rtp = this.routingTable.closestPeers(id)
258
+
259
+ this.log('found %d peers in routing table', rtp.length)
260
+
261
+ const self = this // eslint-disable-line @typescript-eslint/no-this-alias
262
+
263
+ const getValueQuery: QueryFunc = async function * ({ peer, signal }) {
264
+ for await (const event of self.peerRouting.getValueOrPeers(peer, key, { signal })) {
265
+ yield event
266
+
267
+ if (event.name === 'PEER_RESPONSE' && (event.record != null)) {
268
+ yield valueEvent({ from: peer, value: event.record.value })
269
+ }
270
+ }
271
+ }
272
+
273
+ // we have peers, lets send the actual query to them
274
+ yield * this.queryManager.run(key, rtp, getValueQuery, options)
275
+ }
276
+ }
@@ -0,0 +1,202 @@
1
+ import { Message, MESSAGE_TYPE } from '../message/index.js'
2
+ import parallel from 'it-parallel'
3
+ import map from 'it-map'
4
+ import { convertBuffer } from '../utils.js'
5
+ import { ALPHA } from '../constants.js'
6
+ import { pipe } from 'it-pipe'
7
+ import {
8
+ queryErrorEvent,
9
+ peerResponseEvent,
10
+ providerEvent
11
+ } from '../query/events.js'
12
+ import { logger } from '@libp2p/logger'
13
+ import type { PeerId } from '@libp2p/interfaces/peer-id'
14
+ import type { QueryEvent, QueryOptions } from '@libp2p/interfaces/dht'
15
+ import type { PeerRouting } from '../peer-routing/index.js'
16
+ import type { QueryManager } from '../query/manager.js'
17
+ import type { RoutingTable } from '../routing-table/index.js'
18
+ import type { Network } from '../network.js'
19
+ import type { Logger } from '@libp2p/logger'
20
+ import type { Providers } from '../providers.js'
21
+ import type { PeerStore } from '@libp2p/interfaces/peer-store'
22
+ import type { QueryFunc } from '../query/types.js'
23
+ import type { CID } from 'multiformats/cid'
24
+ import type { AbortOptions } from '@libp2p/interfaces'
25
+ import type { Multiaddr } from '@multiformats/multiaddr'
26
+ import type { PeerData } from '@libp2p/interfaces/peer-data'
27
+ import { base58btc } from 'multiformats/bases/base58'
28
+
29
+ export interface ContentRoutingOptions {
30
+ peerId: PeerId
31
+ network: Network
32
+ peerRouting: PeerRouting
33
+ queryManager: QueryManager
34
+ routingTable: RoutingTable
35
+ providers: Providers
36
+ peerStore: PeerStore
37
+ lan: boolean
38
+ }
39
+
40
+ export class ContentRouting {
41
+ private readonly log: Logger
42
+ private readonly peerId: PeerId
43
+ private readonly network: Network
44
+ private readonly peerRouting: PeerRouting
45
+ private readonly queryManager: QueryManager
46
+ private readonly routingTable: RoutingTable
47
+ private readonly providers: Providers
48
+ private readonly peerStore: PeerStore
49
+
50
+ constructor (options: ContentRoutingOptions) {
51
+ const { peerId, network, peerRouting, queryManager, routingTable, providers, peerStore, lan } = options
52
+
53
+ this.log = logger(`libp2p:kad-dht:${lan ? 'lan' : 'wan'}:content-routing`)
54
+ this.peerId = peerId
55
+ this.network = network
56
+ this.peerRouting = peerRouting
57
+ this.queryManager = queryManager
58
+ this.routingTable = routingTable
59
+ this.providers = providers
60
+ this.peerStore = peerStore
61
+ }
62
+
63
+ /**
64
+ * Announce to the network that we can provide the value for a given key and
65
+ * are contactable on the given multiaddrs
66
+ */
67
+ async * provide (key: CID, multiaddrs: Multiaddr[], options: AbortOptions = {}) {
68
+ this.log('provide %s', key)
69
+
70
+ // Add peer as provider
71
+ await this.providers.addProvider(key, this.peerId)
72
+
73
+ const msg = new Message(MESSAGE_TYPE.ADD_PROVIDER, key.bytes, 0)
74
+ msg.providerPeers = [{
75
+ id: this.peerId,
76
+ multiaddrs,
77
+ protocols: []
78
+ }]
79
+
80
+ let sent = 0
81
+
82
+ const maybeNotifyPeer = (event: QueryEvent) => {
83
+ return async () => {
84
+ if (event.name !== 'FINAL_PEER') {
85
+ return [event]
86
+ }
87
+
88
+ const events = []
89
+
90
+ this.log('putProvider %s to %p', key, event.peer.id)
91
+
92
+ try {
93
+ this.log('sending provider record for %s to %p', key, event.peer.id)
94
+
95
+ for await (const sendEvent of this.network.sendMessage(event.peer.id, msg, options)) {
96
+ if (sendEvent.name === 'PEER_RESPONSE') {
97
+ this.log('sent provider record for %s to %p', key, event.peer.id)
98
+ sent++
99
+ }
100
+
101
+ events.push(sendEvent)
102
+ }
103
+ } catch (err: any) {
104
+ this.log.error('error sending provide record to peer %p', event.peer.id, err)
105
+ events.push(queryErrorEvent({ from: event.peer.id, error: err }))
106
+ }
107
+
108
+ return events
109
+ }
110
+ }
111
+
112
+ // Notify closest peers
113
+ yield * pipe(
114
+ this.peerRouting.getClosestPeers(key.multihash.bytes, options),
115
+ (source) => map(source, (event) => maybeNotifyPeer(event)),
116
+ (source) => parallel(source, {
117
+ ordered: false,
118
+ concurrency: ALPHA
119
+ }),
120
+ async function * (source) {
121
+ for await (const events of source) {
122
+ yield * events
123
+ }
124
+ }
125
+ )
126
+
127
+ this.log('sent provider records to %d peers', sent)
128
+ }
129
+
130
+ /**
131
+ * Search the dht for up to `K` providers of the given CID.
132
+ */
133
+ async * findProviders (key: CID, options: QueryOptions) {
134
+ const toFind = this.routingTable.kBucketSize
135
+ const target = key.multihash.bytes
136
+ const id = await convertBuffer(target)
137
+ const self = this // eslint-disable-line @typescript-eslint/no-this-alias
138
+
139
+ this.log('findProviders %c', key)
140
+
141
+ const provs = await this.providers.getProviders(key)
142
+
143
+ // yield values if we have some, also slice because maybe we got lucky and already have too many?
144
+ if (provs.length > 0) {
145
+ const providers: PeerData[] = []
146
+
147
+ for (const peerId of provs.slice(0, toFind)) {
148
+ providers.push({
149
+ id: peerId,
150
+ multiaddrs: ((await this.peerStore.addressBook.get(peerId)) ?? []).map(address => address.multiaddr),
151
+ protocols: []
152
+ })
153
+ }
154
+
155
+ yield peerResponseEvent({ from: this.peerId, messageType: MESSAGE_TYPE.GET_PROVIDERS, providers })
156
+ yield providerEvent({ from: this.peerId, providers: providers })
157
+ }
158
+
159
+ // All done
160
+ if (provs.length >= toFind) {
161
+ return
162
+ }
163
+
164
+ /**
165
+ * The query function to use on this particular disjoint path
166
+ */
167
+ const findProvidersQuery: QueryFunc = async function * ({ peer, signal }) {
168
+ const request = new Message(MESSAGE_TYPE.GET_PROVIDERS, target, 0)
169
+
170
+ yield * self.network.sendRequest(peer, request, { signal })
171
+ }
172
+
173
+ const providers = new Set(provs.map(p => p.toString(base58btc)))
174
+
175
+ for await (const event of this.queryManager.run(target, this.routingTable.closestPeers(id), findProvidersQuery, options)) {
176
+ yield event
177
+
178
+ if (event.name === 'PEER_RESPONSE') {
179
+ this.log('Found %d provider entries for %c and %d closer peers', event.providers.length, key, event.closer.length)
180
+
181
+ const newProviders = []
182
+
183
+ for (const peer of event.providers) {
184
+ if (providers.has(peer.id.toString(base58btc))) {
185
+ continue
186
+ }
187
+
188
+ providers.add(peer.id.toString(base58btc))
189
+ newProviders.push(peer)
190
+ }
191
+
192
+ if (newProviders.length > 0) {
193
+ yield providerEvent({ from: event.from, providers: newProviders })
194
+ }
195
+
196
+ if (providers.size === toFind) {
197
+ return
198
+ }
199
+ }
200
+ }
201
+ }
202
+ }