libp2p 0.42.2 → 0.43.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 (295) hide show
  1. package/README.md +4 -4
  2. package/dist/index.min.js +29 -29
  3. package/dist/src/address-manager/index.d.ts +1 -10
  4. package/dist/src/address-manager/index.d.ts.map +1 -1
  5. package/dist/src/address-manager/index.js +46 -29
  6. package/dist/src/address-manager/index.js.map +1 -1
  7. package/dist/src/autonat/constants.d.ts +4 -0
  8. package/dist/src/autonat/constants.d.ts.map +1 -0
  9. package/dist/src/autonat/constants.js +4 -0
  10. package/dist/src/autonat/constants.js.map +1 -0
  11. package/dist/src/autonat/index.d.ts +64 -0
  12. package/dist/src/autonat/index.d.ts.map +1 -0
  13. package/dist/src/autonat/index.js +417 -0
  14. package/dist/src/autonat/index.js.map +1 -0
  15. package/dist/src/autonat/pb/index.d.ts +57 -0
  16. package/dist/src/autonat/pb/index.d.ts.map +1 -0
  17. package/dist/src/autonat/pb/index.js +250 -0
  18. package/dist/src/autonat/pb/index.js.map +1 -0
  19. package/dist/src/circuit/constants.d.ts +31 -6
  20. package/dist/src/circuit/constants.d.ts.map +1 -1
  21. package/dist/src/circuit/constants.js +37 -7
  22. package/dist/src/circuit/constants.js.map +1 -1
  23. package/dist/src/circuit/index.d.ts +16 -61
  24. package/dist/src/circuit/index.d.ts.map +1 -1
  25. package/dist/src/circuit/index.js +2 -68
  26. package/dist/src/circuit/index.js.map +1 -1
  27. package/dist/src/circuit/pb/index.d.ts +83 -43
  28. package/dist/src/circuit/pb/index.d.ts.map +1 -1
  29. package/dist/src/circuit/pb/index.js +363 -127
  30. package/dist/src/circuit/pb/index.js.map +1 -1
  31. package/dist/src/circuit/server/advert-service.d.ts +43 -0
  32. package/dist/src/circuit/server/advert-service.d.ts.map +1 -0
  33. package/dist/src/circuit/server/advert-service.js +69 -0
  34. package/dist/src/circuit/server/advert-service.js.map +1 -0
  35. package/dist/src/circuit/server/index.d.ts +60 -0
  36. package/dist/src/circuit/server/index.d.ts.map +1 -0
  37. package/dist/src/circuit/server/index.js +287 -0
  38. package/dist/src/circuit/server/index.js.map +1 -0
  39. package/dist/src/circuit/server/reservation-store.d.ts +49 -0
  40. package/dist/src/circuit/server/reservation-store.d.ts.map +1 -0
  41. package/dist/src/circuit/server/reservation-store.js +57 -0
  42. package/dist/src/circuit/server/reservation-store.js.map +1 -0
  43. package/dist/src/circuit/server/reservation-voucher.d.ts +18 -0
  44. package/dist/src/circuit/server/reservation-voucher.d.ts.map +1 -0
  45. package/dist/src/circuit/server/reservation-voucher.js +33 -0
  46. package/dist/src/circuit/server/reservation-voucher.js.map +1 -0
  47. package/dist/src/circuit/transport/discovery.d.ts +45 -0
  48. package/dist/src/circuit/transport/discovery.d.ts.map +1 -0
  49. package/dist/src/circuit/transport/discovery.js +82 -0
  50. package/dist/src/circuit/transport/discovery.js.map +1 -0
  51. package/dist/src/circuit/transport/index.d.ts +33 -0
  52. package/dist/src/circuit/transport/index.d.ts.map +1 -0
  53. package/dist/src/circuit/transport/index.js +225 -0
  54. package/dist/src/circuit/transport/index.js.map +1 -0
  55. package/dist/src/circuit/transport/listener.d.ts +9 -0
  56. package/dist/src/circuit/transport/listener.d.ts.map +1 -0
  57. package/dist/src/circuit/transport/listener.js +76 -0
  58. package/dist/src/circuit/transport/listener.js.map +1 -0
  59. package/dist/src/circuit/transport/reservation-store.d.ts +60 -0
  60. package/dist/src/circuit/transport/reservation-store.d.ts.map +1 -0
  61. package/dist/src/circuit/transport/reservation-store.js +165 -0
  62. package/dist/src/circuit/transport/reservation-store.js.map +1 -0
  63. package/dist/src/circuit/utils.d.ts +7 -0
  64. package/dist/src/circuit/utils.d.ts.map +1 -1
  65. package/dist/src/circuit/utils.js +87 -0
  66. package/dist/src/circuit/utils.js.map +1 -1
  67. package/dist/src/components.d.ts +2 -1
  68. package/dist/src/components.d.ts.map +1 -1
  69. package/dist/src/components.js +13 -13
  70. package/dist/src/components.js.map +1 -1
  71. package/dist/src/config.d.ts.map +1 -1
  72. package/dist/src/config.js +21 -25
  73. package/dist/src/config.js.map +1 -1
  74. package/dist/src/connection/index.d.ts +2 -2
  75. package/dist/src/connection/index.d.ts.map +1 -1
  76. package/dist/src/connection/index.js +4 -4
  77. package/dist/src/connection/index.js.map +1 -1
  78. package/dist/src/connection-manager/auto-dialler.d.ts +0 -4
  79. package/dist/src/connection-manager/auto-dialler.d.ts.map +1 -1
  80. package/dist/src/connection-manager/auto-dialler.js +18 -18
  81. package/dist/src/connection-manager/auto-dialler.js.map +1 -1
  82. package/dist/src/connection-manager/dialer/dial-request.d.ts.map +1 -1
  83. package/dist/src/connection-manager/dialer/dial-request.js +13 -6
  84. package/dist/src/connection-manager/dialer/dial-request.js.map +1 -1
  85. package/dist/src/connection-manager/dialer/index.d.ts +10 -1
  86. package/dist/src/connection-manager/dialer/index.d.ts.map +1 -1
  87. package/dist/src/connection-manager/dialer/index.js +24 -9
  88. package/dist/src/connection-manager/dialer/index.js.map +1 -1
  89. package/dist/src/connection-manager/index.d.ts +1 -4
  90. package/dist/src/connection-manager/index.d.ts.map +1 -1
  91. package/dist/src/connection-manager/index.js +8 -5
  92. package/dist/src/connection-manager/index.js.map +1 -1
  93. package/dist/src/connection-manager/latency-monitor.d.ts.map +1 -1
  94. package/dist/src/connection-manager/latency-monitor.js +1 -1
  95. package/dist/src/connection-manager/latency-monitor.js.map +1 -1
  96. package/dist/src/connection-manager/visibility-change-emitter.d.ts.map +1 -1
  97. package/dist/src/content-routing/index.d.ts +6 -4
  98. package/dist/src/content-routing/index.d.ts.map +1 -1
  99. package/dist/src/content-routing/index.js +9 -9
  100. package/dist/src/content-routing/index.js.map +1 -1
  101. package/dist/src/content-routing/utils.d.ts +3 -3
  102. package/dist/src/content-routing/utils.d.ts.map +1 -1
  103. package/dist/src/content-routing/utils.js +2 -2
  104. package/dist/src/content-routing/utils.js.map +1 -1
  105. package/dist/src/dht/dht-content-routing.d.ts +2 -1
  106. package/dist/src/dht/dht-content-routing.d.ts.map +1 -1
  107. package/dist/src/dht/dht-content-routing.js +2 -2
  108. package/dist/src/dht/dht-content-routing.js.map +1 -1
  109. package/dist/src/dht/dht-peer-routing.d.ts +3 -2
  110. package/dist/src/dht/dht-peer-routing.d.ts.map +1 -1
  111. package/dist/src/dht/dht-peer-routing.js +2 -2
  112. package/dist/src/dht/dht-peer-routing.js.map +1 -1
  113. package/dist/src/dht/dummy-dht.d.ts +1 -1
  114. package/dist/src/dht/dummy-dht.d.ts.map +1 -1
  115. package/dist/src/dht/dummy-dht.js +12 -12
  116. package/dist/src/dht/dummy-dht.js.map +1 -1
  117. package/dist/src/errors.d.ts +2 -1
  118. package/dist/src/errors.d.ts.map +1 -1
  119. package/dist/src/errors.js +1 -0
  120. package/dist/src/errors.js.map +1 -1
  121. package/dist/src/fetch/index.d.ts.map +1 -1
  122. package/dist/src/fetch/index.js +6 -6
  123. package/dist/src/fetch/index.js.map +1 -1
  124. package/dist/src/fetch/pb/proto.d.ts +3 -3
  125. package/dist/src/fetch/pb/proto.d.ts.map +1 -1
  126. package/dist/src/fetch/pb/proto.js +4 -3
  127. package/dist/src/fetch/pb/proto.js.map +1 -1
  128. package/dist/src/get-peer.js +2 -2
  129. package/dist/src/get-peer.js.map +1 -1
  130. package/dist/src/identify/index.d.ts +3 -1
  131. package/dist/src/identify/index.d.ts.map +1 -1
  132. package/dist/src/identify/index.js +19 -14
  133. package/dist/src/identify/index.js.map +1 -1
  134. package/dist/src/identify/pb/message.d.ts +2 -2
  135. package/dist/src/identify/pb/message.d.ts.map +1 -1
  136. package/dist/src/identify/pb/message.js +1 -0
  137. package/dist/src/identify/pb/message.js.map +1 -1
  138. package/dist/src/index.d.ts +14 -8
  139. package/dist/src/index.d.ts.map +1 -1
  140. package/dist/src/index.js.map +1 -1
  141. package/dist/src/insecure/index.d.ts.map +1 -1
  142. package/dist/src/insecure/index.js.map +1 -1
  143. package/dist/src/insecure/pb/proto.d.ts +3 -3
  144. package/dist/src/insecure/pb/proto.d.ts.map +1 -1
  145. package/dist/src/insecure/pb/proto.js +4 -5
  146. package/dist/src/insecure/pb/proto.js.map +1 -1
  147. package/dist/src/libp2p.d.ts +7 -3
  148. package/dist/src/libp2p.d.ts.map +1 -1
  149. package/dist/src/libp2p.js +35 -35
  150. package/dist/src/libp2p.js.map +1 -1
  151. package/dist/src/nat-manager.d.ts.map +1 -1
  152. package/dist/src/nat-manager.js +5 -3
  153. package/dist/src/nat-manager.js.map +1 -1
  154. package/dist/src/peer-record-updater.d.ts.map +1 -1
  155. package/dist/src/peer-routing.d.ts.map +1 -1
  156. package/dist/src/peer-routing.js +5 -5
  157. package/dist/src/peer-routing.js.map +1 -1
  158. package/dist/src/ping/index.d.ts.map +1 -1
  159. package/dist/src/ping/index.js +2 -2
  160. package/dist/src/ping/index.js.map +1 -1
  161. package/dist/src/pnet/crypto.d.ts +1 -1
  162. package/dist/src/pnet/crypto.d.ts.map +1 -1
  163. package/dist/src/pnet/crypto.js +1 -1
  164. package/dist/src/pnet/crypto.js.map +1 -1
  165. package/dist/src/pnet/index.js +3 -3
  166. package/dist/src/pnet/index.js.map +1 -1
  167. package/dist/src/pnet/key-generator.d.ts.map +1 -1
  168. package/dist/src/pubsub/dummy-pubsub.js +9 -9
  169. package/dist/src/pubsub/dummy-pubsub.js.map +1 -1
  170. package/dist/src/registrar.d.ts.map +1 -1
  171. package/dist/src/registrar.js +4 -4
  172. package/dist/src/registrar.js.map +1 -1
  173. package/dist/src/transport-manager.d.ts.map +1 -1
  174. package/dist/src/transport-manager.js +8 -9
  175. package/dist/src/transport-manager.js.map +1 -1
  176. package/dist/src/upgrader.d.ts +2 -1
  177. package/dist/src/upgrader.d.ts.map +1 -1
  178. package/dist/src/upgrader.js +38 -33
  179. package/dist/src/upgrader.js.map +1 -1
  180. package/dist/typedoc-urls.json +19 -6
  181. package/package.json +36 -33
  182. package/src/address-manager/index.ts +62 -35
  183. package/src/autonat/constants.ts +4 -0
  184. package/src/autonat/index.ts +567 -0
  185. package/src/autonat/pb/index.proto +35 -0
  186. package/src/autonat/pb/index.ts +320 -0
  187. package/src/circuit/constants.ts +48 -7
  188. package/src/circuit/index.ts +17 -129
  189. package/src/circuit/pb/index.proto +57 -32
  190. package/src/circuit/pb/index.ts +448 -138
  191. package/src/circuit/server/advert-service.ts +108 -0
  192. package/src/circuit/server/index.ts +421 -0
  193. package/src/circuit/server/reservation-store.ts +111 -0
  194. package/src/circuit/server/reservation-voucher.ts +51 -0
  195. package/src/circuit/transport/discovery.ts +127 -0
  196. package/src/circuit/transport/index.ts +325 -0
  197. package/src/circuit/transport/listener.ts +99 -0
  198. package/src/circuit/transport/reservation-store.ts +249 -0
  199. package/src/circuit/utils.ts +108 -0
  200. package/src/components.ts +22 -21
  201. package/src/config.ts +21 -25
  202. package/src/connection/index.ts +10 -10
  203. package/src/connection-manager/auto-dialler.ts +36 -40
  204. package/src/connection-manager/dialer/dial-request.ts +13 -6
  205. package/src/connection-manager/dialer/index.ts +34 -15
  206. package/src/connection-manager/index.ts +22 -23
  207. package/src/connection-manager/latency-monitor.ts +9 -9
  208. package/src/connection-manager/visibility-change-emitter.ts +4 -4
  209. package/src/content-routing/index.ts +18 -16
  210. package/src/content-routing/utils.ts +5 -5
  211. package/src/dht/dht-content-routing.ts +5 -4
  212. package/src/dht/dht-peer-routing.ts +5 -4
  213. package/src/dht/dummy-dht.ts +13 -13
  214. package/src/errors.ts +2 -1
  215. package/src/fetch/index.ts +13 -13
  216. package/src/fetch/pb/proto.ts +8 -7
  217. package/src/get-peer.ts +3 -3
  218. package/src/identify/index.ts +29 -24
  219. package/src/identify/pb/message.ts +3 -2
  220. package/src/index.ts +15 -8
  221. package/src/insecure/index.ts +2 -1
  222. package/src/insecure/pb/proto.ts +8 -9
  223. package/src/libp2p.ts +52 -46
  224. package/src/nat-manager.ts +11 -9
  225. package/src/peer-record-updater.ts +4 -4
  226. package/src/peer-routing.ts +9 -9
  227. package/src/ping/index.ts +6 -6
  228. package/src/pnet/crypto.ts +3 -3
  229. package/src/pnet/index.ts +3 -3
  230. package/src/pnet/key-generator.ts +1 -1
  231. package/src/pubsub/dummy-pubsub.ts +9 -9
  232. package/src/registrar.ts +12 -12
  233. package/src/transport-manager.ts +17 -18
  234. package/src/upgrader.ts +43 -42
  235. package/src/version.ts +1 -1
  236. package/dist/src/circuit/auto-relay.d.ts +0 -46
  237. package/dist/src/circuit/auto-relay.d.ts.map +0 -1
  238. package/dist/src/circuit/auto-relay.js +0 -220
  239. package/dist/src/circuit/auto-relay.js.map +0 -1
  240. package/dist/src/circuit/circuit/hop.d.ts +0 -42
  241. package/dist/src/circuit/circuit/hop.d.ts.map +0 -1
  242. package/dist/src/circuit/circuit/hop.js +0 -142
  243. package/dist/src/circuit/circuit/hop.js.map +0 -1
  244. package/dist/src/circuit/circuit/stop.d.ts +0 -24
  245. package/dist/src/circuit/circuit/stop.d.ts.map +0 -1
  246. package/dist/src/circuit/circuit/stop.js +0 -51
  247. package/dist/src/circuit/circuit/stop.js.map +0 -1
  248. package/dist/src/circuit/circuit/stream-handler.d.ts +0 -40
  249. package/dist/src/circuit/circuit/stream-handler.d.ts.map +0 -1
  250. package/dist/src/circuit/circuit/stream-handler.js +0 -59
  251. package/dist/src/circuit/circuit/stream-handler.js.map +0 -1
  252. package/dist/src/circuit/circuit/utils.d.ts +0 -7
  253. package/dist/src/circuit/circuit/utils.d.ts.map +0 -1
  254. package/dist/src/circuit/circuit/utils.js +0 -43
  255. package/dist/src/circuit/circuit/utils.js.map +0 -1
  256. package/dist/src/circuit/listener.d.ts +0 -9
  257. package/dist/src/circuit/listener.d.ts.map +0 -1
  258. package/dist/src/circuit/listener.js +0 -62
  259. package/dist/src/circuit/listener.js.map +0 -1
  260. package/dist/src/circuit/multicodec.d.ts +0 -2
  261. package/dist/src/circuit/multicodec.d.ts.map +0 -1
  262. package/dist/src/circuit/multicodec.js +0 -2
  263. package/dist/src/circuit/multicodec.js.map +0 -1
  264. package/dist/src/circuit/transport.d.ts +0 -51
  265. package/dist/src/circuit/transport.d.ts.map +0 -1
  266. package/dist/src/circuit/transport.js +0 -223
  267. package/dist/src/circuit/transport.js.map +0 -1
  268. package/dist/src/keychain/cms.d.ts +0 -33
  269. package/dist/src/keychain/cms.d.ts.map +0 -1
  270. package/dist/src/keychain/cms.js +0 -129
  271. package/dist/src/keychain/cms.js.map +0 -1
  272. package/dist/src/keychain/index.d.ts +0 -151
  273. package/dist/src/keychain/index.d.ts.map +0 -1
  274. package/dist/src/keychain/index.js +0 -519
  275. package/dist/src/keychain/index.js.map +0 -1
  276. package/dist/src/keychain/util.d.ts +0 -21
  277. package/dist/src/keychain/util.d.ts.map +0 -1
  278. package/dist/src/keychain/util.js +0 -79
  279. package/dist/src/keychain/util.js.map +0 -1
  280. package/src/circuit/IMPLEMENTATION_NOTES.md +0 -128
  281. package/src/circuit/README.md +0 -111
  282. package/src/circuit/auto-relay.ts +0 -292
  283. package/src/circuit/circuit/hop.ts +0 -220
  284. package/src/circuit/circuit/stop.ts +0 -83
  285. package/src/circuit/circuit/stream-handler.ts +0 -87
  286. package/src/circuit/circuit/utils.ts +0 -44
  287. package/src/circuit/listener.ts +0 -83
  288. package/src/circuit/multicodec.ts +0 -2
  289. package/src/circuit/transport.ts +0 -278
  290. package/src/keychain/README.md +0 -55
  291. package/src/keychain/cms.ts +0 -150
  292. package/src/keychain/doc/private-key.png +0 -0
  293. package/src/keychain/doc/private-key.xml +0 -1
  294. package/src/keychain/index.ts +0 -629
  295. package/src/keychain/util.ts +0 -82
@@ -0,0 +1,249 @@
1
+ import type { PeerId } from '@libp2p/interface-peer-id'
2
+ import { PeerMap } from '@libp2p/peer-collections'
3
+ import PQueue from 'p-queue'
4
+ import { DEFAULT_RESERVATION_CONCURRENCY, RELAY_TAG, RELAY_V2_HOP_CODEC } from '../constants.js'
5
+ import { logger } from '@libp2p/logger'
6
+ import { pbStream } from 'it-pb-stream'
7
+ import type { ConnectionManager } from '@libp2p/interface-connection-manager'
8
+ import type { Connection } from '@libp2p/interface-connection'
9
+ import type { Reservation } from '../pb/index.js'
10
+ import { HopMessage, Status } from '../pb/index.js'
11
+ import { getExpiration } from '../utils.js'
12
+ import type { TransportManager } from '@libp2p/interface-transport'
13
+ import type { Startable } from '@libp2p/interfaces/dist/src/startable.js'
14
+ import { CustomEvent, EventEmitter } from '@libp2p/interfaces/events'
15
+ import type { PeerStore } from '@libp2p/interface-peer-store'
16
+ import { multiaddr } from '@multiformats/multiaddr'
17
+
18
+ const log = logger('libp2p:circuit-relay:transport:reservation-store')
19
+
20
+ // allow refreshing a relay reservation if it will expire in the next 10 minutes
21
+ const REFRESH_WINDOW = (60 * 1000) * 10
22
+
23
+ // try to refresh relay reservations 5 minutes before expiry
24
+ const REFRESH_TIMEOUT = (60 * 1000) * 5
25
+
26
+ export interface RelayStoreComponents {
27
+ peerId: PeerId
28
+ connectionManager: ConnectionManager
29
+ transportManager: TransportManager
30
+ peerStore: PeerStore
31
+ }
32
+
33
+ export interface RelayStoreInit {
34
+ /**
35
+ * Multiple relays may be discovered simultaneously - to prevent listening
36
+ * on too many relays, this value controls how many to attempt to reserve a
37
+ * slot on at once. If set to more than one, we may end up listening on
38
+ * more relays than the `maxReservations` value, but on networks with poor
39
+ * connectivity the user may wish to attempt to reserve on multiple relays
40
+ * simultaneously. (default: 1)
41
+ */
42
+ reservationConcurrency?: number
43
+
44
+ /**
45
+ * How many discovered relays to allow in the reservation store
46
+ */
47
+ discoverRelays?: number
48
+ }
49
+
50
+ export type RelayType = 'discovered' | 'configured'
51
+
52
+ interface RelayEntry {
53
+ timeout: ReturnType<typeof setTimeout>
54
+ type: RelayType
55
+ reservation: Reservation
56
+ }
57
+
58
+ export interface ReservationStoreEvents {
59
+ 'relay:not-enough-relays': CustomEvent
60
+ 'relay:removed': CustomEvent<PeerId>
61
+ }
62
+
63
+ export class ReservationStore extends EventEmitter<ReservationStoreEvents> implements Startable {
64
+ private readonly peerId: PeerId
65
+ private readonly connectionManager: ConnectionManager
66
+ private readonly transportManager: TransportManager
67
+ private readonly peerStore: PeerStore
68
+ private readonly reserveQueue: PQueue
69
+ private readonly reservations: PeerMap<RelayEntry>
70
+ private readonly maxDiscoveredRelays: number
71
+ private started: boolean
72
+
73
+ constructor (components: RelayStoreComponents, init?: RelayStoreInit) {
74
+ super()
75
+
76
+ this.peerId = components.peerId
77
+ this.connectionManager = components.connectionManager
78
+ this.transportManager = components.transportManager
79
+ this.peerStore = components.peerStore
80
+ this.reservations = new PeerMap()
81
+ this.maxDiscoveredRelays = init?.discoverRelays ?? 0
82
+ this.started = false
83
+
84
+ // ensure we don't listen on multiple relays simultaneously
85
+ this.reserveQueue = new PQueue({
86
+ concurrency: init?.reservationConcurrency ?? DEFAULT_RESERVATION_CONCURRENCY
87
+ })
88
+
89
+ // When a peer disconnects, if we had a reservation on that peer
90
+ // remove the reservation and multiaddr and maybe trigger search
91
+ // for new relays
92
+ this.connectionManager.addEventListener('peer:disconnect', (evt) => {
93
+ this.removeRelay(evt.detail.remotePeer)
94
+ })
95
+ }
96
+
97
+ isStarted (): boolean {
98
+ return this.started
99
+ }
100
+
101
+ async start (): Promise<void> {
102
+ this.started = true
103
+ }
104
+
105
+ async stop (): Promise<void> {
106
+ this.reservations.forEach(({ timeout }) => {
107
+ clearTimeout(timeout)
108
+ })
109
+ this.reservations.clear()
110
+
111
+ this.started = true
112
+ }
113
+
114
+ /**
115
+ * If the number of current relays is beneath the configured `maxReservations`
116
+ * value, and the passed peer id is not our own, and we have a non-relayed connection
117
+ * to the remote, and the remote peer speaks the hop protocol, try to reserve a slot
118
+ * on the remote peer
119
+ */
120
+ async addRelay (peerId: PeerId, type: RelayType): Promise<void> {
121
+ log('add relay', this.reserveQueue.size)
122
+
123
+ await this.reserveQueue.add(async () => {
124
+ try {
125
+ if (this.peerId.equals(peerId)) {
126
+ log('not trying to use self as relay')
127
+ return
128
+ }
129
+
130
+ // allow refresh of an existing reservation if it is about to expire
131
+ const existingReservation = this.reservations.get(peerId)
132
+
133
+ if (existingReservation != null) {
134
+ if (getExpiration(existingReservation.reservation.expire) > REFRESH_WINDOW) {
135
+ log('already have reservation on relay peer %p and it expires in more than 10 minutes', peerId)
136
+ return
137
+ }
138
+
139
+ clearTimeout(existingReservation.timeout)
140
+ this.reservations.delete(peerId)
141
+ }
142
+
143
+ if (type === 'discovered' && [...this.reservations.values()].reduce((acc, curr) => {
144
+ if (curr.type === 'discovered') {
145
+ acc++
146
+ }
147
+
148
+ return acc
149
+ }, 0) >= this.maxDiscoveredRelays) {
150
+ log('already have enough discovered relays')
151
+ return
152
+ }
153
+
154
+ const connection = await this.connectionManager.openConnection(peerId)
155
+
156
+ if (connection.remoteAddr.protoNames().includes('p2p-circuit')) {
157
+ log('not creating reservation over relayed connection')
158
+ return
159
+ }
160
+
161
+ const reservation = await this.#createReservation(connection)
162
+
163
+ log('created reservation on relay peer %p', peerId)
164
+
165
+ const expiration = getExpiration(reservation.expire)
166
+
167
+ const timeout = setTimeout(() => {
168
+ this.addRelay(peerId, type).catch(err => {
169
+ log.error('could not refresh reservation to relay %p', peerId, err)
170
+ })
171
+ }, Math.max(expiration - REFRESH_TIMEOUT, 0))
172
+
173
+ this.reservations.set(peerId, {
174
+ timeout,
175
+ reservation,
176
+ type
177
+ })
178
+
179
+ // ensure we don't close the connection to the relay
180
+ await this.peerStore.tagPeer(peerId, RELAY_TAG, {
181
+ value: 1,
182
+ ttl: expiration
183
+ })
184
+
185
+ await this.transportManager.listen(
186
+ reservation.addrs.map(ma => {
187
+ return multiaddr(ma).encapsulate('/p2p-circuit')
188
+ })
189
+ )
190
+ } catch (err) {
191
+ log.error('could not reserve slot on %p', peerId, err)
192
+ }
193
+ })
194
+ }
195
+
196
+ hasReservation (peerId: PeerId): boolean {
197
+ return this.reservations.has(peerId)
198
+ }
199
+
200
+ async #createReservation (connection: Connection): Promise<Reservation> {
201
+ log('requesting reservation from %s', connection.remotePeer)
202
+ const stream = await connection.newStream(RELAY_V2_HOP_CODEC)
203
+ const pbstr = pbStream(stream)
204
+ const hopstr = pbstr.pb(HopMessage)
205
+ hopstr.write({ type: HopMessage.Type.RESERVE })
206
+
207
+ let response: HopMessage
208
+
209
+ try {
210
+ response = await hopstr.read()
211
+ } catch (err: any) {
212
+ log.error('error parsing reserve message response from %s because', connection.remotePeer, err.message)
213
+ throw err
214
+ } finally {
215
+ stream.close()
216
+ }
217
+
218
+ if (response.status === Status.OK && (response.reservation != null)) {
219
+ return response.reservation
220
+ }
221
+
222
+ const errMsg = `reservation failed with status ${response.status ?? 'undefined'}`
223
+ log.error(errMsg)
224
+
225
+ throw new Error(errMsg)
226
+ }
227
+
228
+ /**
229
+ * Remove listen relay
230
+ */
231
+ removeRelay (peerId: PeerId): void {
232
+ const existingReservation = this.reservations.get(peerId)
233
+
234
+ if (existingReservation == null) {
235
+ return
236
+ }
237
+
238
+ log('removing relay %p', peerId)
239
+
240
+ clearTimeout(existingReservation.timeout)
241
+ this.reservations.delete(peerId)
242
+
243
+ this.safeDispatchEvent('relay:removed', { detail: peerId })
244
+
245
+ if (this.reservations.size < this.maxDiscoveredRelays) {
246
+ this.dispatchEvent(new CustomEvent('relay:not-enough-relays'))
247
+ }
248
+ }
249
+ }
@@ -1,5 +1,106 @@
1
1
  import { CID } from 'multiformats/cid'
2
2
  import { sha256 } from 'multiformats/hashes/sha2'
3
+ import type { Source } from 'it-stream-types'
4
+ import type { Uint8ArrayList } from 'uint8arraylist'
5
+ import type { Limit } from './pb/index.js'
6
+ import { logger } from '@libp2p/logger'
7
+ import type { Stream } from '@libp2p/interface-connection'
8
+ import { DEFAULT_DATA_LIMIT, DEFAULT_DURATION_LIMIT } from './constants.js'
9
+ import { abortableSource } from 'abortable-iterator'
10
+ import anySignal from 'any-signal'
11
+
12
+ const log = logger('libp2p:circuit-relay:utils')
13
+
14
+ async function * countStreamBytes (source: Source<Uint8Array | Uint8ArrayList>, limit: { remaining: bigint }): AsyncGenerator<Uint8Array | Uint8ArrayList, void, unknown> {
15
+ for await (const buf of source) {
16
+ const len = BigInt(buf.byteLength)
17
+
18
+ if ((limit.remaining - len) < 0) {
19
+ // this is a safe downcast since len is guarantee to be in the range for a number
20
+ const remaining = Number(limit.remaining)
21
+ limit.remaining = 0n
22
+
23
+ try {
24
+ if (remaining !== 0) {
25
+ yield buf.subarray(0, remaining)
26
+ }
27
+ } catch (err: any) {
28
+ log.error(err)
29
+ }
30
+
31
+ throw new Error('data limit exceeded')
32
+ }
33
+
34
+ limit.remaining -= len
35
+ yield buf
36
+ }
37
+ }
38
+
39
+ const doRelay = (src: Stream, dst: Stream, abortSignal: AbortSignal, limit: Required<Limit>): void => {
40
+ function abortStreams (err: Error): void {
41
+ src.abort(err)
42
+ dst.abort(err)
43
+ clearTimeout(timeout)
44
+ }
45
+
46
+ const abortController = new AbortController()
47
+ const signal = anySignal([abortSignal, abortController.signal])
48
+
49
+ const timeout = setTimeout(() => {
50
+ abortController.abort()
51
+ }, limit.duration)
52
+
53
+ let srcDstFinished = false
54
+ let dstSrcFinished = false
55
+
56
+ const dataLimit = {
57
+ remaining: limit.data
58
+ }
59
+
60
+ queueMicrotask(() => {
61
+ void dst.sink(countStreamBytes(abortableSource(src.source, signal, {
62
+ abortMessage: 'duration limit exceeded'
63
+ }), dataLimit))
64
+ .catch(err => {
65
+ log.error('error while relaying streams src -> dst', err)
66
+ abortStreams(err)
67
+ })
68
+ .finally(() => {
69
+ srcDstFinished = true
70
+
71
+ if (dstSrcFinished) {
72
+ clearTimeout(timeout)
73
+ }
74
+ })
75
+ })
76
+
77
+ queueMicrotask(() => {
78
+ void src.sink(countStreamBytes(abortableSource(dst.source, signal, {
79
+ abortMessage: 'duration limit exceeded'
80
+ }), dataLimit))
81
+ .catch(err => {
82
+ log.error('error while relaying streams dst -> src', err)
83
+ abortStreams(err)
84
+ })
85
+ .finally(() => {
86
+ dstSrcFinished = true
87
+
88
+ if (srcDstFinished) {
89
+ clearTimeout(timeout)
90
+ }
91
+ })
92
+ })
93
+ }
94
+
95
+ export function createLimitedRelay (source: Stream, destination: Stream, abortSignal: AbortSignal, limit?: Limit): void {
96
+ const dataLimit = limit?.data ?? BigInt(DEFAULT_DATA_LIMIT)
97
+ const durationLimit = limit?.duration ?? DEFAULT_DURATION_LIMIT
98
+
99
+ doRelay(source, destination, abortSignal, {
100
+ data: dataLimit,
101
+ duration: durationLimit
102
+ })
103
+ }
3
104
 
4
105
  /**
5
106
  * Convert a namespace string into a cid
@@ -10,3 +111,10 @@ export async function namespaceToCid (namespace: string): Promise<CID> {
10
111
 
11
112
  return CID.createV0(hash)
12
113
  }
114
+
115
+ /**
116
+ * returns number of ms between now and expiration time
117
+ */
118
+ export function getExpiration (expireTime: bigint): number {
119
+ return Number(expireTime) - new Date().getTime()
120
+ }
package/src/components.ts CHANGED
@@ -1,5 +1,5 @@
1
- import errCode from 'err-code'
2
- import type { ConnectionGater, ConnectionProtector } from '@libp2p/interface-connection'
1
+ import { CodeError } from '@libp2p/interfaces/errors'
2
+ import type { ConnectionProtector } from '@libp2p/interface-connection'
3
3
  import type { ContentRouting } from '@libp2p/interface-content-routing'
4
4
  import type { AddressManager } from '@libp2p/interface-address-manager'
5
5
  import { isStartable, Startable } from '@libp2p/interfaces/startable'
@@ -13,6 +13,7 @@ import type { Datastore } from 'interface-datastore'
13
13
  import type { PubSub } from '@libp2p/interface-pubsub'
14
14
  import type { DualDHT } from '@libp2p/interface-dht'
15
15
  import type { ConnectionManager, Dialer } from '@libp2p/interface-connection-manager'
16
+ import type { ConnectionGater } from '@libp2p/interface-connection-gater'
16
17
 
17
18
  export interface Components {
18
19
  peerId: PeerId
@@ -90,11 +91,11 @@ export class DefaultComponents implements Components, Startable {
90
91
  this._dialer = init.dialer
91
92
  }
92
93
 
93
- isStarted () {
94
+ isStarted (): boolean {
94
95
  return this._started
95
96
  }
96
97
 
97
- async beforeStart () {
98
+ async beforeStart (): Promise<void> {
98
99
  await Promise.all(
99
100
  Object.values(this).filter(obj => isStartable(obj)).map(async (startable: Startable) => {
100
101
  if (startable.beforeStart != null) {
@@ -104,7 +105,7 @@ export class DefaultComponents implements Components, Startable {
104
105
  )
105
106
  }
106
107
 
107
- async start () {
108
+ async start (): Promise<void> {
108
109
  await Promise.all(
109
110
  Object.values(this).filter(obj => isStartable(obj)).map(async (startable: Startable) => {
110
111
  await startable.start()
@@ -114,7 +115,7 @@ export class DefaultComponents implements Components, Startable {
114
115
  this._started = true
115
116
  }
116
117
 
117
- async afterStart () {
118
+ async afterStart (): Promise<void> {
118
119
  await Promise.all(
119
120
  Object.values(this).filter(obj => isStartable(obj)).map(async (startable: Startable) => {
120
121
  if (startable.afterStart != null) {
@@ -124,7 +125,7 @@ export class DefaultComponents implements Components, Startable {
124
125
  )
125
126
  }
126
127
 
127
- async beforeStop () {
128
+ async beforeStop (): Promise<void> {
128
129
  await Promise.all(
129
130
  Object.values(this).filter(obj => isStartable(obj)).map(async (startable: Startable) => {
130
131
  if (startable.beforeStop != null) {
@@ -134,7 +135,7 @@ export class DefaultComponents implements Components, Startable {
134
135
  )
135
136
  }
136
137
 
137
- async stop () {
138
+ async stop (): Promise<void> {
138
139
  await Promise.all(
139
140
  Object.values(this).filter(obj => isStartable(obj)).map(async (startable: Startable) => {
140
141
  await startable.stop()
@@ -144,7 +145,7 @@ export class DefaultComponents implements Components, Startable {
144
145
  this._started = false
145
146
  }
146
147
 
147
- async afterStop () {
148
+ async afterStop (): Promise<void> {
148
149
  await Promise.all(
149
150
  Object.values(this).filter(obj => isStartable(obj)).map(async (startable: Startable) => {
150
151
  if (startable.afterStop != null) {
@@ -156,7 +157,7 @@ export class DefaultComponents implements Components, Startable {
156
157
 
157
158
  get peerId (): PeerId {
158
159
  if (this._peerId == null) {
159
- throw errCode(new Error('peerId not set'), 'ERR_SERVICE_MISSING')
160
+ throw new CodeError('peerId not set', 'ERR_SERVICE_MISSING')
160
161
  }
161
162
 
162
163
  return this._peerId
@@ -168,7 +169,7 @@ export class DefaultComponents implements Components, Startable {
168
169
 
169
170
  get addressManager (): AddressManager {
170
171
  if (this._addressManager == null) {
171
- throw errCode(new Error('addressManager not set'), 'ERR_SERVICE_MISSING')
172
+ throw new CodeError('addressManager not set', 'ERR_SERVICE_MISSING')
172
173
  }
173
174
 
174
175
  return this._addressManager
@@ -180,7 +181,7 @@ export class DefaultComponents implements Components, Startable {
180
181
 
181
182
  get peerStore (): PeerStore {
182
183
  if (this._peerStore == null) {
183
- throw errCode(new Error('peerStore not set'), 'ERR_SERVICE_MISSING')
184
+ throw new CodeError('peerStore not set', 'ERR_SERVICE_MISSING')
184
185
  }
185
186
 
186
187
  return this._peerStore
@@ -192,7 +193,7 @@ export class DefaultComponents implements Components, Startable {
192
193
 
193
194
  get upgrader (): Upgrader {
194
195
  if (this._upgrader == null) {
195
- throw errCode(new Error('upgrader not set'), 'ERR_SERVICE_MISSING')
196
+ throw new CodeError('upgrader not set', 'ERR_SERVICE_MISSING')
196
197
  }
197
198
 
198
199
  return this._upgrader
@@ -204,7 +205,7 @@ export class DefaultComponents implements Components, Startable {
204
205
 
205
206
  get registrar (): Registrar {
206
207
  if (this._registrar == null) {
207
- throw errCode(new Error('registrar not set'), 'ERR_SERVICE_MISSING')
208
+ throw new CodeError('registrar not set', 'ERR_SERVICE_MISSING')
208
209
  }
209
210
 
210
211
  return this._registrar
@@ -216,7 +217,7 @@ export class DefaultComponents implements Components, Startable {
216
217
 
217
218
  get connectionManager (): ConnectionManager {
218
219
  if (this._connectionManager == null) {
219
- throw errCode(new Error('connectionManager not set'), 'ERR_SERVICE_MISSING')
220
+ throw new CodeError('connectionManager not set', 'ERR_SERVICE_MISSING')
220
221
  }
221
222
 
222
223
  return this._connectionManager
@@ -228,7 +229,7 @@ export class DefaultComponents implements Components, Startable {
228
229
 
229
230
  get transportManager (): TransportManager {
230
231
  if (this._transportManager == null) {
231
- throw errCode(new Error('transportManager not set'), 'ERR_SERVICE_MISSING')
232
+ throw new CodeError('transportManager not set', 'ERR_SERVICE_MISSING')
232
233
  }
233
234
 
234
235
  return this._transportManager
@@ -240,7 +241,7 @@ export class DefaultComponents implements Components, Startable {
240
241
 
241
242
  get connectionGater (): ConnectionGater {
242
243
  if (this._connectionGater == null) {
243
- throw errCode(new Error('connectionGater not set'), 'ERR_SERVICE_MISSING')
244
+ throw new CodeError('connectionGater not set', 'ERR_SERVICE_MISSING')
244
245
  }
245
246
 
246
247
  return this._connectionGater
@@ -252,7 +253,7 @@ export class DefaultComponents implements Components, Startable {
252
253
 
253
254
  get contentRouting (): ContentRouting {
254
255
  if (this._contentRouting == null) {
255
- throw errCode(new Error('contentRouting not set'), 'ERR_SERVICE_MISSING')
256
+ throw new CodeError('contentRouting not set', 'ERR_SERVICE_MISSING')
256
257
  }
257
258
 
258
259
  return this._contentRouting
@@ -264,7 +265,7 @@ export class DefaultComponents implements Components, Startable {
264
265
 
265
266
  get peerRouting (): PeerRouting {
266
267
  if (this._peerRouting == null) {
267
- throw errCode(new Error('peerRouting not set'), 'ERR_SERVICE_MISSING')
268
+ throw new CodeError('peerRouting not set', 'ERR_SERVICE_MISSING')
268
269
  }
269
270
 
270
271
  return this._peerRouting
@@ -276,7 +277,7 @@ export class DefaultComponents implements Components, Startable {
276
277
 
277
278
  get datastore (): Datastore {
278
279
  if (this._datastore == null) {
279
- throw errCode(new Error('datastore not set'), 'ERR_SERVICE_MISSING')
280
+ throw new CodeError('datastore not set', 'ERR_SERVICE_MISSING')
280
281
  }
281
282
 
282
283
  return this._datastore
@@ -296,7 +297,7 @@ export class DefaultComponents implements Components, Startable {
296
297
 
297
298
  get dialer (): Dialer {
298
299
  if (this._dialer == null) {
299
- throw errCode(new Error('dialer not set'), 'ERR_SERVICE_MISSING')
300
+ throw new CodeError('dialer not set', 'ERR_SERVICE_MISSING')
300
301
  }
301
302
 
302
303
  return this._dialer
package/src/config.ts CHANGED
@@ -2,13 +2,12 @@ import mergeOptions from 'merge-options'
2
2
  import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers'
3
3
  import * as Constants from './constants.js'
4
4
  import { AGENT_VERSION } from './identify/consts.js'
5
- import * as RelayConstants from './circuit/constants.js'
6
5
  import { publicAddressesFirst } from '@libp2p/utils/address-sort'
7
6
  import { FaultTolerance } from '@libp2p/interface-transport'
8
7
  import type { Multiaddr } from '@multiformats/multiaddr'
9
8
  import type { Libp2pInit } from './index.js'
10
9
  import { codes, messages } from './errors.js'
11
- import errCode from 'err-code'
10
+ import { CodeError } from '@libp2p/interfaces/errors'
12
11
  import type { RecursivePartial } from '@libp2p/interfaces'
13
12
  import { isNode, isBrowser, isWebWorker, isElectronMain, isElectronRenderer, isReactNative } from 'wherearewe'
14
13
 
@@ -22,7 +21,6 @@ const DefaultConfig: Partial<Libp2pInit> = {
22
21
  connectionManager: {
23
22
  maxConnections: 300,
24
23
  minConnections: 50,
25
- autoDial: true,
26
24
  autoDialInterval: 10000,
27
25
  maxParallelDials: Constants.MAX_PARALLEL_DIALS,
28
26
  maxDialsPerPeer: Constants.MAX_PER_PEER_DIALS,
@@ -49,23 +47,6 @@ const DefaultConfig: Partial<Libp2pInit> = {
49
47
  ttl: 7200,
50
48
  keepAlive: true
51
49
  },
52
- relay: {
53
- enabled: true,
54
- advertise: {
55
- bootDelay: RelayConstants.ADVERTISE_BOOT_DELAY,
56
- enabled: false,
57
- ttl: RelayConstants.ADVERTISE_TTL
58
- },
59
- hop: {
60
- enabled: false,
61
- active: false,
62
- timeout: 30000
63
- },
64
- autoRelay: {
65
- enabled: false,
66
- maxListeners: 2
67
- }
68
- },
69
50
  identify: {
70
51
  protocolPrefix: 'ipfs',
71
52
  host: {
@@ -76,11 +57,18 @@ const DefaultConfig: Partial<Libp2pInit> = {
76
57
  maxInboundStreams: 1,
77
58
  maxOutboundStreams: 1,
78
59
  maxPushIncomingStreams: 1,
79
- maxPushOutgoingStreams: 1
60
+ maxPushOutgoingStreams: 1,
61
+ maxObservedAddresses: 10
80
62
  },
81
63
  ping: {
82
64
  protocolPrefix: 'ipfs',
83
- maxInboundStreams: 1,
65
+ // See https://github.com/libp2p/specs/blob/d4b5fb0152a6bb86cfd9ea/ping/ping.md?plain=1#L38-L43
66
+ // The dialing peer MUST NOT keep more than one outbound stream for the ping protocol per peer.
67
+ // The listening peer SHOULD accept at most two streams per peer since cross-stream behavior is
68
+ // non-linear and stream writes occur asynchronously. The listening peer may perceive the
69
+ // dialing peer closing and opening the wrong streams (for instance, closing stream B and
70
+ // opening stream A even though the dialing peer is opening stream B and closing stream A).
71
+ maxInboundStreams: 2,
84
72
  maxOutboundStreams: 1,
85
73
  timeout: 10000
86
74
  },
@@ -89,6 +77,14 @@ const DefaultConfig: Partial<Libp2pInit> = {
89
77
  maxInboundStreams: 1,
90
78
  maxOutboundStreams: 1,
91
79
  timeout: 10000
80
+ },
81
+ autonat: {
82
+ protocolPrefix: 'libp2p',
83
+ maxInboundStreams: 1,
84
+ maxOutboundStreams: 1,
85
+ timeout: 30000,
86
+ startupDelay: 5000,
87
+ refreshInterval: 60000
92
88
  }
93
89
  }
94
90
 
@@ -96,15 +92,15 @@ export function validateConfig (opts: RecursivePartial<Libp2pInit>): Libp2pInit
96
92
  const resultingOptions: Libp2pInit = mergeOptions(DefaultConfig, opts)
97
93
 
98
94
  if (resultingOptions.transports == null || resultingOptions.transports.length < 1) {
99
- throw errCode(new Error(messages.ERR_TRANSPORTS_REQUIRED), codes.ERR_TRANSPORTS_REQUIRED)
95
+ throw new CodeError(messages.ERR_TRANSPORTS_REQUIRED, codes.ERR_TRANSPORTS_REQUIRED)
100
96
  }
101
97
 
102
98
  if (resultingOptions.connectionEncryption == null || resultingOptions.connectionEncryption.length === 0) {
103
- throw errCode(new Error(messages.CONN_ENCRYPTION_REQUIRED), codes.CONN_ENCRYPTION_REQUIRED)
99
+ throw new CodeError(messages.CONN_ENCRYPTION_REQUIRED, codes.CONN_ENCRYPTION_REQUIRED)
104
100
  }
105
101
 
106
102
  if (resultingOptions.connectionProtector === null && globalThis.process?.env?.LIBP2P_FORCE_PNET != null) { // eslint-disable-line no-undef
107
- throw errCode(new Error(messages.ERR_PROTECTOR_REQUIRED), codes.ERR_PROTECTOR_REQUIRED)
103
+ throw new CodeError(messages.ERR_PROTECTOR_REQUIRED, codes.ERR_PROTECTOR_REQUIRED)
108
104
  }
109
105
 
110
106
  // Append user agent version to default AGENT_VERSION depending on the environment