libp2p 0.43.4 → 0.44.0-0d46c78f

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 (215) hide show
  1. package/dist/index.min.js +29 -29
  2. package/dist/src/address-manager/index.d.ts +4 -4
  3. package/dist/src/address-manager/index.d.ts.map +1 -1
  4. package/dist/src/address-manager/index.js +9 -6
  5. package/dist/src/address-manager/index.js.map +1 -1
  6. package/dist/src/autonat/index.d.ts +1 -2
  7. package/dist/src/autonat/index.d.ts.map +1 -1
  8. package/dist/src/autonat/index.js +19 -19
  9. package/dist/src/autonat/index.js.map +1 -1
  10. package/dist/src/circuit-relay/server/advert-service.d.ts.map +1 -1
  11. package/dist/src/circuit-relay/server/advert-service.js +2 -2
  12. package/dist/src/circuit-relay/server/advert-service.js.map +1 -1
  13. package/dist/src/circuit-relay/server/index.d.ts.map +1 -1
  14. package/dist/src/circuit-relay/server/index.js +7 -3
  15. package/dist/src/circuit-relay/server/index.js.map +1 -1
  16. package/dist/src/circuit-relay/transport/discovery.d.ts.map +1 -1
  17. package/dist/src/circuit-relay/transport/discovery.js +3 -1
  18. package/dist/src/circuit-relay/transport/discovery.js.map +1 -1
  19. package/dist/src/circuit-relay/transport/index.d.ts +3 -0
  20. package/dist/src/circuit-relay/transport/index.d.ts.map +1 -1
  21. package/dist/src/circuit-relay/transport/index.js +6 -2
  22. package/dist/src/circuit-relay/transport/index.js.map +1 -1
  23. package/dist/src/circuit-relay/transport/listener.d.ts +3 -0
  24. package/dist/src/circuit-relay/transport/listener.d.ts.map +1 -1
  25. package/dist/src/circuit-relay/transport/listener.js +5 -4
  26. package/dist/src/circuit-relay/transport/listener.js.map +1 -1
  27. package/dist/src/circuit-relay/transport/reservation-store.d.ts +4 -1
  28. package/dist/src/circuit-relay/transport/reservation-store.d.ts.map +1 -1
  29. package/dist/src/circuit-relay/transport/reservation-store.js +11 -6
  30. package/dist/src/circuit-relay/transport/reservation-store.js.map +1 -1
  31. package/dist/src/circuit-relay/utils.d.ts.map +1 -1
  32. package/dist/src/circuit-relay/utils.js +3 -1
  33. package/dist/src/circuit-relay/utils.js.map +1 -1
  34. package/dist/src/components.d.ts +7 -69
  35. package/dist/src/components.d.ts.map +1 -1
  36. package/dist/src/components.js +60 -174
  37. package/dist/src/components.js.map +1 -1
  38. package/dist/src/config/connection-gater.browser.d.ts +8 -0
  39. package/dist/src/config/connection-gater.browser.d.ts.map +1 -0
  40. package/dist/src/config/connection-gater.browser.js +27 -0
  41. package/dist/src/config/connection-gater.browser.js.map +1 -0
  42. package/dist/src/config/connection-gater.d.ts +6 -0
  43. package/dist/src/config/connection-gater.d.ts.map +1 -0
  44. package/dist/src/config/connection-gater.js +18 -0
  45. package/dist/src/config/connection-gater.js.map +1 -0
  46. package/dist/src/config.d.ts +2 -1
  47. package/dist/src/config.d.ts.map +1 -1
  48. package/dist/src/config.js +0 -71
  49. package/dist/src/config.js.map +1 -1
  50. package/dist/src/connection-manager/auto-dial.d.ts +39 -0
  51. package/dist/src/connection-manager/auto-dial.d.ts.map +1 -0
  52. package/dist/src/connection-manager/auto-dial.js +136 -0
  53. package/dist/src/connection-manager/auto-dial.js.map +1 -0
  54. package/dist/src/connection-manager/connection-pruner.d.ts +32 -0
  55. package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -0
  56. package/dist/src/connection-manager/connection-pruner.js +111 -0
  57. package/dist/src/connection-manager/connection-pruner.js.map +1 -0
  58. package/dist/src/connection-manager/constants.d.ts +49 -0
  59. package/dist/src/connection-manager/constants.d.ts.map +1 -0
  60. package/dist/src/connection-manager/constants.js +49 -0
  61. package/dist/src/connection-manager/constants.js.map +1 -0
  62. package/dist/src/connection-manager/dial-queue.d.ts +78 -0
  63. package/dist/src/connection-manager/dial-queue.d.ts.map +1 -0
  64. package/dist/src/connection-manager/dial-queue.js +372 -0
  65. package/dist/src/connection-manager/dial-queue.js.map +1 -0
  66. package/dist/src/connection-manager/index.d.ts +70 -73
  67. package/dist/src/connection-manager/index.d.ts.map +1 -1
  68. package/dist/src/connection-manager/index.js +118 -247
  69. package/dist/src/connection-manager/index.js.map +1 -1
  70. package/dist/src/connection-manager/utils.d.ts +9 -0
  71. package/dist/src/connection-manager/utils.d.ts.map +1 -0
  72. package/dist/src/connection-manager/utils.js +66 -0
  73. package/dist/src/connection-manager/utils.js.map +1 -0
  74. package/dist/src/content-routing/index.d.ts +0 -10
  75. package/dist/src/content-routing/index.d.ts.map +1 -1
  76. package/dist/src/content-routing/index.js +7 -42
  77. package/dist/src/content-routing/index.js.map +1 -1
  78. package/dist/src/content-routing/utils.d.ts.map +1 -1
  79. package/dist/src/content-routing/utils.js +3 -1
  80. package/dist/src/content-routing/utils.js.map +1 -1
  81. package/dist/src/fetch/index.d.ts +13 -35
  82. package/dist/src/fetch/index.d.ts.map +1 -1
  83. package/dist/src/fetch/index.js +10 -12
  84. package/dist/src/fetch/index.js.map +1 -1
  85. package/dist/src/identify/index.d.ts +16 -48
  86. package/dist/src/identify/index.d.ts.map +1 -1
  87. package/dist/src/identify/index.js +203 -201
  88. package/dist/src/identify/index.js.map +1 -1
  89. package/dist/src/index.d.ts +11 -67
  90. package/dist/src/index.d.ts.map +1 -1
  91. package/dist/src/index.js.map +1 -1
  92. package/dist/src/insecure/index.d.ts.map +1 -1
  93. package/dist/src/insecure/index.js +3 -1
  94. package/dist/src/insecure/index.js.map +1 -1
  95. package/dist/src/libp2p.d.ts +12 -35
  96. package/dist/src/libp2p.d.ts.map +1 -1
  97. package/dist/src/libp2p.js +141 -206
  98. package/dist/src/libp2p.js.map +1 -1
  99. package/dist/src/peer-routing.d.ts +1 -38
  100. package/dist/src/peer-routing.d.ts.map +1 -1
  101. package/dist/src/peer-routing.js +0 -59
  102. package/dist/src/peer-routing.js.map +1 -1
  103. package/dist/src/ping/constants.d.ts +4 -0
  104. package/dist/src/ping/constants.d.ts.map +1 -1
  105. package/dist/src/ping/constants.js +10 -0
  106. package/dist/src/ping/constants.js.map +1 -1
  107. package/dist/src/ping/index.d.ts +10 -27
  108. package/dist/src/ping/index.d.ts.map +1 -1
  109. package/dist/src/ping/index.js +18 -21
  110. package/dist/src/ping/index.js.map +1 -1
  111. package/dist/src/registrar.d.ts +5 -2
  112. package/dist/src/registrar.d.ts.map +1 -1
  113. package/dist/src/registrar.js +27 -25
  114. package/dist/src/registrar.js.map +1 -1
  115. package/dist/src/transport-manager.d.ts +15 -4
  116. package/dist/src/transport-manager.d.ts.map +1 -1
  117. package/dist/src/transport-manager.js +37 -12
  118. package/dist/src/transport-manager.js.map +1 -1
  119. package/dist/src/upgrader.d.ts +16 -11
  120. package/dist/src/upgrader.d.ts.map +1 -1
  121. package/dist/src/upgrader.js +38 -47
  122. package/dist/src/upgrader.js.map +1 -1
  123. package/dist/src/upnp-nat/index.d.ts +42 -0
  124. package/dist/src/upnp-nat/index.d.ts.map +1 -0
  125. package/dist/src/{nat-manager.js → upnp-nat/index.js} +11 -7
  126. package/dist/src/upnp-nat/index.js.map +1 -0
  127. package/package.json +70 -54
  128. package/src/address-manager/index.ts +12 -8
  129. package/src/autonat/index.ts +20 -22
  130. package/src/circuit-relay/server/advert-service.ts +2 -2
  131. package/src/circuit-relay/server/index.ts +7 -3
  132. package/src/circuit-relay/transport/discovery.ts +3 -1
  133. package/src/circuit-relay/transport/index.ts +10 -2
  134. package/src/circuit-relay/transport/listener.ts +8 -4
  135. package/src/circuit-relay/transport/reservation-store.ts +15 -7
  136. package/src/circuit-relay/utils.ts +3 -1
  137. package/src/components.ts +72 -251
  138. package/src/config/connection-gater.browser.ts +31 -0
  139. package/src/config/connection-gater.ts +19 -0
  140. package/src/config.ts +3 -73
  141. package/src/connection-manager/auto-dial.ts +189 -0
  142. package/src/connection-manager/connection-pruner.ts +157 -0
  143. package/src/connection-manager/constants.ts +60 -0
  144. package/src/connection-manager/dial-queue.ts +506 -0
  145. package/src/connection-manager/index.ts +194 -339
  146. package/src/connection-manager/utils.ts +76 -0
  147. package/src/content-routing/index.ts +7 -55
  148. package/src/content-routing/utils.ts +3 -1
  149. package/src/fetch/index.ts +55 -18
  150. package/src/identify/index.ts +238 -228
  151. package/src/index.ts +12 -76
  152. package/src/insecure/index.ts +9 -5
  153. package/src/libp2p.ts +146 -265
  154. package/src/peer-routing.ts +1 -101
  155. package/src/ping/constants.ts +11 -0
  156. package/src/ping/index.ts +32 -28
  157. package/src/registrar.ts +31 -27
  158. package/src/transport-manager.ts +49 -15
  159. package/src/upgrader.ts +62 -57
  160. package/src/{nat-manager.ts → upnp-nat/index.ts} +15 -16
  161. package/src/version.ts +1 -1
  162. package/dist/src/connection-manager/auto-dialler.d.ts +0 -42
  163. package/dist/src/connection-manager/auto-dialler.d.ts.map +0 -1
  164. package/dist/src/connection-manager/auto-dialler.js +0 -105
  165. package/dist/src/connection-manager/auto-dialler.js.map +0 -1
  166. package/dist/src/connection-manager/dialer/dial-request.d.ts +0 -27
  167. package/dist/src/connection-manager/dialer/dial-request.d.ts.map +0 -1
  168. package/dist/src/connection-manager/dialer/dial-request.js +0 -114
  169. package/dist/src/connection-manager/dialer/dial-request.js.map +0 -1
  170. package/dist/src/connection-manager/dialer/index.d.ts +0 -121
  171. package/dist/src/connection-manager/dialer/index.d.ts.map +0 -1
  172. package/dist/src/connection-manager/dialer/index.js +0 -324
  173. package/dist/src/connection-manager/dialer/index.js.map +0 -1
  174. package/dist/src/connection-manager/latency-monitor.d.ts +0 -120
  175. package/dist/src/connection-manager/latency-monitor.d.ts.map +0 -1
  176. package/dist/src/connection-manager/latency-monitor.js +0 -220
  177. package/dist/src/connection-manager/latency-monitor.js.map +0 -1
  178. package/dist/src/connection-manager/visibility-change-emitter.d.ts +0 -66
  179. package/dist/src/connection-manager/visibility-change-emitter.d.ts.map +0 -1
  180. package/dist/src/connection-manager/visibility-change-emitter.js +0 -118
  181. package/dist/src/connection-manager/visibility-change-emitter.js.map +0 -1
  182. package/dist/src/constants.d.ts +0 -27
  183. package/dist/src/constants.d.ts.map +0 -1
  184. package/dist/src/constants.js +0 -31
  185. package/dist/src/constants.js.map +0 -1
  186. package/dist/src/dht/dht-content-routing.d.ts +0 -17
  187. package/dist/src/dht/dht-content-routing.d.ts.map +0 -1
  188. package/dist/src/dht/dht-content-routing.js +0 -32
  189. package/dist/src/dht/dht-content-routing.js.map +0 -1
  190. package/dist/src/dht/dht-peer-routing.d.ts +0 -15
  191. package/dist/src/dht/dht-peer-routing.d.ts.map +0 -1
  192. package/dist/src/dht/dht-peer-routing.js +0 -26
  193. package/dist/src/dht/dht-peer-routing.js.map +0 -1
  194. package/dist/src/dht/dummy-dht.d.ts +0 -20
  195. package/dist/src/dht/dummy-dht.d.ts.map +0 -1
  196. package/dist/src/dht/dummy-dht.js +0 -46
  197. package/dist/src/dht/dummy-dht.js.map +0 -1
  198. package/dist/src/nat-manager.d.ts +0 -74
  199. package/dist/src/nat-manager.d.ts.map +0 -1
  200. package/dist/src/nat-manager.js.map +0 -1
  201. package/dist/src/peer-record-updater.d.ts +0 -24
  202. package/dist/src/peer-record-updater.d.ts.map +0 -1
  203. package/dist/src/peer-record-updater.js +0 -44
  204. package/dist/src/peer-record-updater.js.map +0 -1
  205. package/dist/typedoc-urls.json +0 -41
  206. package/src/connection-manager/auto-dialler.ts +0 -158
  207. package/src/connection-manager/dialer/dial-request.ts +0 -144
  208. package/src/connection-manager/dialer/index.ts +0 -461
  209. package/src/connection-manager/latency-monitor.ts +0 -319
  210. package/src/connection-manager/visibility-change-emitter.ts +0 -135
  211. package/src/constants.ts +0 -36
  212. package/src/dht/dht-content-routing.ts +0 -44
  213. package/src/dht/dht-peer-routing.ts +0 -36
  214. package/src/dht/dummy-dht.ts +0 -60
  215. package/src/peer-record-updater.ts +0 -65
@@ -8,6 +8,7 @@ import { Multiaddr, multiaddr, protocols } from '@multiformats/multiaddr'
8
8
  import { Identify } from './pb/message.js'
9
9
  import { RecordEnvelope, PeerRecord } from '@libp2p/peer-record'
10
10
  import {
11
+ AGENT_VERSION,
11
12
  MULTICODEC_IDENTIFY,
12
13
  MULTICODEC_IDENTIFY_PUSH,
13
14
  IDENTIFY_PROTOCOL_VERSION,
@@ -21,50 +22,51 @@ import type { IncomingStreamData, Registrar } from '@libp2p/interface-registrar'
21
22
  import type { Connection, Stream } from '@libp2p/interface-connection'
22
23
  import type { Startable } from '@libp2p/interfaces/startable'
23
24
  import { peerIdFromKeys } from '@libp2p/peer-id'
24
- import { TimeoutController } from 'timeout-abort-controller'
25
25
  import type { AbortOptions } from '@libp2p/interfaces'
26
26
  import { abortableDuplex } from 'abortable-iterator'
27
27
  import { setMaxListeners } from 'events'
28
28
  import type { ConnectionManager } from '@libp2p/interface-connection-manager'
29
29
  import type { PeerId } from '@libp2p/interface-peer-id'
30
- import type { PeerStore } from '@libp2p/interface-peer-store'
30
+ import type { Peer, PeerStore } from '@libp2p/interface-peer-store'
31
31
  import type { AddressManager } from '@libp2p/interface-address-manager'
32
+ import { anySignal } from 'any-signal'
33
+ import type { EventEmitter } from '@libp2p/interfaces/events'
34
+ import type { Libp2pEvents } from '@libp2p/interface-libp2p'
35
+ import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
36
+ import { pbStream } from 'it-pb-stream'
37
+ import { isNode, isBrowser, isWebWorker, isElectronMain, isElectronRenderer, isReactNative } from 'wherearewe'
32
38
 
33
39
  const log = logger('libp2p:identify')
34
40
 
35
41
  // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L52
36
42
  const MAX_IDENTIFY_MESSAGE_SIZE = 1024 * 8
37
43
 
38
- export interface HostProperties {
39
- agentVersion: string
40
- }
41
-
42
44
  export interface IdentifyServiceInit {
43
45
  /**
44
46
  * The prefix to use for the protocol (default: 'ipfs')
45
47
  */
46
- protocolPrefix: string
48
+ protocolPrefix?: string
47
49
 
48
50
  /**
49
51
  * What details we should send as part of an identify message
50
52
  */
51
- host: HostProperties
53
+ agentVersion?: string
52
54
 
53
55
  /**
54
56
  * How long we should wait for a remote peer to send their identify response
55
57
  */
56
- timeout: number
58
+ timeout?: number
57
59
 
58
60
  /**
59
61
  * Identify responses larger than this in bytes will be rejected (default: 8192)
60
62
  */
61
63
  maxIdentifyMessageSize?: number
62
64
 
63
- maxInboundStreams: number
64
- maxOutboundStreams: number
65
+ maxInboundStreams?: number
66
+ maxOutboundStreams?: number
65
67
 
66
- maxPushIncomingStreams: number
67
- maxPushOutgoingStreams: number
68
+ maxPushIncomingStreams?: number
69
+ maxPushOutgoingStreams?: number
68
70
  maxObservedAddresses?: number
69
71
  }
70
72
 
@@ -74,10 +76,37 @@ export interface IdentifyServiceComponents {
74
76
  connectionManager: ConnectionManager
75
77
  registrar: Registrar
76
78
  addressManager: AddressManager
79
+ events: EventEmitter<Libp2pEvents>
80
+ }
81
+
82
+ export interface IdentifyService {
83
+ /**
84
+ * Requests the `Identify` message from peer associated with the given `connection`.
85
+ * If the identified peer does not match the `PeerId` associated with the connection,
86
+ * an error will be thrown.
87
+ */
88
+ identify: (connection: Connection, options?: AbortOptions) => Promise<void>
89
+
90
+ /**
91
+ * Calls `push` on all peer connections
92
+ */
93
+ push: () => Promise<void>
94
+ }
95
+
96
+ const defaultValues = {
97
+ protocolPrefix: 'ipfs',
98
+ agentVersion: AGENT_VERSION,
99
+ // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L48
100
+ timeout: 60000,
101
+ maxInboundStreams: 1,
102
+ maxOutboundStreams: 1,
103
+ maxPushIncomingStreams: 1,
104
+ maxPushOutgoingStreams: 1,
105
+ maxObservedAddresses: 10,
106
+ maxIdentifyMessageSize: 8192
77
107
  }
78
108
 
79
- export class IdentifyService implements Startable {
80
- private readonly components: IdentifyServiceComponents
109
+ class DefaultIdentifyService implements Startable, IdentifyService {
81
110
  private readonly identifyProtocolStr: string
82
111
  private readonly identifyPushProtocolStr: string
83
112
  public readonly host: {
@@ -85,46 +114,63 @@ export class IdentifyService implements Startable {
85
114
  agentVersion: string
86
115
  }
87
116
 
88
- private readonly init: IdentifyServiceInit
89
117
  private started: boolean
118
+ private readonly timeout: number
119
+ private readonly peerId: PeerId
120
+ private readonly peerStore: PeerStore
121
+ private readonly registrar: Registrar
122
+ private readonly connectionManager: ConnectionManager
123
+ private readonly addressManager: AddressManager
124
+ private readonly maxInboundStreams: number
125
+ private readonly maxOutboundStreams: number
126
+ private readonly maxPushIncomingStreams: number
127
+ private readonly maxPushOutgoingStreams: number
128
+ private readonly maxIdentifyMessageSize: number
129
+ private readonly maxObservedAddresses: number
90
130
 
91
131
  constructor (components: IdentifyServiceComponents, init: IdentifyServiceInit) {
92
- this.components = components
93
132
  this.started = false
94
- this.init = init
95
-
96
- this.identifyProtocolStr = `/${init.protocolPrefix}/${MULTICODEC_IDENTIFY_PROTOCOL_NAME}/${MULTICODEC_IDENTIFY_PROTOCOL_VERSION}`
97
- this.identifyPushProtocolStr = `/${init.protocolPrefix}/${MULTICODEC_IDENTIFY_PUSH_PROTOCOL_NAME}/${MULTICODEC_IDENTIFY_PUSH_PROTOCOL_VERSION}`
133
+ this.peerId = components.peerId
134
+ this.peerStore = components.peerStore
135
+ this.registrar = components.registrar
136
+ this.addressManager = components.addressManager
137
+ this.connectionManager = components.connectionManager
138
+
139
+ this.identifyProtocolStr = `/${init.protocolPrefix ?? defaultValues.protocolPrefix}/${MULTICODEC_IDENTIFY_PROTOCOL_NAME}/${MULTICODEC_IDENTIFY_PROTOCOL_VERSION}`
140
+ this.identifyPushProtocolStr = `/${init.protocolPrefix ?? defaultValues.protocolPrefix}/${MULTICODEC_IDENTIFY_PUSH_PROTOCOL_NAME}/${MULTICODEC_IDENTIFY_PUSH_PROTOCOL_VERSION}`
141
+ this.timeout = init.timeout ?? defaultValues.timeout
142
+ this.maxInboundStreams = init.maxInboundStreams ?? defaultValues.maxInboundStreams
143
+ this.maxOutboundStreams = init.maxOutboundStreams ?? defaultValues.maxOutboundStreams
144
+ this.maxPushIncomingStreams = init.maxPushIncomingStreams ?? defaultValues.maxPushIncomingStreams
145
+ this.maxPushOutgoingStreams = init.maxPushOutgoingStreams ?? defaultValues.maxPushOutgoingStreams
146
+ this.maxIdentifyMessageSize = init.maxIdentifyMessageSize ?? defaultValues.maxIdentifyMessageSize
147
+ this.maxObservedAddresses = init.maxObservedAddresses ?? defaultValues.maxObservedAddresses
98
148
 
99
149
  // Store self host metadata
100
150
  this.host = {
101
- protocolVersion: `${init.protocolPrefix}/${IDENTIFY_PROTOCOL_VERSION}`,
102
- ...init.host
151
+ protocolVersion: `${init.protocolPrefix ?? defaultValues.protocolPrefix}/${IDENTIFY_PROTOCOL_VERSION}`,
152
+ agentVersion: init.agentVersion ?? defaultValues.agentVersion
103
153
  }
104
154
 
105
155
  // When a new connection happens, trigger identify
106
- this.components.connectionManager.addEventListener('peer:connect', (evt) => {
156
+ components.events.addEventListener('connection:open', (evt) => {
107
157
  const connection = evt.detail
108
- this.identify(connection).catch(log.error)
158
+ this.identify(connection).catch(err => { log.error('error during identify trigged by connection:open', err) })
109
159
  })
110
160
 
111
- // When self multiaddrs change, trigger identify-push
112
- this.components.peerStore.addEventListener('change:multiaddrs', (evt) => {
113
- const { peerId } = evt.detail
114
-
115
- if (this.components.peerId.equals(peerId)) {
116
- void this.pushToPeerStore().catch(err => { log.error(err) })
117
- }
161
+ // When self peer record changes, trigger identify-push
162
+ components.events.addEventListener('self:peer:update', (evt) => {
163
+ void this.push().catch(err => { log.error(err) })
118
164
  })
119
165
 
120
- // When self protocols change, trigger identify-push
121
- this.components.peerStore.addEventListener('change:protocols', (evt) => {
122
- const { peerId } = evt.detail
123
-
124
- if (this.components.peerId.equals(peerId)) {
125
- void this.pushToPeerStore().catch(err => { log.error(err) })
166
+ // Append user agent version to default AGENT_VERSION depending on the environment
167
+ if (this.host.agentVersion === AGENT_VERSION) {
168
+ if (isNode || isElectronMain) {
169
+ this.host.agentVersion += ` UserAgent=${globalThis.process.version}`
170
+ } else if (isBrowser || isWebWorker || isElectronRenderer || isReactNative) {
171
+ this.host.agentVersion += ` UserAgent=${globalThis.navigator.userAgent}`
126
172
  }
127
- })
173
+ }
128
174
  }
129
175
 
130
176
  isStarted (): boolean {
@@ -136,32 +182,36 @@ export class IdentifyService implements Startable {
136
182
  return
137
183
  }
138
184
 
139
- await this.components.peerStore.metadataBook.setValue(this.components.peerId, 'AgentVersion', uint8ArrayFromString(this.host.agentVersion))
140
- await this.components.peerStore.metadataBook.setValue(this.components.peerId, 'ProtocolVersion', uint8ArrayFromString(this.host.protocolVersion))
185
+ await this.peerStore.merge(this.peerId, {
186
+ metadata: {
187
+ AgentVersion: uint8ArrayFromString(this.host.agentVersion),
188
+ ProtocolVersion: uint8ArrayFromString(this.host.protocolVersion)
189
+ }
190
+ })
141
191
 
142
- await this.components.registrar.handle(this.identifyProtocolStr, (data) => {
192
+ await this.registrar.handle(this.identifyProtocolStr, (data) => {
143
193
  void this._handleIdentify(data).catch(err => {
144
194
  log.error(err)
145
195
  })
146
196
  }, {
147
- maxInboundStreams: this.init.maxInboundStreams,
148
- maxOutboundStreams: this.init.maxOutboundStreams
197
+ maxInboundStreams: this.maxInboundStreams,
198
+ maxOutboundStreams: this.maxOutboundStreams
149
199
  })
150
- await this.components.registrar.handle(this.identifyPushProtocolStr, (data) => {
200
+ await this.registrar.handle(this.identifyPushProtocolStr, (data) => {
151
201
  void this._handlePush(data).catch(err => {
152
202
  log.error(err)
153
203
  })
154
204
  }, {
155
- maxInboundStreams: this.init.maxPushIncomingStreams,
156
- maxOutboundStreams: this.init.maxPushOutgoingStreams
205
+ maxInboundStreams: this.maxPushIncomingStreams,
206
+ maxOutboundStreams: this.maxPushOutgoingStreams
157
207
  })
158
208
 
159
209
  this.started = true
160
210
  }
161
211
 
162
212
  async stop (): Promise<void> {
163
- await this.components.registrar.unhandle(this.identifyProtocolStr)
164
- await this.components.registrar.unhandle(this.identifyPushProtocolStr)
213
+ await this.registrar.unhandle(this.identifyProtocolStr)
214
+ await this.registrar.unhandle(this.identifyPushProtocolStr)
165
215
 
166
216
  this.started = false
167
217
  }
@@ -169,35 +219,45 @@ export class IdentifyService implements Startable {
169
219
  /**
170
220
  * Send an Identify Push update to the list of connections
171
221
  */
172
- async push (connections: Connection[]): Promise<void> {
173
- const signedPeerRecord = await this.components.peerStore.addressBook.getRawEnvelope(this.components.peerId)
174
- const listenAddrs = this.components.addressManager.getAddresses().map((ma) => ma.bytes)
175
- const protocols = await this.components.peerStore.protoBook.get(this.components.peerId)
222
+ async pushToConnections (connections: Connection[]): Promise<void> {
223
+ const listenAddresses = this.addressManager.getAddresses().map(ma => ma.decapsulateCode(protocols('p2p').code))
224
+ const peerRecord = new PeerRecord({
225
+ peerId: this.peerId,
226
+ multiaddrs: listenAddresses
227
+ })
228
+ const signedPeerRecord = await RecordEnvelope.seal(peerRecord, this.peerId)
229
+ const supportedProtocols = this.registrar.getProtocols()
230
+ const peer = await this.peerStore.get(this.peerId)
231
+ const agentVersion = uint8ArrayToString(peer.metadata.get('AgentVersion') ?? uint8ArrayFromString(this.host.agentVersion))
232
+ const protocolVersion = uint8ArrayToString(peer.metadata.get('ProtocolVersion') ?? uint8ArrayFromString(this.host.protocolVersion))
176
233
 
177
234
  const pushes = connections.map(async connection => {
178
235
  let stream: Stream | undefined
179
- const timeoutController = new TimeoutController(this.init.timeout)
236
+
237
+ const signal = AbortSignal.timeout(this.timeout)
180
238
 
181
239
  try {
182
240
  // fails on node < 15.4
183
- setMaxListeners?.(Infinity, timeoutController.signal)
241
+ setMaxListeners?.(Infinity, signal)
184
242
  } catch {}
185
243
 
186
244
  try {
187
245
  stream = await connection.newStream([this.identifyPushProtocolStr], {
188
- signal: timeoutController.signal
246
+ signal
189
247
  })
190
248
 
191
249
  // make stream abortable
192
- const source = abortableDuplex(stream, timeoutController.signal)
250
+ const source = abortableDuplex(stream, signal)
193
251
 
194
252
  await source.sink(pipe(
195
253
  [Identify.encode({
196
- listenAddrs,
197
- signedPeerRecord,
198
- protocols
254
+ listenAddrs: listenAddresses.map(ma => ma.bytes),
255
+ signedPeerRecord: signedPeerRecord.marshal(),
256
+ protocols: supportedProtocols,
257
+ agentVersion,
258
+ protocolVersion
199
259
  })],
200
- lp.encode()
260
+ (source) => lp.encode(source)
201
261
  ))
202
262
  } catch (err: any) {
203
263
  // Just log errors
@@ -206,8 +266,6 @@ export class IdentifyService implements Startable {
206
266
  if (stream != null) {
207
267
  stream.close()
208
268
  }
209
-
210
- timeoutController.clear()
211
269
  }
212
270
  })
213
271
 
@@ -217,7 +275,7 @@ export class IdentifyService implements Startable {
217
275
  /**
218
276
  * Calls `push` on all peer connections
219
277
  */
220
- async pushToPeerStore (): Promise<void> {
278
+ async push (): Promise<void> {
221
279
  // Do not try to push if we are not running
222
280
  if (!this.isStarted()) {
223
281
  return
@@ -225,35 +283,36 @@ export class IdentifyService implements Startable {
225
283
 
226
284
  const connections: Connection[] = []
227
285
 
228
- for (const conn of this.components.connectionManager.getConnections()) {
229
- const peerId = conn.remotePeer
230
- const peer = await this.components.peerStore.get(peerId)
286
+ await Promise.all(
287
+ this.connectionManager.getConnections().map(async conn => {
288
+ try {
289
+ const peer = await this.peerStore.get(conn.remotePeer)
231
290
 
232
- if (!peer.protocols.includes(this.identifyPushProtocolStr)) {
233
- continue
234
- }
291
+ if (!peer.protocols.includes(this.identifyPushProtocolStr)) {
292
+ return
293
+ }
235
294
 
236
- connections.push(conn)
237
- }
295
+ connections.push(conn)
296
+ } catch (err: any) {
297
+ if (err.code !== codes.ERR_NOT_FOUND) {
298
+ throw err
299
+ }
300
+ }
301
+ })
302
+ )
238
303
 
239
- await this.push(connections)
304
+ await this.pushToConnections(connections)
240
305
  }
241
306
 
242
307
  async _identify (connection: Connection, options: AbortOptions = {}): Promise<Identify> {
243
- let timeoutController
244
- let signal = options.signal
245
308
  let stream: Stream | undefined
246
309
 
247
- // create a timeout if no abort signal passed
248
- if (signal == null) {
249
- timeoutController = new TimeoutController(this.init.timeout)
250
- signal = timeoutController.signal
310
+ const signal = anySignal([AbortSignal.timeout(this.timeout), options?.signal])
251
311
 
252
- try {
253
- // fails on node < 15.4
254
- setMaxListeners?.(Infinity, timeoutController.signal)
255
- } catch {}
256
- }
312
+ try {
313
+ // fails on node < 15.4
314
+ setMaxListeners?.(Infinity, signal)
315
+ } catch {}
257
316
 
258
317
  try {
259
318
  stream = await connection.newStream([this.identifyProtocolStr], {
@@ -266,8 +325,8 @@ export class IdentifyService implements Startable {
266
325
  const data = await pipe(
267
326
  [],
268
327
  source,
269
- lp.decode({
270
- maxDataLength: this.init.maxIdentifyMessageSize ?? MAX_IDENTIFY_MESSAGE_SIZE
328
+ (source) => lp.decode(source, {
329
+ maxDataLength: this.maxIdentifyMessageSize ?? MAX_IDENTIFY_MESSAGE_SIZE
271
330
  }),
272
331
  async (source) => await first(source)
273
332
  )
@@ -282,32 +341,19 @@ export class IdentifyService implements Startable {
282
341
  throw new CodeError(String(err), codes.ERR_INVALID_MESSAGE)
283
342
  }
284
343
  } finally {
285
- if (timeoutController != null) {
286
- timeoutController.clear()
287
- }
288
-
289
344
  if (stream != null) {
290
345
  stream.close()
291
346
  }
347
+ signal.clear()
292
348
  }
293
349
  }
294
350
 
295
- /**
296
- * Requests the `Identify` message from peer associated with the given `connection`.
297
- * If the identified peer does not match the `PeerId` associated with the connection,
298
- * an error will be thrown.
299
- */
300
351
  async identify (connection: Connection, options: AbortOptions = {}): Promise<void> {
301
352
  const message = await this._identify(connection, options)
302
-
303
353
  const {
304
354
  publicKey,
305
- listenAddrs,
306
355
  protocols,
307
- observedAddr,
308
- signedPeerRecord,
309
- agentVersion,
310
- protocolVersion
356
+ observedAddr
311
357
  } = message
312
358
 
313
359
  if (publicKey == null) {
@@ -320,72 +366,23 @@ export class IdentifyService implements Startable {
320
366
  throw new CodeError('identified peer does not match the expected peer', codes.ERR_INVALID_PEER)
321
367
  }
322
368
 
323
- if (this.components.peerId.equals(id)) {
369
+ if (this.peerId.equals(id)) {
324
370
  throw new CodeError('identified peer is our own peer id?', codes.ERR_INVALID_PEER)
325
371
  }
326
372
 
327
373
  // Get the observedAddr if there is one
328
- const cleanObservedAddr = IdentifyService.getCleanMultiaddr(observedAddr)
329
-
330
- if (signedPeerRecord != null) {
331
- log('received signed peer record from %p', id)
332
-
333
- try {
334
- const envelope = await RecordEnvelope.openAndCertify(signedPeerRecord, PeerRecord.DOMAIN)
335
-
336
- if (!envelope.peerId.equals(id)) {
337
- throw new CodeError('identified peer does not match the expected peer', codes.ERR_INVALID_PEER)
338
- }
339
-
340
- if (await this.components.peerStore.addressBook.consumePeerRecord(envelope)) {
341
- await this.components.peerStore.protoBook.set(id, protocols)
342
-
343
- if (agentVersion != null) {
344
- await this.components.peerStore.metadataBook.setValue(id, 'AgentVersion', uint8ArrayFromString(agentVersion))
345
- }
346
-
347
- if (protocolVersion != null) {
348
- await this.components.peerStore.metadataBook.setValue(id, 'ProtocolVersion', uint8ArrayFromString(protocolVersion))
349
- }
350
-
351
- log('identify completed for peer %p with and protocols %o', id, protocols)
352
-
353
- return
354
- }
355
- } catch (err: any) {
356
- log('received invalid envelope, discard it and fallback to listenAddrs is available', err)
357
- }
358
- } else {
359
- log('no signed peer record received from %p', id)
360
- }
361
-
362
- log('falling back to legacy addresses from %p', id)
363
-
364
- // LEGACY: Update peers data in PeerStore
365
- try {
366
- await this.components.peerStore.addressBook.set(id, listenAddrs.map((addr) => multiaddr(addr)))
367
- } catch (err: any) {
368
- log.error('received invalid addrs', err)
369
- }
370
-
371
- await this.components.peerStore.protoBook.set(id, protocols)
372
-
373
- if (agentVersion != null) {
374
- await this.components.peerStore.metadataBook.setValue(id, 'AgentVersion', uint8ArrayFromString(agentVersion))
375
- }
376
-
377
- if (protocolVersion != null) {
378
- await this.components.peerStore.metadataBook.setValue(id, 'ProtocolVersion', uint8ArrayFromString(protocolVersion))
379
- }
374
+ const cleanObservedAddr = getCleanMultiaddr(observedAddr)
380
375
 
381
376
  log('identify completed for peer %p and protocols %o', id, protocols)
382
377
  log('our observed address is %s', cleanObservedAddr)
383
378
 
384
379
  if (cleanObservedAddr != null &&
385
- this.components.addressManager.getObservedAddrs().length < (this.init.maxObservedAddresses ?? Infinity)) {
380
+ this.addressManager.getObservedAddrs().length < (this.maxObservedAddresses ?? Infinity)) {
386
381
  log('storing our observed address %s', cleanObservedAddr?.toString())
387
- this.components.addressManager.addObservedAddr(cleanObservedAddr)
382
+ this.addressManager.addObservedAddr(cleanObservedAddr)
388
383
  }
384
+
385
+ await this.#consumeIdentifyMessage(connection.remotePeer, message)
389
386
  }
390
387
 
391
388
  /**
@@ -394,27 +391,27 @@ export class IdentifyService implements Startable {
394
391
  */
395
392
  async _handleIdentify (data: IncomingStreamData): Promise<void> {
396
393
  const { connection, stream } = data
397
- const timeoutController = new TimeoutController(this.init.timeout)
394
+
395
+ const signal = AbortSignal.timeout(this.timeout)
398
396
 
399
397
  try {
400
398
  // fails on node < 15.4
401
- setMaxListeners?.(Infinity, timeoutController.signal)
399
+ setMaxListeners?.(Infinity, signal)
402
400
  } catch {}
403
401
 
404
402
  try {
405
- const publicKey = this.components.peerId.publicKey ?? new Uint8Array(0)
406
- const peerData = await this.components.peerStore.get(this.components.peerId)
407
- const multiaddrs = this.components.addressManager.getAddresses().map(ma => ma.decapsulateCode(protocols('p2p').code))
403
+ const publicKey = this.peerId.publicKey ?? new Uint8Array(0)
404
+ const peerData = await this.peerStore.get(this.peerId)
405
+ const multiaddrs = this.addressManager.getAddresses().map(ma => ma.decapsulateCode(protocols('p2p').code))
408
406
  let signedPeerRecord = peerData.peerRecordEnvelope
409
407
 
410
408
  if (multiaddrs.length > 0 && signedPeerRecord == null) {
411
409
  const peerRecord = new PeerRecord({
412
- peerId: this.components.peerId,
410
+ peerId: this.peerId,
413
411
  multiaddrs
414
412
  })
415
413
 
416
- const envelope = await RecordEnvelope.seal(peerRecord, this.components.peerId)
417
- await this.components.peerStore.addressBook.consumePeerRecord(envelope)
414
+ const envelope = await RecordEnvelope.seal(peerRecord, this.peerId)
418
415
  signedPeerRecord = envelope.marshal().subarray()
419
416
  }
420
417
 
@@ -429,15 +426,14 @@ export class IdentifyService implements Startable {
429
426
  })
430
427
 
431
428
  // make stream abortable
432
- const source = abortableDuplex(stream, timeoutController.signal)
429
+ const source = abortableDuplex(stream, signal)
433
430
 
434
- const msgWithLenPrefix = pipe([message], lp.encode())
431
+ const msgWithLenPrefix = pipe([message], (source) => lp.encode(source))
435
432
  await source.sink(msgWithLenPrefix)
436
433
  } catch (err: any) {
437
434
  log.error('could not respond to identify request', err)
438
435
  } finally {
439
436
  stream.close()
440
- timeoutController.clear()
441
437
  }
442
438
  }
443
439
 
@@ -446,100 +442,110 @@ export class IdentifyService implements Startable {
446
442
  */
447
443
  async _handlePush (data: IncomingStreamData): Promise<void> {
448
444
  const { connection, stream } = data
449
- const timeoutController = new TimeoutController(this.init.timeout)
450
445
 
451
446
  try {
452
- // fails on node < 15.4
453
- setMaxListeners?.(Infinity, timeoutController.signal)
454
- } catch {}
447
+ if (this.peerId.equals(connection.remotePeer)) {
448
+ throw new Error('received push from ourselves?')
449
+ }
455
450
 
456
- let message: Identify | undefined
457
- try {
458
451
  // make stream abortable
459
- const source = abortableDuplex(stream, timeoutController.signal)
460
-
461
- const data = await pipe(
462
- [],
463
- source,
464
- lp.decode({
465
- maxDataLength: this.init.maxIdentifyMessageSize ?? MAX_IDENTIFY_MESSAGE_SIZE
466
- }),
467
- async (source) => await first(source)
468
- )
452
+ const source = abortableDuplex(stream, AbortSignal.timeout(this.timeout))
453
+ const pb = pbStream(source, {
454
+ maxDataLength: this.maxIdentifyMessageSize ?? MAX_IDENTIFY_MESSAGE_SIZE
455
+ })
456
+ const message = await pb.readPB(Identify)
469
457
 
470
- if (data != null) {
471
- message = Identify.decode(data)
472
- }
458
+ await this.#consumeIdentifyMessage(connection.remotePeer, message)
473
459
  } catch (err: any) {
474
460
  log.error('received invalid message', err)
475
461
  return
476
462
  } finally {
477
463
  stream.close()
478
- timeoutController.clear()
479
464
  }
480
465
 
466
+ log('handled push from %p', connection.remotePeer)
467
+ }
468
+
469
+ async #consumeIdentifyMessage (remotePeer: PeerId, message: Identify): Promise<void> {
481
470
  if (message == null) {
482
- log.error('received invalid message')
483
- return
471
+ throw new Error('Message was null or undefined')
484
472
  }
485
473
 
486
- const id = connection.remotePeer
474
+ log('received identify from %p', remotePeer)
487
475
 
488
- if (this.components.peerId.equals(id)) {
489
- log('received push from ourselves?')
476
+ if (message.signedPeerRecord == null) {
490
477
  return
491
478
  }
492
479
 
493
- log('received push from %p', id)
480
+ const envelope = await RecordEnvelope.openAndCertify(message.signedPeerRecord, PeerRecord.DOMAIN)
481
+ const peerRecord = PeerRecord.createFromProtobuf(envelope.payload)
494
482
 
495
- if (message.signedPeerRecord != null) {
496
- log('received signedPeerRecord in push')
483
+ // Verify peerId
484
+ if (!peerRecord.peerId.equals(envelope.peerId)) {
485
+ throw new Error('signing key does not match PeerId in the PeerRecord')
486
+ }
497
487
 
498
- try {
499
- const envelope = await RecordEnvelope.openAndCertify(message.signedPeerRecord, PeerRecord.DOMAIN)
488
+ // Make sure remote peer is the one sending the record
489
+ if (!remotePeer.equals(peerRecord.peerId)) {
490
+ throw new Error('signing key does not match remote PeerId')
491
+ }
500
492
 
501
- if (await this.components.peerStore.addressBook.consumePeerRecord(envelope)) {
502
- log('consumed signedPeerRecord sent in push')
493
+ let peer: Peer | undefined
503
494
 
504
- await this.components.peerStore.protoBook.set(id, message.protocols)
505
- return
506
- } else {
507
- log('failed to consume signedPeerRecord sent in push')
508
- }
509
- } catch (err: any) {
510
- log('received invalid envelope, discard it and fallback to listenAddrs is available', err)
495
+ try {
496
+ peer = await this.peerStore.get(peerRecord.peerId)
497
+ } catch (err: any) {
498
+ if (err.code !== 'ERR_NOT_FOUND') {
499
+ throw err
511
500
  }
512
- } else {
513
- log('did not receive signedPeerRecord in push')
514
501
  }
515
502
 
516
- // LEGACY: Update peers data in PeerStore
517
- try {
518
- await this.components.peerStore.addressBook.set(id, message.listenAddrs.map((addr) => multiaddr(addr)))
519
- } catch (err: any) {
520
- log.error('received invalid addrs', err)
503
+ log('received signedPeerRecord in push from %p', remotePeer)
504
+ let metadata = new Map()
505
+
506
+ if (peer?.peerRecordEnvelope != null) {
507
+ const storedEnvelope = await RecordEnvelope.createFromProtobuf(peer.peerRecordEnvelope)
508
+ const storedRecord = PeerRecord.createFromProtobuf(storedEnvelope.payload)
509
+
510
+ // ensure seq is greater than, or equal to, the last received
511
+ if (storedRecord.seqNumber >= peerRecord.seqNumber) {
512
+ log('sequence number was lower or equal to existing sequence number - stored: %d received: %d', storedRecord.seqNumber, peerRecord.seqNumber)
513
+ }
514
+
515
+ metadata = peer.metadata
521
516
  }
522
517
 
523
- // Update the protocols
524
- try {
525
- await this.components.peerStore.protoBook.set(id, message.protocols)
526
- } catch (err: any) {
527
- log.error('received invalid protocols', err)
518
+ if (message.agentVersion != null) {
519
+ metadata.set('AgentVersion', uint8ArrayFromString(message.agentVersion))
520
+ }
521
+
522
+ if (message.protocolVersion != null) {
523
+ metadata.set('ProtocolVersion', uint8ArrayFromString(message.protocolVersion))
528
524
  }
529
525
 
530
- log('handled push from %p', id)
526
+ await this.peerStore.patch(peerRecord.peerId, {
527
+ peerRecordEnvelope: message.signedPeerRecord,
528
+ protocols: message.protocols,
529
+ addresses: peerRecord.multiaddrs.map(multiaddr => ({
530
+ isCertified: true,
531
+ multiaddr
532
+ })),
533
+ metadata
534
+ })
535
+
536
+ log('consumed signedPeerRecord sent in push from %p', remotePeer)
531
537
  }
538
+ }
532
539
 
533
- /**
534
- * Takes the `addr` and converts it to a Multiaddr if possible
535
- */
536
- static getCleanMultiaddr (addr: Uint8Array | string | null | undefined): Multiaddr | undefined {
537
- if (addr != null && addr.length > 0) {
538
- try {
539
- return multiaddr(addr)
540
- } catch {
540
+ /**
541
+ * Takes the `addr` and converts it to a Multiaddr if possible
542
+ */
543
+ function getCleanMultiaddr (addr: Uint8Array | string | null | undefined): Multiaddr | undefined {
544
+ if (addr != null && addr.length > 0) {
545
+ try {
546
+ return multiaddr(addr)
547
+ } catch {
541
548
 
542
- }
543
549
  }
544
550
  }
545
551
  }
@@ -553,3 +559,7 @@ export const multicodecs = {
553
559
  }
554
560
 
555
561
  export const Message = { Identify }
562
+
563
+ export function identifyService (init: IdentifyServiceInit = {}): (components: IdentifyServiceComponents) => IdentifyService {
564
+ return (components) => new DefaultIdentifyService(components, init)
565
+ }