@libp2p/utils 6.7.2-8484de8a2 → 6.7.2-87bc8d4fb

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 (164) hide show
  1. package/README.md +1 -1
  2. package/dist/index.min.js +1 -6
  3. package/dist/index.min.js.map +4 -4
  4. package/dist/src/abort-options.d.ts +7 -0
  5. package/dist/src/abort-options.d.ts.map +1 -0
  6. package/dist/src/abort-options.js +14 -0
  7. package/dist/src/abort-options.js.map +1 -0
  8. package/dist/src/abstract-stream.d.ts +130 -14
  9. package/dist/src/abstract-stream.d.ts.map +1 -1
  10. package/dist/src/abstract-stream.js +321 -39
  11. package/dist/src/abstract-stream.js.map +1 -1
  12. package/dist/src/array-equals.d.ts +24 -0
  13. package/dist/src/array-equals.d.ts.map +1 -0
  14. package/dist/src/array-equals.js +31 -0
  15. package/dist/src/array-equals.js.map +1 -0
  16. package/dist/src/close-source.d.ts +4 -0
  17. package/dist/src/close-source.d.ts.map +1 -0
  18. package/dist/src/close-source.js +11 -0
  19. package/dist/src/close-source.js.map +1 -0
  20. package/dist/src/close.d.ts +21 -0
  21. package/dist/src/close.d.ts.map +1 -0
  22. package/dist/src/close.js +49 -0
  23. package/dist/src/close.js.map +1 -0
  24. package/dist/src/errors.d.ts +0 -8
  25. package/dist/src/errors.d.ts.map +1 -1
  26. package/dist/src/errors.js +0 -8
  27. package/dist/src/errors.js.map +1 -1
  28. package/dist/src/get-thin-waist-addresses.browser.d.ts +1 -1
  29. package/dist/src/get-thin-waist-addresses.browser.d.ts.map +1 -1
  30. package/dist/src/get-thin-waist-addresses.browser.js +3 -4
  31. package/dist/src/get-thin-waist-addresses.browser.js.map +1 -1
  32. package/dist/src/get-thin-waist-addresses.d.ts +1 -1
  33. package/dist/src/get-thin-waist-addresses.d.ts.map +1 -1
  34. package/dist/src/get-thin-waist-addresses.js +9 -7
  35. package/dist/src/get-thin-waist-addresses.js.map +1 -1
  36. package/dist/src/index.d.ts +1 -33
  37. package/dist/src/index.d.ts.map +1 -1
  38. package/dist/src/index.js +1 -33
  39. package/dist/src/index.js.map +1 -1
  40. package/dist/src/multiaddr/is-global-unicast.d.ts.map +1 -1
  41. package/dist/src/multiaddr/is-global-unicast.js +9 -8
  42. package/dist/src/multiaddr/is-global-unicast.js.map +1 -1
  43. package/dist/src/multiaddr/is-ip-based.d.ts +6 -0
  44. package/dist/src/multiaddr/is-ip-based.d.ts.map +1 -0
  45. package/dist/src/multiaddr/is-ip-based.js +18 -0
  46. package/dist/src/multiaddr/is-ip-based.js.map +1 -0
  47. package/dist/src/multiaddr/is-link-local.d.ts.map +1 -1
  48. package/dist/src/multiaddr/is-link-local.js +16 -11
  49. package/dist/src/multiaddr/is-link-local.js.map +1 -1
  50. package/dist/src/multiaddr/is-loopback.d.ts.map +1 -1
  51. package/dist/src/multiaddr/is-loopback.js +5 -12
  52. package/dist/src/multiaddr/is-loopback.js.map +1 -1
  53. package/dist/src/multiaddr/is-network-address.d.ts.map +1 -1
  54. package/dist/src/multiaddr/is-network-address.js +16 -4
  55. package/dist/src/multiaddr/is-network-address.js.map +1 -1
  56. package/dist/src/multiaddr/is-private.d.ts.map +1 -1
  57. package/dist/src/multiaddr/is-private.js +10 -9
  58. package/dist/src/multiaddr/is-private.js.map +1 -1
  59. package/dist/src/queue/index.d.ts +0 -3
  60. package/dist/src/queue/index.d.ts.map +1 -1
  61. package/dist/src/queue/index.js +4 -20
  62. package/dist/src/queue/index.js.map +1 -1
  63. package/dist/src/rate-limiter.d.ts +15 -1
  64. package/dist/src/rate-limiter.d.ts.map +1 -1
  65. package/dist/src/rate-limiter.js +14 -1
  66. package/dist/src/rate-limiter.js.map +1 -1
  67. package/dist/src/stream-to-ma-conn.d.ts +23 -0
  68. package/dist/src/stream-to-ma-conn.d.ts.map +1 -0
  69. package/dist/src/stream-to-ma-conn.js +75 -0
  70. package/dist/src/stream-to-ma-conn.js.map +1 -0
  71. package/package.json +163 -19
  72. package/src/abort-options.ts +20 -0
  73. package/src/abstract-stream.ts +464 -51
  74. package/src/array-equals.ts +34 -0
  75. package/src/close-source.ts +14 -0
  76. package/src/close.ts +65 -0
  77. package/src/errors.ts +0 -10
  78. package/src/get-thin-waist-addresses.browser.ts +4 -5
  79. package/src/get-thin-waist-addresses.ts +12 -8
  80. package/src/index.ts +1 -33
  81. package/src/multiaddr/is-global-unicast.ts +11 -8
  82. package/src/multiaddr/is-ip-based.ts +21 -0
  83. package/src/multiaddr/is-link-local.ts +20 -11
  84. package/src/multiaddr/is-loopback.ts +7 -12
  85. package/src/multiaddr/is-network-address.ts +19 -4
  86. package/src/multiaddr/is-private.ts +14 -9
  87. package/src/queue/index.ts +4 -24
  88. package/src/rate-limiter.ts +30 -3
  89. package/src/stream-to-ma-conn.ts +106 -0
  90. package/dist/src/abstract-message-stream.d.ts +0 -129
  91. package/dist/src/abstract-message-stream.d.ts.map +0 -1
  92. package/dist/src/abstract-message-stream.js +0 -389
  93. package/dist/src/abstract-message-stream.js.map +0 -1
  94. package/dist/src/abstract-multiaddr-connection.d.ts +0 -26
  95. package/dist/src/abstract-multiaddr-connection.d.ts.map +0 -1
  96. package/dist/src/abstract-multiaddr-connection.js +0 -66
  97. package/dist/src/abstract-multiaddr-connection.js.map +0 -1
  98. package/dist/src/abstract-stream-muxer.d.ts +0 -53
  99. package/dist/src/abstract-stream-muxer.d.ts.map +0 -1
  100. package/dist/src/abstract-stream-muxer.js +0 -169
  101. package/dist/src/abstract-stream-muxer.js.map +0 -1
  102. package/dist/src/length-prefixed-decoder.d.ts +0 -37
  103. package/dist/src/length-prefixed-decoder.d.ts.map +0 -1
  104. package/dist/src/length-prefixed-decoder.js +0 -64
  105. package/dist/src/length-prefixed-decoder.js.map +0 -1
  106. package/dist/src/message-queue.d.ts +0 -61
  107. package/dist/src/message-queue.d.ts.map +0 -1
  108. package/dist/src/message-queue.js +0 -93
  109. package/dist/src/message-queue.js.map +0 -1
  110. package/dist/src/mock-muxer.d.ts +0 -57
  111. package/dist/src/mock-muxer.d.ts.map +0 -1
  112. package/dist/src/mock-muxer.js +0 -204
  113. package/dist/src/mock-muxer.js.map +0 -1
  114. package/dist/src/mock-stream.d.ts +0 -31
  115. package/dist/src/mock-stream.d.ts.map +0 -1
  116. package/dist/src/mock-stream.js +0 -69
  117. package/dist/src/mock-stream.js.map +0 -1
  118. package/dist/src/multiaddr/get-net-config.d.ts +0 -55
  119. package/dist/src/multiaddr/get-net-config.d.ts.map +0 -1
  120. package/dist/src/multiaddr/get-net-config.js +0 -54
  121. package/dist/src/multiaddr/get-net-config.js.map +0 -1
  122. package/dist/src/multiaddr/index.d.ts +0 -7
  123. package/dist/src/multiaddr/index.d.ts.map +0 -1
  124. package/dist/src/multiaddr/index.js +0 -7
  125. package/dist/src/multiaddr/index.js.map +0 -1
  126. package/dist/src/multiaddr/utils.d.ts +0 -5
  127. package/dist/src/multiaddr/utils.d.ts.map +0 -1
  128. package/dist/src/multiaddr/utils.js +0 -32
  129. package/dist/src/multiaddr/utils.js.map +0 -1
  130. package/dist/src/multiaddr-connection-pair.d.ts +0 -25
  131. package/dist/src/multiaddr-connection-pair.d.ts.map +0 -1
  132. package/dist/src/multiaddr-connection-pair.js +0 -103
  133. package/dist/src/multiaddr-connection-pair.js.map +0 -1
  134. package/dist/src/socket-writer.browser.d.ts +0 -2
  135. package/dist/src/socket-writer.browser.d.ts.map +0 -1
  136. package/dist/src/socket-writer.browser.js +0 -4
  137. package/dist/src/socket-writer.browser.js.map +0 -1
  138. package/dist/src/socket-writer.d.ts +0 -19
  139. package/dist/src/socket-writer.d.ts.map +0 -1
  140. package/dist/src/socket-writer.js +0 -43
  141. package/dist/src/socket-writer.js.map +0 -1
  142. package/dist/src/stream-pair.d.ts +0 -42
  143. package/dist/src/stream-pair.d.ts.map +0 -1
  144. package/dist/src/stream-pair.js +0 -40
  145. package/dist/src/stream-pair.js.map +0 -1
  146. package/dist/src/stream-utils.d.ts +0 -198
  147. package/dist/src/stream-utils.d.ts.map +0 -1
  148. package/dist/src/stream-utils.js +0 -369
  149. package/dist/src/stream-utils.js.map +0 -1
  150. package/src/abstract-message-stream.ts +0 -549
  151. package/src/abstract-multiaddr-connection.ts +0 -93
  152. package/src/abstract-stream-muxer.ts +0 -239
  153. package/src/length-prefixed-decoder.ts +0 -98
  154. package/src/message-queue.ts +0 -156
  155. package/src/mock-muxer.ts +0 -304
  156. package/src/mock-stream.ts +0 -101
  157. package/src/multiaddr/get-net-config.ts +0 -112
  158. package/src/multiaddr/index.ts +0 -6
  159. package/src/multiaddr/utils.ts +0 -46
  160. package/src/multiaddr-connection-pair.ts +0 -147
  161. package/src/socket-writer.browser.ts +0 -3
  162. package/src/socket-writer.ts +0 -64
  163. package/src/stream-pair.ts +0 -90
  164. package/src/stream-utils.ts +0 -873
package/src/close.ts ADDED
@@ -0,0 +1,65 @@
1
+ import type { Connection, Stream, AbortOptions } from '@libp2p/interface'
2
+
3
+ /**
4
+ * Close the passed stream, falling back to aborting the stream if closing
5
+ * cleanly fails.
6
+ */
7
+ export async function safelyCloseStream (stream?: Stream, options?: AbortOptions): Promise<void> {
8
+ try {
9
+ await stream?.close(options)
10
+ } catch (err: any) {
11
+ stream?.abort(err)
12
+ }
13
+ }
14
+
15
+ /**
16
+ * These are speculative protocols that are run automatically on connection open
17
+ * so are usually not the reason the connection was opened.
18
+ *
19
+ * Consequently when requested it should be safe to close connections that only
20
+ * have these protocol streams open.
21
+ */
22
+ const DEFAULT_CLOSABLE_PROTOCOLS = [
23
+ // identify
24
+ '/ipfs/id/1.0.0',
25
+
26
+ // identify-push
27
+ '/ipfs/id/push/1.0.0',
28
+
29
+ // autonat
30
+ '/libp2p/autonat/1.0.0',
31
+
32
+ // dcutr
33
+ '/libp2p/dcutr'
34
+ ]
35
+
36
+ export interface SafelyCloseConnectionOptions extends AbortOptions {
37
+ /**
38
+ * Only close the stream if it either has no protocol streams open or only
39
+ * ones in this list.
40
+ *
41
+ * @default ['/ipfs/id/1.0.0']
42
+ */
43
+ closableProtocols?: string[]
44
+ }
45
+
46
+ /**
47
+ * Close the passed connection if it has no streams, or only closable protocol
48
+ * streams, falling back to aborting the connection if closing it cleanly fails.
49
+ */
50
+ export async function safelyCloseConnectionIfUnused (connection?: Connection, options?: SafelyCloseConnectionOptions): Promise<void> {
51
+ const streamProtocols = connection?.streams?.map(stream => stream.protocol) ?? []
52
+ const closableProtocols = options?.closableProtocols ?? DEFAULT_CLOSABLE_PROTOCOLS
53
+
54
+ // if the connection has protocols not in the closable protocols list, do not
55
+ // close the connection
56
+ if (streamProtocols.filter(proto => proto != null && !closableProtocols.includes(proto)).length > 0) {
57
+ return
58
+ }
59
+
60
+ try {
61
+ await connection?.close(options)
62
+ } catch (err: any) {
63
+ connection?.abort(err)
64
+ }
65
+ }
package/src/errors.ts CHANGED
@@ -27,13 +27,3 @@ export class QueueFullError extends Error {
27
27
  this.name = 'QueueFullError'
28
28
  }
29
29
  }
30
-
31
- export class UnexpectedEOFError extends Error {
32
- static name = 'UnexpectedEOFError'
33
- name = 'UnexpectedEOFError'
34
- }
35
-
36
- export class MaxEarlyStreamsError extends Error {
37
- static name = 'MaxEarlyStreamsError'
38
- name = 'MaxEarlyStreamsError'
39
- }
@@ -1,5 +1,4 @@
1
- import { getNetConfig } from './multiaddr/get-net-config.ts'
2
- import { netConfigToMultiaddr } from './multiaddr/utils.ts'
1
+ import { multiaddr } from '@multiformats/multiaddr'
3
2
  import type { Multiaddr } from '@multiformats/multiaddr'
4
3
 
5
4
  /**
@@ -8,14 +7,14 @@ import type { Multiaddr } from '@multiformats/multiaddr'
8
7
  *
9
8
  * Wildcard IP4/6 addresses will be expanded into all available interfaces.
10
9
  */
11
- export function getThinWaistAddresses (ma?: Multiaddr, port?: number | string): Multiaddr[] {
10
+ export function getThinWaistAddresses (ma?: Multiaddr, port?: number): Multiaddr[] {
12
11
  if (ma == null) {
13
12
  return []
14
13
  }
15
14
 
16
- const config = getNetConfig(ma)
15
+ const options = ma.toOptions()
17
16
 
18
17
  return [
19
- netConfigToMultiaddr(config, port)
18
+ multiaddr(`/ip${options.family}/${options.host}/${options.transport}/${port ?? options.port}`)
20
19
  ]
21
20
  }
@@ -1,7 +1,6 @@
1
1
  import os from 'node:os'
2
+ import { multiaddr } from '@multiformats/multiaddr'
2
3
  import { isLinkLocalIp } from './link-local-ip.js'
3
- import { getNetConfig } from './multiaddr/get-net-config.ts'
4
- import { netConfigToMultiaddr } from './multiaddr/utils.ts'
5
4
  import type { Multiaddr } from '@multiformats/multiaddr'
6
5
 
7
6
  const FAMILIES = { 4: 'IPv4', 6: 'IPv6' }
@@ -37,19 +36,24 @@ function getNetworkAddrs (family: 4 | 6): string[] {
37
36
  *
38
37
  * Wildcard IP4/6 addresses will be expanded into all available interfaces.
39
38
  */
40
- export function getThinWaistAddresses (ma?: Multiaddr, port?: number | string): Multiaddr[] {
39
+ export function getThinWaistAddresses (ma?: Multiaddr, port?: number): Multiaddr[] {
41
40
  if (ma == null) {
42
41
  return []
43
42
  }
44
43
 
45
- const config = getNetConfig(ma)
44
+ const options = ma.toOptions()
46
45
 
47
- if ((config.type === 'ip4' || config.type === 'ip6') && isWildcard(config.host)) {
48
- return getNetworkAddrs(config.type === 'ip4' ? 4 : 6)
49
- .map(host => netConfigToMultiaddr(config, port, host))
46
+ if (isWildcard(options.host)) {
47
+ const addrs = []
48
+
49
+ for (const host of getNetworkAddrs(options.family)) {
50
+ addrs.push(multiaddr(`/ip${options.family}/${host}/${options.transport}/${port ?? options.port}`))
51
+ }
52
+
53
+ return addrs
50
54
  }
51
55
 
52
56
  return [
53
- netConfigToMultiaddr(config, port)
57
+ multiaddr(`/ip${options.family}/${options.host}/${options.transport}/${port ?? options.port}`)
54
58
  ]
55
59
  }
package/src/index.ts CHANGED
@@ -4,36 +4,4 @@
4
4
  * This module contains utility functions used by libp2p modules.
5
5
  */
6
6
 
7
- export * from './filters/index.js'
8
- export * from './multiaddr/index.js'
9
- export * from './queue/index.js'
10
- export * from './abstract-message-stream.js'
11
- export * from './abstract-multiaddr-connection.js'
12
- export * from './abstract-stream-muxer.js'
13
- export * from './abstract-stream.js'
14
- export * from './adaptive-timeout.js'
15
- export * from './debounce.js'
16
- export * from './errors.js'
17
- export * from './get-thin-waist-addresses.js'
18
- export * from './global-unicast-ip.js'
19
- export * from './ip-port-to-multiaddr.js'
20
- export * from './is-async-generator.js'
21
- export * from './is-generator.js'
22
- export * from './is-promise.js'
23
- export * from './length-prefixed-decoder.js'
24
- export * from './link-local-ip.js'
25
- export * from './merge-options.js'
26
- export * from './mock-muxer.js'
27
- export * from './mock-stream.js'
28
- export * from './moving-average.js'
29
- export * from './multiaddr-connection-pair.js'
30
- export * from './peer-queue.js'
31
- export * from './priority-queue.js'
32
- export * from './private-ip.js'
33
- export * from './rate-limiter.js'
34
- export * from './repeating-task.js'
35
- export * from './stream-pair.js'
36
- export * from './stream-utils.js'
37
- export * from './socket-writer.js'
38
- export * from './tracked-list.js'
39
- export * from './tracked-map.js'
7
+ export {}
@@ -1,5 +1,5 @@
1
1
  import { cidrContains } from '@chainsafe/netmask'
2
- import { getNetConfig } from './get-net-config.ts'
2
+ import { CODE_IP6 } from '@multiformats/multiaddr'
3
3
  import type { Multiaddr } from '@multiformats/multiaddr'
4
4
 
5
5
  /**
@@ -7,15 +7,18 @@ import type { Multiaddr } from '@multiformats/multiaddr'
7
7
  */
8
8
  export function isGlobalUnicast (ma: Multiaddr): boolean {
9
9
  try {
10
- const config = getNetConfig(ma)
10
+ for (const { code, value } of ma.getComponents()) {
11
+ if (value == null) {
12
+ continue
13
+ }
11
14
 
12
- switch (config.type) {
13
- case 'ip6':
14
- return cidrContains('2000::/3', config.host)
15
- default:
16
- return false
15
+ if (code === CODE_IP6) {
16
+ return cidrContains('2000::/3', value)
17
+ }
17
18
  }
18
19
  } catch {
19
- return false
20
+
20
21
  }
22
+
23
+ return false
21
24
  }
@@ -0,0 +1,21 @@
1
+ import { CODE_IP4, CODE_IP6, CODE_IP6ZONE } from '@multiformats/multiaddr'
2
+ import type { Multiaddr } from '@multiformats/multiaddr'
3
+
4
+ /**
5
+ * Check if a given multiaddr is IP-based
6
+ */
7
+ export function isIpBased (ma: Multiaddr): boolean {
8
+ try {
9
+ for (const { code } of ma.getComponents()) {
10
+ if (code === CODE_IP6ZONE) {
11
+ continue
12
+ }
13
+
14
+ return code === CODE_IP4 || code === CODE_IP6
15
+ }
16
+ } catch {
17
+
18
+ }
19
+
20
+ return false
21
+ }
@@ -1,4 +1,4 @@
1
- import { getNetConfig } from './get-net-config.ts'
1
+ import { CODE_IP4, CODE_IP6, CODE_IP6ZONE } from '@multiformats/multiaddr'
2
2
  import type { Multiaddr } from '@multiformats/multiaddr'
3
3
 
4
4
  /**
@@ -6,17 +6,26 @@ import type { Multiaddr } from '@multiformats/multiaddr'
6
6
  */
7
7
  export function isLinkLocal (ma: Multiaddr): boolean {
8
8
  try {
9
- const config = getNetConfig(ma)
9
+ for (const { code, value } of ma.getComponents()) {
10
+ if (code === CODE_IP6ZONE) {
11
+ continue
12
+ }
10
13
 
11
- switch (config.type) {
12
- case 'ip4':
13
- return config.host.startsWith('169.254.')
14
- case 'ip6':
15
- return config.host.toLowerCase().startsWith('fe80')
16
- default:
17
- return false
14
+ if (value == null) {
15
+ continue
16
+ }
17
+
18
+ if (code === CODE_IP4) {
19
+ return value.startsWith('169.254.')
20
+ }
21
+
22
+ if (code === CODE_IP6) {
23
+ return value.toLowerCase().startsWith('fe80')
24
+ }
18
25
  }
19
- } catch (err) {
20
- return false
26
+ } catch {
27
+
21
28
  }
29
+
30
+ return false
22
31
  }
@@ -1,22 +1,17 @@
1
1
  import { isLoopbackAddr } from 'is-loopback-addr'
2
- import { getNetConfig } from './get-net-config.ts'
2
+ import { isIpBased } from './is-ip-based.js'
3
3
  import type { Multiaddr } from '@multiformats/multiaddr'
4
4
 
5
5
  /**
6
6
  * Check if a given multiaddr is a loopback address.
7
7
  */
8
8
  export function isLoopback (ma: Multiaddr): boolean {
9
- try {
10
- const config = getNetConfig(ma)
11
-
12
- switch (config.type) {
13
- case 'ip4':
14
- case 'ip6':
15
- return isLoopbackAddr(config.host)
16
- default:
17
- return false
18
- }
19
- } catch {
9
+ if (!isIpBased(ma)) {
10
+ // not an IP based multiaddr, cannot be private
20
11
  return false
21
12
  }
13
+
14
+ const { address } = ma.nodeAddress()
15
+
16
+ return isLoopbackAddr(address)
22
17
  }
@@ -1,15 +1,30 @@
1
- import { getNetConfig } from './get-net-config.ts'
1
+ import { CODE_IP4, CODE_IP6, CODE_IP6ZONE, CODE_DNS, CODE_DNS4, CODE_DNS6, CODE_DNSADDR } from '@multiformats/multiaddr'
2
2
  import type { Multiaddr } from '@multiformats/multiaddr'
3
3
 
4
+ const NETWORK_CODECS = [
5
+ CODE_IP4,
6
+ CODE_IP6,
7
+ CODE_DNS,
8
+ CODE_DNS4,
9
+ CODE_DNS6,
10
+ CODE_DNSADDR
11
+ ]
12
+
4
13
  /**
5
14
  * Check if a given multiaddr is a network address
6
15
  */
7
16
  export function isNetworkAddress (ma: Multiaddr): boolean {
8
17
  try {
9
- getNetConfig(ma)
18
+ for (const { code } of ma.getComponents()) {
19
+ if (code === CODE_IP6ZONE) {
20
+ continue
21
+ }
10
22
 
11
- return true
23
+ return NETWORK_CODECS.includes(code)
24
+ }
12
25
  } catch {
13
- return false
26
+
14
27
  }
28
+
29
+ return false
15
30
  }
@@ -1,5 +1,5 @@
1
1
  import { isPrivateIp } from '../private-ip.js'
2
- import { getNetConfig } from './get-net-config.ts'
2
+ import { isIpBased } from './is-ip-based.js'
3
3
  import type { Multiaddr } from '@multiformats/multiaddr'
4
4
 
5
5
  /**
@@ -7,16 +7,21 @@ import type { Multiaddr } from '@multiformats/multiaddr'
7
7
  */
8
8
  export function isPrivate (ma: Multiaddr): boolean {
9
9
  try {
10
- const config = getNetConfig(ma)
10
+ if (!isIpBased(ma)) {
11
+ // not an IP based multiaddr, cannot be private
12
+ return false
13
+ }
14
+
15
+ const [[, value]] = ma.stringTuples()
11
16
 
12
- switch (config.type) {
13
- case 'ip4':
14
- case 'ip6':
15
- return isPrivateIp(config.host) ?? false
16
- default:
17
- return config.host === 'localhost'
17
+ if (value == null) {
18
+ return false
18
19
  }
20
+
21
+ return isPrivateIp(value) ?? false
19
22
  } catch {
20
- return false
23
+
21
24
  }
25
+
26
+ return true
22
27
  }
@@ -1,7 +1,7 @@
1
1
  import { AbortError } from '@libp2p/interface'
2
2
  import { pushable } from 'it-pushable'
3
3
  import { TypedEventEmitter } from 'main-event'
4
- import { pEvent } from 'p-event'
4
+ import { raceEvent } from 'race-event'
5
5
  import { debounce } from '../debounce.js'
6
6
  import { QueueFullError } from '../errors.js'
7
7
  import { Job } from './job.js'
@@ -131,7 +131,6 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
131
131
  public queue: Array<Job<JobOptions, JobReturnType>>
132
132
  private pending: number
133
133
  private readonly sort?: Comparator<Job<JobOptions, JobReturnType>>
134
- private paused: boolean
135
134
 
136
135
  constructor (init: QueueInit<JobReturnType, JobOptions> = {}) {
137
136
  super()
@@ -139,7 +138,6 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
139
138
  this.concurrency = init.concurrency ?? Number.POSITIVE_INFINITY
140
139
  this.maxSize = init.maxSize ?? Number.POSITIVE_INFINITY
141
140
  this.pending = 0
142
- this.paused = false
143
141
 
144
142
  if (init.metricName != null) {
145
143
  init.metrics?.registerMetricGroup(init.metricName, {
@@ -176,24 +174,7 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
176
174
  this.safeDispatchEvent('idle')
177
175
  }
178
176
 
179
- pause (): void {
180
- this.paused = true
181
- }
182
-
183
- resume (): void {
184
- if (!this.paused) {
185
- return
186
- }
187
-
188
- this.paused = false
189
- this.tryToStartAnother()
190
- }
191
-
192
177
  private tryToStartAnother (): boolean {
193
- if (this.paused) {
194
- return false
195
- }
196
-
197
178
  if (this.size === 0) {
198
179
  this.emitEmpty()
199
180
 
@@ -319,7 +300,7 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
319
300
  return
320
301
  }
321
302
 
322
- await pEvent(this, 'empty', options)
303
+ await raceEvent(this, 'empty', options?.signal)
323
304
  }
324
305
 
325
306
  /**
@@ -339,8 +320,7 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
339
320
  return
340
321
  }
341
322
 
342
- await pEvent(this, 'next', {
343
- ...options,
323
+ await raceEvent(this, 'next', options?.signal, {
344
324
  filter: () => this.size < limit
345
325
  })
346
326
  }
@@ -359,7 +339,7 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
359
339
  return
360
340
  }
361
341
 
362
- await pEvent(this, 'idle', options)
342
+ await raceEvent(this, 'idle', options?.signal)
363
343
  }
364
344
 
365
345
  /**
@@ -1,3 +1,4 @@
1
+ import delay from 'delay'
1
2
  import { RateLimitError } from './errors.js'
2
3
 
3
4
  export interface RateLimiterInit {
@@ -22,6 +23,20 @@ export interface RateLimiterInit {
22
23
  */
23
24
  blockDuration?: number
24
25
 
26
+ /**
27
+ * Execute allowed actions evenly over duration
28
+ *
29
+ * @default false
30
+ */
31
+ execEvenly?: boolean
32
+
33
+ /**
34
+ * ms, works with execEvenly=true option
35
+ *
36
+ * @default duration * 1000 / points
37
+ */
38
+ execEvenlyMinDelayMs?: number
39
+
25
40
  /**
26
41
  * @default "rlflx"
27
42
  */
@@ -50,17 +65,21 @@ export class RateLimiter {
50
65
  protected points: number
51
66
  protected duration: number
52
67
  protected blockDuration: number
68
+ protected execEvenly: boolean
69
+ protected execEvenlyMinDelayMs: number
53
70
  protected keyPrefix: string
54
71
 
55
72
  constructor (opts: RateLimiterInit = {}) {
56
73
  this.points = opts.points ?? 4
57
74
  this.duration = opts.duration ?? 1
58
75
  this.blockDuration = opts.blockDuration ?? 0
76
+ this.execEvenly = opts.execEvenly ?? false
77
+ this.execEvenlyMinDelayMs = opts.execEvenlyMinDelayMs ?? (this.duration * 1000 / this.points)
59
78
  this.keyPrefix = opts.keyPrefix ?? 'rlflx'
60
79
  this.memoryStorage = new MemoryStorage()
61
80
  }
62
81
 
63
- consume (key: string, pointsToConsume: number = 1, options: GetKeySecDurationOptions = {}): RateLimiterResult {
82
+ async consume (key: string, pointsToConsume: number = 1, options: GetKeySecDurationOptions = {}): Promise<RateLimiterResult> {
64
83
  const rlKey = this.getKey(key)
65
84
  const secDuration = this._getKeySecDuration(options)
66
85
  let res = this.memoryStorage.incrby(rlKey, pointsToConsume, secDuration)
@@ -74,6 +93,14 @@ export class RateLimiter {
74
93
  }
75
94
 
76
95
  throw new RateLimitError('Rate limit exceeded', res)
96
+ } else if (this.execEvenly && res.msBeforeNext > 0 && !res.isFirstInDuration) {
97
+ // Execute evenly
98
+ let delayMs = Math.ceil(res.msBeforeNext / (res.remainingPoints + 2))
99
+ if (delayMs < this.execEvenlyMinDelayMs) {
100
+ delayMs = res.consumedPoints * this.execEvenlyMinDelayMs
101
+ }
102
+
103
+ await delay(delayMs)
77
104
  }
78
105
 
79
106
  return res
@@ -214,8 +241,8 @@ export class MemoryStorage {
214
241
  this.storage.delete(key)
215
242
  }, durationMs)
216
243
 
217
- if ((record.timeoutId as any).unref != null) {
218
- (record.timeoutId as any).unref()
244
+ if (record.timeoutId.unref != null) {
245
+ record.timeoutId.unref()
219
246
  }
220
247
  }
221
248
 
@@ -0,0 +1,106 @@
1
+ import forEach from 'it-foreach'
2
+ import { pipe } from 'it-pipe'
3
+ import type { Logger, MultiaddrConnection, Stream } from '@libp2p/interface'
4
+ import type { Multiaddr } from '@multiformats/multiaddr'
5
+ import type { Uint8ArrayList } from 'uint8arraylist'
6
+
7
+ export interface StreamProperties {
8
+ stream: Stream
9
+ remoteAddr: Multiaddr
10
+ localAddr: Multiaddr
11
+ log: Logger
12
+
13
+ /**
14
+ * A callback invoked when data is read from the stream
15
+ */
16
+ onDataRead?(buf: Uint8ArrayList | Uint8Array): void
17
+
18
+ /**
19
+ * A callback invoked when data is written to the stream
20
+ */
21
+ onDataWrite?(buf: Uint8ArrayList | Uint8Array): void
22
+ }
23
+
24
+ /**
25
+ * Convert a duplex iterable into a MultiaddrConnection.
26
+ * https://github.com/libp2p/interface-transport#multiaddrconnection
27
+ */
28
+ export function streamToMaConnection (props: StreamProperties): MultiaddrConnection {
29
+ const { stream, remoteAddr, log, onDataRead, onDataWrite } = props
30
+
31
+ let closedRead = false
32
+ let closedWrite = false
33
+
34
+ // piggyback on `stream.close` invocations to close multiaddr connection
35
+ const streamClose = stream.close.bind(stream)
36
+ stream.close = async (options): Promise<void> => {
37
+ await streamClose(options)
38
+ close(true)
39
+ }
40
+
41
+ // piggyback on `stream.abort` invocations to close multiaddr connection
42
+ const streamAbort = stream.abort.bind(stream)
43
+ stream.abort = (err): void => {
44
+ streamAbort(err)
45
+ close(true)
46
+ }
47
+
48
+ // piggyback on `stream.sink` invocations to close multiaddr connection
49
+ const streamSink = stream.sink.bind(stream)
50
+ stream.sink = async (source): Promise<void> => {
51
+ try {
52
+ await streamSink(
53
+ pipe(
54
+ source,
55
+ (source) => forEach(source, buf => onDataWrite?.(buf))
56
+ )
57
+ )
58
+ } catch (err: any) {
59
+ maConn.log.error('errored - %e', err)
60
+
61
+ // If aborted we can safely ignore
62
+ if (err.type !== 'aborted') {
63
+ // If the source errored the socket will already have been destroyed by
64
+ // toIterable.duplex(). If the socket errored it will already be
65
+ // destroyed. There's nothing to do here except log the error & return.
66
+ maConn.log.error('%s error in sink - %e', remoteAddr, err)
67
+ }
68
+ } finally {
69
+ closedWrite = true
70
+ close()
71
+ }
72
+ }
73
+
74
+ const maConn: MultiaddrConnection = {
75
+ log: log.newScope('stream-to-maconn'),
76
+ sink: stream.sink,
77
+ source: (async function * (): AsyncGenerator<Uint8ArrayList> {
78
+ try {
79
+ for await (const buf of stream.source) {
80
+ onDataRead?.(buf)
81
+ yield buf
82
+ }
83
+ } finally {
84
+ closedRead = true
85
+ close()
86
+ }
87
+ }()),
88
+ remoteAddr,
89
+ timeline: { open: Date.now(), close: undefined },
90
+ close: stream.close,
91
+ abort: stream.abort
92
+ }
93
+
94
+ function close (force?: boolean): void {
95
+ if (force === true) {
96
+ closedRead = true
97
+ closedWrite = true
98
+ }
99
+
100
+ if (closedRead && closedWrite && maConn.timeline.close == null) {
101
+ maConn.timeline.close = Date.now()
102
+ }
103
+ }
104
+
105
+ return maConn
106
+ }