libp2p 0.37.3 → 0.38.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 (189) hide show
  1. package/README.md +1 -2
  2. package/dist/src/address-manager/index.d.ts +2 -2
  3. package/dist/src/address-manager/index.d.ts.map +1 -1
  4. package/dist/src/circuit/auto-relay.d.ts +4 -4
  5. package/dist/src/circuit/auto-relay.d.ts.map +1 -1
  6. package/dist/src/circuit/circuit/hop.d.ts +7 -5
  7. package/dist/src/circuit/circuit/hop.d.ts.map +1 -1
  8. package/dist/src/circuit/circuit/hop.js +8 -4
  9. package/dist/src/circuit/circuit/hop.js.map +1 -1
  10. package/dist/src/circuit/circuit/stop.d.ts +6 -4
  11. package/dist/src/circuit/circuit/stop.d.ts.map +1 -1
  12. package/dist/src/circuit/circuit/stop.js +4 -2
  13. package/dist/src/circuit/circuit/stop.js.map +1 -1
  14. package/dist/src/circuit/circuit/stream-handler.d.ts +3 -2
  15. package/dist/src/circuit/circuit/stream-handler.d.ts.map +1 -1
  16. package/dist/src/circuit/circuit/stream-handler.js +2 -2
  17. package/dist/src/circuit/circuit/stream-handler.js.map +1 -1
  18. package/dist/src/circuit/index.d.ts +4 -12
  19. package/dist/src/circuit/index.d.ts.map +1 -1
  20. package/dist/src/circuit/index.js.map +1 -1
  21. package/dist/src/circuit/listener.d.ts +3 -3
  22. package/dist/src/circuit/listener.d.ts.map +1 -1
  23. package/dist/src/circuit/pb/index.d.ts +5 -4
  24. package/dist/src/circuit/pb/index.d.ts.map +1 -1
  25. package/dist/src/circuit/pb/index.js +107 -11
  26. package/dist/src/circuit/pb/index.js.map +1 -1
  27. package/dist/src/circuit/transport.d.ts +8 -5
  28. package/dist/src/circuit/transport.d.ts.map +1 -1
  29. package/dist/src/circuit/transport.js +81 -59
  30. package/dist/src/circuit/transport.js.map +1 -1
  31. package/dist/src/config.d.ts.map +1 -1
  32. package/dist/src/config.js +27 -4
  33. package/dist/src/config.js.map +1 -1
  34. package/dist/src/connection-manager/auto-dialler.d.ts +1 -1
  35. package/dist/src/connection-manager/auto-dialler.d.ts.map +1 -1
  36. package/dist/src/connection-manager/dialer/auto-dialer.d.ts +2 -2
  37. package/dist/src/connection-manager/dialer/auto-dialer.d.ts.map +1 -1
  38. package/dist/src/connection-manager/dialer/auto-dialer.js +6 -0
  39. package/dist/src/connection-manager/dialer/auto-dialer.js.map +1 -1
  40. package/dist/src/connection-manager/dialer/dial-request.d.ts +1 -1
  41. package/dist/src/connection-manager/dialer/dial-request.d.ts.map +1 -1
  42. package/dist/src/connection-manager/dialer/index.d.ts +9 -9
  43. package/dist/src/connection-manager/dialer/index.d.ts.map +1 -1
  44. package/dist/src/connection-manager/dialer/index.js +11 -11
  45. package/dist/src/connection-manager/dialer/index.js.map +1 -1
  46. package/dist/src/connection-manager/index.d.ts +20 -16
  47. package/dist/src/connection-manager/index.d.ts.map +1 -1
  48. package/dist/src/connection-manager/index.js +185 -65
  49. package/dist/src/connection-manager/index.js.map +1 -1
  50. package/dist/src/constants.d.ts +4 -0
  51. package/dist/src/constants.d.ts.map +1 -1
  52. package/dist/src/constants.js +4 -0
  53. package/dist/src/constants.js.map +1 -1
  54. package/dist/src/content-routing/index.d.ts +4 -4
  55. package/dist/src/content-routing/index.d.ts.map +1 -1
  56. package/dist/src/content-routing/utils.d.ts +2 -2
  57. package/dist/src/content-routing/utils.d.ts.map +1 -1
  58. package/dist/src/dht/dht-content-routing.d.ts +3 -3
  59. package/dist/src/dht/dht-content-routing.d.ts.map +1 -1
  60. package/dist/src/dht/dht-peer-routing.d.ts +5 -5
  61. package/dist/src/dht/dht-peer-routing.d.ts.map +1 -1
  62. package/dist/src/dht/dummy-dht.d.ts +3 -3
  63. package/dist/src/dht/dummy-dht.d.ts.map +1 -1
  64. package/dist/src/dht/dummy-dht.js +1 -1
  65. package/dist/src/dht/dummy-dht.js.map +1 -1
  66. package/dist/src/errors.d.ts +4 -1
  67. package/dist/src/errors.d.ts.map +1 -1
  68. package/dist/src/errors.js +3 -0
  69. package/dist/src/errors.js.map +1 -1
  70. package/dist/src/fetch/index.d.ts +11 -4
  71. package/dist/src/fetch/index.d.ts.map +1 -1
  72. package/dist/src/fetch/index.js +82 -41
  73. package/dist/src/fetch/index.js.map +1 -1
  74. package/dist/src/fetch/pb/proto.d.ts +4 -3
  75. package/dist/src/fetch/pb/proto.d.ts.map +1 -1
  76. package/dist/src/fetch/pb/proto.js +88 -8
  77. package/dist/src/fetch/pb/proto.js.map +1 -1
  78. package/dist/src/get-peer.d.ts +2 -2
  79. package/dist/src/get-peer.d.ts.map +1 -1
  80. package/dist/src/get-peer.js +1 -1
  81. package/dist/src/get-peer.js.map +1 -1
  82. package/dist/src/identify/index.d.ts +8 -8
  83. package/dist/src/identify/index.d.ts.map +1 -1
  84. package/dist/src/identify/index.js +49 -34
  85. package/dist/src/identify/index.js.map +1 -1
  86. package/dist/src/identify/pb/message.d.ts +2 -1
  87. package/dist/src/identify/pb/message.d.ts.map +1 -1
  88. package/dist/src/identify/pb/message.js +94 -10
  89. package/dist/src/identify/pb/message.js.map +1 -1
  90. package/dist/src/index.d.ts +18 -17
  91. package/dist/src/index.d.ts.map +1 -1
  92. package/dist/src/index.js.map +1 -1
  93. package/dist/src/insecure/index.d.ts +2 -2
  94. package/dist/src/insecure/index.d.ts.map +1 -1
  95. package/dist/src/insecure/index.js +8 -4
  96. package/dist/src/insecure/index.js.map +1 -1
  97. package/dist/src/insecure/pb/proto.d.ts +4 -3
  98. package/dist/src/insecure/pb/proto.d.ts.map +1 -1
  99. package/dist/src/insecure/pb/proto.js +89 -9
  100. package/dist/src/insecure/pb/proto.js.map +1 -1
  101. package/dist/src/keychain/index.d.ts +2 -2
  102. package/dist/src/keychain/index.d.ts.map +1 -1
  103. package/dist/src/libp2p.d.ts +14 -14
  104. package/dist/src/libp2p.d.ts.map +1 -1
  105. package/dist/src/libp2p.js +17 -17
  106. package/dist/src/libp2p.js.map +1 -1
  107. package/dist/src/metrics/index.d.ts +4 -5
  108. package/dist/src/metrics/index.d.ts.map +1 -1
  109. package/dist/src/metrics/index.js +9 -6
  110. package/dist/src/metrics/index.js.map +1 -1
  111. package/dist/src/metrics/moving-average.d.ts +1 -1
  112. package/dist/src/metrics/moving-average.d.ts.map +1 -1
  113. package/dist/src/metrics/stats.d.ts +1 -1
  114. package/dist/src/metrics/stats.d.ts.map +1 -1
  115. package/dist/src/nat-manager.d.ts +1 -1
  116. package/dist/src/nat-manager.d.ts.map +1 -1
  117. package/dist/src/peer-record-updater.d.ts +1 -1
  118. package/dist/src/peer-record-updater.d.ts.map +1 -1
  119. package/dist/src/peer-routing.d.ts +4 -4
  120. package/dist/src/peer-routing.d.ts.map +1 -1
  121. package/dist/src/ping/index.d.ts +10 -3
  122. package/dist/src/ping/index.d.ts.map +1 -1
  123. package/dist/src/ping/index.js +32 -9
  124. package/dist/src/ping/index.js.map +1 -1
  125. package/dist/src/pnet/index.d.ts +1 -2
  126. package/dist/src/pnet/index.d.ts.map +1 -1
  127. package/dist/src/pnet/index.js +2 -1
  128. package/dist/src/pnet/index.js.map +1 -1
  129. package/dist/src/pubsub/dummy-pubsub.d.ts +2 -2
  130. package/dist/src/pubsub/dummy-pubsub.d.ts.map +1 -1
  131. package/dist/src/registrar.d.ts +10 -8
  132. package/dist/src/registrar.d.ts.map +1 -1
  133. package/dist/src/registrar.js +63 -44
  134. package/dist/src/registrar.js.map +1 -1
  135. package/dist/src/transport-manager.d.ts +3 -3
  136. package/dist/src/transport-manager.d.ts.map +1 -1
  137. package/dist/src/upgrader.d.ts +12 -6
  138. package/dist/src/upgrader.d.ts.map +1 -1
  139. package/dist/src/upgrader.js +183 -82
  140. package/dist/src/upgrader.js.map +1 -1
  141. package/dist/src/version.d.ts.map +1 -1
  142. package/dist/src/version.js.map +1 -1
  143. package/package.json +66 -42
  144. package/src/address-manager/index.ts +2 -2
  145. package/src/circuit/README.md +2 -2
  146. package/src/circuit/auto-relay.ts +4 -4
  147. package/src/circuit/circuit/hop.ts +20 -11
  148. package/src/circuit/circuit/stop.ts +10 -5
  149. package/src/circuit/circuit/stream-handler.ts +6 -5
  150. package/src/circuit/index.ts +4 -13
  151. package/src/circuit/listener.ts +3 -3
  152. package/src/circuit/pb/index.ts +133 -15
  153. package/src/circuit/transport.ts +92 -63
  154. package/src/config.ts +27 -4
  155. package/src/connection-manager/auto-dialler.ts +1 -1
  156. package/src/connection-manager/dialer/auto-dialer.ts +8 -2
  157. package/src/connection-manager/dialer/dial-request.ts +1 -1
  158. package/src/connection-manager/dialer/index.ts +15 -15
  159. package/src/connection-manager/index.ts +239 -82
  160. package/src/constants.ts +5 -0
  161. package/src/content-routing/index.ts +2 -2
  162. package/src/content-routing/utils.ts +2 -2
  163. package/src/dht/dht-content-routing.ts +2 -2
  164. package/src/dht/dht-peer-routing.ts +3 -3
  165. package/src/dht/dummy-dht.ts +3 -3
  166. package/src/errors.ts +4 -1
  167. package/src/fetch/index.ts +120 -53
  168. package/src/fetch/pb/proto.ts +109 -11
  169. package/src/get-peer.ts +3 -3
  170. package/src/identify/index.ts +64 -47
  171. package/src/identify/pb/message.ts +111 -11
  172. package/src/index.ts +18 -17
  173. package/src/insecure/index.ts +11 -6
  174. package/src/insecure/pb/proto.ts +111 -12
  175. package/src/keychain/index.ts +2 -2
  176. package/src/libp2p.ts +34 -29
  177. package/src/metrics/index.ts +13 -12
  178. package/src/metrics/moving-average.ts +1 -1
  179. package/src/metrics/stats.ts +1 -1
  180. package/src/nat-manager.ts +1 -1
  181. package/src/peer-record-updater.ts +1 -1
  182. package/src/peer-routing.ts +4 -4
  183. package/src/ping/index.ts +48 -15
  184. package/src/pnet/index.ts +3 -2
  185. package/src/pubsub/dummy-pubsub.ts +2 -2
  186. package/src/registrar.ts +79 -55
  187. package/src/transport-manager.ts +3 -3
  188. package/src/upgrader.ts +223 -93
  189. package/src/version.ts +1 -2
@@ -3,21 +3,30 @@ import errCode from 'err-code'
3
3
  import { codes } from '../errors.js'
4
4
  import * as lp from 'it-length-prefixed'
5
5
  import { FetchRequest, FetchResponse } from './pb/proto.js'
6
- import { handshake } from 'it-handshake'
7
6
  import { PROTOCOL_NAME, PROTOCOL_VERSION } from './constants.js'
8
- import type { PeerId } from '@libp2p/interfaces/peer-id'
7
+ import type { PeerId } from '@libp2p/interface-peer-id'
9
8
  import type { Startable } from '@libp2p/interfaces/startable'
10
- import type { Stream } from '@libp2p/interfaces/connection'
11
- import type { IncomingStreamData } from '@libp2p/interfaces/registrar'
12
- import type { Components } from '@libp2p/interfaces/components'
9
+ import type { Stream } from '@libp2p/interface-connection'
10
+ import type { IncomingStreamData } from '@libp2p/interface-registrar'
11
+ import type { Components } from '@libp2p/components'
13
12
  import type { AbortOptions } from '@libp2p/interfaces'
14
- import type { Duplex } from 'it-stream-types'
15
13
  import { abortableDuplex } from 'abortable-iterator'
14
+ import { pipe } from 'it-pipe'
15
+ import first from 'it-first'
16
+ import { TimeoutController } from 'timeout-abort-controller'
17
+ import { setMaxListeners } from 'events'
16
18
 
17
19
  const log = logger('libp2p:fetch')
18
20
 
19
21
  export interface FetchServiceInit {
20
22
  protocolPrefix: string
23
+ maxInboundStreams: number
24
+ maxOutboundStreams: number
25
+
26
+ /**
27
+ * How long we should wait for a remote peer to send any data
28
+ */
29
+ timeout: number
21
30
  }
22
31
 
23
32
  export interface HandleMessageOptions {
@@ -40,6 +49,7 @@ export class FetchService implements Startable {
40
49
  private readonly components: Components
41
50
  private readonly lookupFunctions: Map<string, LookupFunction>
42
51
  private started: boolean
52
+ private readonly init: FetchServiceInit
43
53
 
44
54
  constructor (components: Components, init: FetchServiceInit) {
45
55
  this.started = false
@@ -47,13 +57,21 @@ export class FetchService implements Startable {
47
57
  this.protocol = `/${init.protocolPrefix ?? 'libp2p'}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}`
48
58
  this.lookupFunctions = new Map() // Maps key prefix to value lookup function
49
59
  this.handleMessage = this.handleMessage.bind(this)
60
+ this.init = init
50
61
  }
51
62
 
52
63
  async start () {
53
64
  await this.components.getRegistrar().handle(this.protocol, (data) => {
54
- void this.handleMessage(data).catch(err => {
55
- log.error(err)
56
- })
65
+ void this.handleMessage(data)
66
+ .catch(err => {
67
+ log.error(err)
68
+ })
69
+ .finally(() => {
70
+ data.stream.close()
71
+ })
72
+ }, {
73
+ maxInboundStreams: this.init.maxInboundStreams,
74
+ maxOutboundStreams: this.init.maxOutboundStreams
57
75
  })
58
76
  this.started = true
59
77
  }
@@ -74,35 +92,69 @@ export class FetchService implements Startable {
74
92
  log('dialing %s to %p', this.protocol, peer)
75
93
 
76
94
  const connection = await this.components.getConnectionManager().openConnection(peer, options)
77
- const { stream } = await connection.newStream([this.protocol], options)
78
- let source: Duplex<Uint8Array> = stream
79
-
80
- // make stream abortable if AbortSignal passed
81
- if (options.signal != null) {
82
- source = abortableDuplex(stream, options.signal)
95
+ let timeoutController
96
+ let signal = options.signal
97
+ let stream: Stream | undefined
98
+
99
+ // create a timeout if no abort signal passed
100
+ if (signal == null) {
101
+ timeoutController = new TimeoutController(this.init.timeout)
102
+ signal = timeoutController.signal
103
+
104
+ try {
105
+ // fails on node < 15.4
106
+ setMaxListeners?.(Infinity, timeoutController.signal)
107
+ } catch {}
83
108
  }
84
109
 
85
- const shake = handshake(source)
86
-
87
- // send message
88
- shake.write(lp.encode.single(FetchRequest.encode({ identifier: key })).slice())
110
+ try {
111
+ stream = await connection.newStream([this.protocol], {
112
+ signal
113
+ })
89
114
 
90
- // read response
91
- // @ts-expect-error fromReader returns a Source which has no .next method
92
- const response = FetchResponse.decode((await lp.decode.fromReader(shake.reader).next()).value.slice())
93
- switch (response.status) {
94
- case (FetchResponse.StatusCode.OK): {
95
- return response.data
96
- }
97
- case (FetchResponse.StatusCode.NOT_FOUND): {
98
- return null
115
+ // make stream abortable
116
+ const source = abortableDuplex(stream, signal)
117
+
118
+ const result = await pipe(
119
+ [FetchRequest.encode({ identifier: key })],
120
+ lp.encode(),
121
+ source,
122
+ lp.decode(),
123
+ async function (source) {
124
+ const buf = await first(source)
125
+
126
+ if (buf == null) {
127
+ throw errCode(new Error('No data received'), codes.ERR_INVALID_MESSAGE)
128
+ }
129
+
130
+ const response = FetchResponse.decode(buf)
131
+
132
+ switch (response.status) {
133
+ case (FetchResponse.StatusCode.OK): {
134
+ return response.data
135
+ }
136
+ case (FetchResponse.StatusCode.NOT_FOUND): {
137
+ return null
138
+ }
139
+ case (FetchResponse.StatusCode.ERROR): {
140
+ const errmsg = (new TextDecoder()).decode(response.data)
141
+ throw errCode(new Error('Error in fetch protocol response: ' + errmsg), codes.ERR_INVALID_PARAMETERS)
142
+ }
143
+ default: {
144
+ throw errCode(new Error('Unknown response status'), codes.ERR_INVALID_MESSAGE)
145
+ }
146
+ }
147
+ }
148
+ )
149
+
150
+ return result ?? null
151
+ } finally {
152
+ if (timeoutController != null) {
153
+ timeoutController.clear()
99
154
  }
100
- case (FetchResponse.StatusCode.ERROR): {
101
- const errmsg = (new TextDecoder()).decode(response.data)
102
- throw errCode(new Error('Error in fetch protocol response: ' + errmsg), codes.ERR_INVALID_PARAMETERS)
103
- }
104
- default: {
105
- throw errCode(new Error('Unknown response status'), codes.ERR_INVALID_MESSAGE)
155
+
156
+ if (stream != null) {
157
+ stream.close()
106
158
  }
107
159
  }
108
160
  }
@@ -114,25 +166,40 @@ export class FetchService implements Startable {
114
166
  */
115
167
  async handleMessage (data: IncomingStreamData) {
116
168
  const { stream } = data
117
- const shake = handshake(stream)
118
- // @ts-expect-error fromReader returns a Source which has no .next method
119
- const request = FetchRequest.decode((await lp.decode.fromReader(shake.reader).next()).value.slice())
120
-
121
- let response: FetchResponse
122
- const lookup = this._getLookupFunction(request.identifier)
123
- if (lookup != null) {
124
- const data = await lookup(request.identifier)
125
- if (data != null) {
126
- response = { status: FetchResponse.StatusCode.OK, data }
127
- } else {
128
- response = { status: FetchResponse.StatusCode.NOT_FOUND, data: new Uint8Array(0) }
129
- }
130
- } else {
131
- const errmsg = (new TextEncoder()).encode('No lookup function registered for key: ' + request.identifier)
132
- response = { status: FetchResponse.StatusCode.ERROR, data: errmsg }
133
- }
134
-
135
- shake.write(lp.encode.single(FetchResponse.encode(response)).slice())
169
+ const self = this
170
+
171
+ await pipe(
172
+ stream,
173
+ lp.decode(),
174
+ async function * (source) {
175
+ const buf = await first(source)
176
+
177
+ if (buf == null) {
178
+ throw errCode(new Error('No data received'), codes.ERR_INVALID_MESSAGE)
179
+ }
180
+
181
+ // for await (const buf of source) {
182
+ const request = FetchRequest.decode(buf)
183
+
184
+ let response: FetchResponse
185
+ const lookup = self._getLookupFunction(request.identifier)
186
+ if (lookup != null) {
187
+ const data = await lookup(request.identifier)
188
+ if (data != null) {
189
+ response = { status: FetchResponse.StatusCode.OK, data }
190
+ } else {
191
+ response = { status: FetchResponse.StatusCode.NOT_FOUND, data: new Uint8Array(0) }
192
+ }
193
+ } else {
194
+ const errmsg = (new TextEncoder()).encode('No lookup function registered for key: ' + request.identifier)
195
+ response = { status: FetchResponse.StatusCode.ERROR, data: errmsg }
196
+ }
197
+
198
+ yield FetchResponse.encode(response)
199
+ },
200
+ lp.encode(),
201
+ stream
202
+ )
136
203
  }
137
204
 
138
205
  /**
@@ -1,7 +1,8 @@
1
1
  /* eslint-disable import/export */
2
2
  /* eslint-disable @typescript-eslint/no-namespace */
3
3
 
4
- import { encodeMessage, decodeMessage, message, string, enumeration, bytes } from 'protons-runtime'
4
+ import { encodeMessage, decodeMessage, message, enumeration } from 'protons-runtime'
5
+ import type { Uint8ArrayList } from 'uint8arraylist'
5
6
  import type { Codec } from 'protons-runtime'
6
7
 
7
8
  export interface FetchRequest {
@@ -9,17 +10,59 @@ export interface FetchRequest {
9
10
  }
10
11
 
11
12
  export namespace FetchRequest {
13
+ let _codec: Codec<FetchRequest>
14
+
12
15
  export const codec = (): Codec<FetchRequest> => {
13
- return message<FetchRequest>({
14
- 1: { name: 'identifier', codec: string }
15
- })
16
+ if (_codec == null) {
17
+ _codec = message<FetchRequest>((obj, writer, opts = {}) => {
18
+ if (opts.lengthDelimited !== false) {
19
+ writer.fork()
20
+ }
21
+
22
+ if (obj.identifier != null) {
23
+ writer.uint32(10)
24
+ writer.string(obj.identifier)
25
+ } else {
26
+ throw new Error('Protocol error: required field "identifier" was not found in object')
27
+ }
28
+
29
+ if (opts.lengthDelimited !== false) {
30
+ writer.ldelim()
31
+ }
32
+ }, (reader, length) => {
33
+ const obj: any = {}
34
+
35
+ const end = length == null ? reader.len : reader.pos + length
36
+
37
+ while (reader.pos < end) {
38
+ const tag = reader.uint32()
39
+
40
+ switch (tag >>> 3) {
41
+ case 1:
42
+ obj.identifier = reader.string()
43
+ break
44
+ default:
45
+ reader.skipType(tag & 7)
46
+ break
47
+ }
48
+ }
49
+
50
+ if (obj.identifier == null) {
51
+ throw new Error('Protocol error: value for required field "identifier" was not found in protobuf')
52
+ }
53
+
54
+ return obj
55
+ })
56
+ }
57
+
58
+ return _codec
16
59
  }
17
60
 
18
61
  export const encode = (obj: FetchRequest): Uint8Array => {
19
62
  return encodeMessage(obj, FetchRequest.codec())
20
63
  }
21
64
 
22
- export const decode = (buf: Uint8Array): FetchRequest => {
65
+ export const decode = (buf: Uint8Array | Uint8ArrayList): FetchRequest => {
23
66
  return decodeMessage(buf, FetchRequest.codec())
24
67
  }
25
68
  }
@@ -44,22 +87,77 @@ export namespace FetchResponse {
44
87
 
45
88
  export namespace StatusCode {
46
89
  export const codec = () => {
47
- return enumeration<typeof StatusCode>(__StatusCodeValues)
90
+ return enumeration<StatusCode>(__StatusCodeValues)
48
91
  }
49
92
  }
50
93
 
94
+ let _codec: Codec<FetchResponse>
95
+
51
96
  export const codec = (): Codec<FetchResponse> => {
52
- return message<FetchResponse>({
53
- 1: { name: 'status', codec: FetchResponse.StatusCode.codec() },
54
- 2: { name: 'data', codec: bytes }
55
- })
97
+ if (_codec == null) {
98
+ _codec = message<FetchResponse>((obj, writer, opts = {}) => {
99
+ if (opts.lengthDelimited !== false) {
100
+ writer.fork()
101
+ }
102
+
103
+ if (obj.status != null) {
104
+ writer.uint32(8)
105
+ FetchResponse.StatusCode.codec().encode(obj.status, writer)
106
+ } else {
107
+ throw new Error('Protocol error: required field "status" was not found in object')
108
+ }
109
+
110
+ if (obj.data != null) {
111
+ writer.uint32(18)
112
+ writer.bytes(obj.data)
113
+ } else {
114
+ throw new Error('Protocol error: required field "data" was not found in object')
115
+ }
116
+
117
+ if (opts.lengthDelimited !== false) {
118
+ writer.ldelim()
119
+ }
120
+ }, (reader, length) => {
121
+ const obj: any = {}
122
+
123
+ const end = length == null ? reader.len : reader.pos + length
124
+
125
+ while (reader.pos < end) {
126
+ const tag = reader.uint32()
127
+
128
+ switch (tag >>> 3) {
129
+ case 1:
130
+ obj.status = FetchResponse.StatusCode.codec().decode(reader)
131
+ break
132
+ case 2:
133
+ obj.data = reader.bytes()
134
+ break
135
+ default:
136
+ reader.skipType(tag & 7)
137
+ break
138
+ }
139
+ }
140
+
141
+ if (obj.status == null) {
142
+ throw new Error('Protocol error: value for required field "status" was not found in protobuf')
143
+ }
144
+
145
+ if (obj.data == null) {
146
+ throw new Error('Protocol error: value for required field "data" was not found in protobuf')
147
+ }
148
+
149
+ return obj
150
+ })
151
+ }
152
+
153
+ return _codec
56
154
  }
57
155
 
58
156
  export const encode = (obj: FetchResponse): Uint8Array => {
59
157
  return encodeMessage(obj, FetchResponse.codec())
60
158
  }
61
159
 
62
- export const decode = (buf: Uint8Array): FetchResponse => {
160
+ export const decode = (buf: Uint8Array | Uint8ArrayList): FetchResponse => {
63
161
  return decodeMessage(buf, FetchResponse.codec())
64
162
  }
65
163
  }
package/src/get-peer.ts CHANGED
@@ -2,9 +2,9 @@ import { peerIdFromString } from '@libp2p/peer-id'
2
2
  import { Multiaddr } from '@multiformats/multiaddr'
3
3
  import errCode from 'err-code'
4
4
  import { codes } from './errors.js'
5
- import { isPeerId } from '@libp2p/interfaces/peer-id'
6
- import type { PeerId } from '@libp2p/interfaces/peer-id'
7
- import type { PeerInfo } from '@libp2p/interfaces/peer-info'
5
+ import { isPeerId } from '@libp2p/interface-peer-id'
6
+ import type { PeerId } from '@libp2p/interface-peer-id'
7
+ import type { PeerInfo } from '@libp2p/interface-peer-info'
8
8
 
9
9
  function peerIdFromMultiaddr (ma: Multiaddr) {
10
10
  const idStr = ma.getPeerId()
@@ -18,21 +18,18 @@ import {
18
18
  MULTICODEC_IDENTIFY_PUSH_PROTOCOL_VERSION
19
19
  } from './consts.js'
20
20
  import { codes } from '../errors.js'
21
- import type { IncomingStreamData } from '@libp2p/interfaces/registrar'
22
- import type { Connection, Stream } from '@libp2p/interfaces/connection'
21
+ import type { IncomingStreamData } from '@libp2p/interface-registrar'
22
+ import type { Connection, Stream } from '@libp2p/interface-connection'
23
23
  import type { Startable } from '@libp2p/interfaces/startable'
24
24
  import { peerIdFromKeys } from '@libp2p/peer-id'
25
- import type { Components } from '@libp2p/interfaces/components'
25
+ import type { Components } from '@libp2p/components'
26
26
  import { TimeoutController } from 'timeout-abort-controller'
27
27
  import type { AbortOptions } from '@libp2p/interfaces'
28
28
  import { abortableDuplex } from 'abortable-iterator'
29
- import type { Duplex } from 'it-stream-types'
29
+ import { setMaxListeners } from 'events'
30
30
 
31
31
  const log = logger('libp2p:identify')
32
32
 
33
- // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L48
34
- const IDENTIFY_TIMEOUT = 60000
35
-
36
33
  // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L52
37
34
  const MAX_IDENTIFY_MESSAGE_SIZE = 1024 * 8
38
35
 
@@ -54,12 +51,18 @@ export interface IdentifyServiceInit {
54
51
  /**
55
52
  * How long we should wait for a remote peer to send their identify response
56
53
  */
57
- timeout?: number
54
+ timeout: number
58
55
 
59
56
  /**
60
57
  * Identify responses larger than this in bytes will be rejected (default: 8192)
61
58
  */
62
59
  maxIdentifyMessageSize?: number
60
+
61
+ maxInboundStreams: number
62
+ maxOutboundStreams: number
63
+
64
+ maxPushIncomingStreams: number
65
+ maxPushOutgoingStreams: number
63
66
  }
64
67
 
65
68
  export class IdentifyService implements Startable {
@@ -79,8 +82,6 @@ export class IdentifyService implements Startable {
79
82
  this.started = false
80
83
  this.init = init
81
84
 
82
- this.handleMessage = this.handleMessage.bind(this)
83
-
84
85
  this.identifyProtocolStr = `/${init.protocolPrefix}/${MULTICODEC_IDENTIFY_PROTOCOL_NAME}/${MULTICODEC_IDENTIFY_PROTOCOL_VERSION}`
85
86
  this.identifyPushProtocolStr = `/${init.protocolPrefix}/${MULTICODEC_IDENTIFY_PUSH_PROTOCOL_NAME}/${MULTICODEC_IDENTIFY_PUSH_PROTOCOL_VERSION}`
86
87
 
@@ -127,13 +128,21 @@ export class IdentifyService implements Startable {
127
128
  await this.components.getPeerStore().metadataBook.setValue(this.components.getPeerId(), 'AgentVersion', uint8ArrayFromString(this.host.agentVersion))
128
129
  await this.components.getPeerStore().metadataBook.setValue(this.components.getPeerId(), 'ProtocolVersion', uint8ArrayFromString(this.host.protocolVersion))
129
130
 
130
- await this.components.getRegistrar().handle([
131
- this.identifyProtocolStr,
132
- this.identifyPushProtocolStr
133
- ], (data) => {
134
- void this.handleMessage(data)?.catch(err => {
131
+ await this.components.getRegistrar().handle(this.identifyProtocolStr, (data) => {
132
+ void this._handleIdentify(data).catch(err => {
133
+ log.error(err)
134
+ })
135
+ }, {
136
+ maxInboundStreams: this.init.maxInboundStreams,
137
+ maxOutboundStreams: this.init.maxOutboundStreams
138
+ })
139
+ await this.components.getRegistrar().handle(this.identifyPushProtocolStr, (data) => {
140
+ void this._handlePush(data).catch(err => {
135
141
  log.error(err)
136
142
  })
143
+ }, {
144
+ maxInboundStreams: this.init.maxPushIncomingStreams,
145
+ maxOutboundStreams: this.init.maxPushOutgoingStreams
137
146
  })
138
147
 
139
148
  this.started = true
@@ -155,17 +164,21 @@ export class IdentifyService implements Startable {
155
164
  const protocols = await this.components.getPeerStore().protoBook.get(this.components.getPeerId())
156
165
 
157
166
  const pushes = connections.map(async connection => {
158
- const timeoutController = new TimeoutController(this.init.timeout ?? IDENTIFY_TIMEOUT)
159
167
  let stream: Stream | undefined
168
+ const timeoutController = new TimeoutController(this.init.timeout)
160
169
 
161
170
  try {
162
- const data = await connection.newStream([this.identifyPushProtocolStr], {
171
+ // fails on node < 15.4
172
+ setMaxListeners?.(Infinity, timeoutController.signal)
173
+ } catch {}
174
+
175
+ try {
176
+ stream = await connection.newStream([this.identifyPushProtocolStr], {
163
177
  signal: timeoutController.signal
164
178
  })
165
- stream = data.stream
166
179
 
167
180
  // make stream abortable
168
- const source: Duplex<Uint8Array> = abortableDuplex(stream, timeoutController.signal)
181
+ const source = abortableDuplex(stream, timeoutController.signal)
169
182
 
170
183
  await pipe(
171
184
  [Identify.encode({
@@ -218,21 +231,29 @@ export class IdentifyService implements Startable {
218
231
  }
219
232
 
220
233
  async _identify (connection: Connection, options: AbortOptions = {}): Promise<Identify> {
221
- const { stream } = await connection.newStream([this.identifyProtocolStr], options)
222
- let source: Duplex<Uint8Array> = stream
223
234
  let timeoutController
224
235
  let signal = options.signal
236
+ let stream: Stream | undefined
225
237
 
226
238
  // create a timeout if no abort signal passed
227
239
  if (signal == null) {
228
- timeoutController = new TimeoutController(this.init.timeout ?? IDENTIFY_TIMEOUT)
240
+ timeoutController = new TimeoutController(this.init.timeout)
229
241
  signal = timeoutController.signal
230
- }
231
242
 
232
- // make stream abortable if AbortSignal passed
233
- source = abortableDuplex(stream, signal)
243
+ try {
244
+ // fails on node < 15.4
245
+ setMaxListeners?.(Infinity, timeoutController.signal)
246
+ } catch {}
247
+ }
234
248
 
235
249
  try {
250
+ stream = await connection.newStream([this.identifyProtocolStr], {
251
+ signal
252
+ })
253
+
254
+ // make stream abortable
255
+ const source = abortableDuplex(stream, signal)
256
+
236
257
  const data = await pipe(
237
258
  [],
238
259
  source,
@@ -256,7 +277,9 @@ export class IdentifyService implements Startable {
256
277
  timeoutController.clear()
257
278
  }
258
279
 
259
- stream.close()
280
+ if (stream != null) {
281
+ stream.close()
282
+ }
260
283
  }
261
284
  }
262
285
 
@@ -353,29 +376,18 @@ export class IdentifyService implements Startable {
353
376
  // this.components.getAddressManager().addObservedAddr(observedAddr)
354
377
  }
355
378
 
356
- /**
357
- * A handler to register with Libp2p to process identify messages
358
- */
359
- handleMessage (data: IncomingStreamData) {
360
- const { protocol } = data
361
-
362
- switch (protocol) {
363
- case this.identifyProtocolStr:
364
- return this._handleIdentify(data)
365
- case this.identifyPushProtocolStr:
366
- return this._handlePush(data)
367
- default:
368
- log.error('cannot handle unknown protocol %s', protocol)
369
- }
370
- }
371
-
372
379
  /**
373
380
  * Sends the `Identify` response with the Signed Peer Record
374
381
  * to the requesting peer over the given `connection`
375
382
  */
376
383
  async _handleIdentify (data: IncomingStreamData) {
377
384
  const { connection, stream } = data
378
- const timeoutController = new TimeoutController(this.init.timeout ?? IDENTIFY_TIMEOUT)
385
+ const timeoutController = new TimeoutController(this.init.timeout)
386
+
387
+ try {
388
+ // fails on node < 15.4
389
+ setMaxListeners?.(Infinity, timeoutController.signal)
390
+ } catch {}
379
391
 
380
392
  try {
381
393
  const publicKey = this.components.getPeerId().publicKey ?? new Uint8Array(0)
@@ -391,7 +403,7 @@ export class IdentifyService implements Startable {
391
403
 
392
404
  const envelope = await RecordEnvelope.seal(peerRecord, this.components.getPeerId())
393
405
  await this.components.getPeerStore().addressBook.consumePeerRecord(envelope)
394
- signedPeerRecord = envelope.marshal()
406
+ signedPeerRecord = envelope.marshal().subarray()
395
407
  }
396
408
 
397
409
  const message = Identify.encode({
@@ -405,7 +417,7 @@ export class IdentifyService implements Startable {
405
417
  })
406
418
 
407
419
  // make stream abortable
408
- const source: Duplex<Uint8Array> = abortableDuplex(stream, timeoutController.signal)
420
+ const source = abortableDuplex(stream, timeoutController.signal)
409
421
 
410
422
  await pipe(
411
423
  [message],
@@ -426,12 +438,17 @@ export class IdentifyService implements Startable {
426
438
  */
427
439
  async _handlePush (data: IncomingStreamData) {
428
440
  const { connection, stream } = data
429
- const timeoutController = new TimeoutController(this.init.timeout ?? IDENTIFY_TIMEOUT)
441
+ const timeoutController = new TimeoutController(this.init.timeout)
442
+
443
+ try {
444
+ // fails on node < 15.4
445
+ setMaxListeners?.(Infinity, timeoutController.signal)
446
+ } catch {}
430
447
 
431
448
  let message: Identify | undefined
432
449
  try {
433
450
  // make stream abortable
434
- const source: Duplex<Uint8Array> = abortableDuplex(stream, timeoutController.signal)
451
+ const source = abortableDuplex(stream, timeoutController.signal)
435
452
 
436
453
  const data = await pipe(
437
454
  [],