@streamr/dht 0.0.1-tatum.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 (344) hide show
  1. package/.eslintignore +5 -0
  2. package/.eslintrc +3 -0
  3. package/README.md +38 -0
  4. package/dist/src/connection/Connection.d.ts +11 -0
  5. package/dist/src/connection/Connection.js +23 -0
  6. package/dist/src/connection/Connection.js.map +1 -0
  7. package/dist/src/connection/ConnectionLockHandler.d.ts +23 -0
  8. package/dist/src/connection/ConnectionLockHandler.js +94 -0
  9. package/dist/src/connection/ConnectionLockHandler.js.map +1 -0
  10. package/dist/src/connection/ConnectionManager.d.ts +94 -0
  11. package/dist/src/connection/ConnectionManager.js +554 -0
  12. package/dist/src/connection/ConnectionManager.js.map +1 -0
  13. package/dist/src/connection/ConnectivityChecker.d.ts +17 -0
  14. package/dist/src/connection/ConnectivityChecker.js +187 -0
  15. package/dist/src/connection/ConnectivityChecker.js.map +1 -0
  16. package/dist/src/connection/Handshaker.d.ts +19 -0
  17. package/dist/src/connection/Handshaker.js +77 -0
  18. package/dist/src/connection/Handshaker.js.map +1 -0
  19. package/dist/src/connection/IConnection.d.ts +38 -0
  20. package/dist/src/connection/IConnection.js +19 -0
  21. package/dist/src/connection/IConnection.js.map +1 -0
  22. package/dist/src/connection/IConnectionSource.d.ts +4 -0
  23. package/dist/src/connection/IConnectionSource.js +3 -0
  24. package/dist/src/connection/IConnectionSource.js.map +1 -0
  25. package/dist/src/connection/ManagedConnection.d.ts +60 -0
  26. package/dist/src/connection/ManagedConnection.js +352 -0
  27. package/dist/src/connection/ManagedConnection.js.map +1 -0
  28. package/dist/src/connection/ManagedWebRtcConnection.d.ts +7 -0
  29. package/dist/src/connection/ManagedWebRtcConnection.js +20 -0
  30. package/dist/src/connection/ManagedWebRtcConnection.js.map +1 -0
  31. package/dist/src/connection/RemoteConnectionLocker.d.ts +14 -0
  32. package/dist/src/connection/RemoteConnectionLocker.js +93 -0
  33. package/dist/src/connection/RemoteConnectionLocker.js.map +1 -0
  34. package/dist/src/connection/Simulator/Simulator.d.ts +42 -0
  35. package/dist/src/connection/Simulator/Simulator.js +325 -0
  36. package/dist/src/connection/Simulator/Simulator.js.map +1 -0
  37. package/dist/src/connection/Simulator/SimulatorConnection.d.ts +19 -0
  38. package/dist/src/connection/Simulator/SimulatorConnection.js +118 -0
  39. package/dist/src/connection/Simulator/SimulatorConnection.js.map +1 -0
  40. package/dist/src/connection/Simulator/SimulatorConnector.d.ts +17 -0
  41. package/dist/src/connection/Simulator/SimulatorConnector.js +72 -0
  42. package/dist/src/connection/Simulator/SimulatorConnector.js.map +1 -0
  43. package/dist/src/connection/Simulator/SimulatorTransport.d.ts +6 -0
  44. package/dist/src/connection/Simulator/SimulatorTransport.js +11 -0
  45. package/dist/src/connection/Simulator/SimulatorTransport.js.map +1 -0
  46. package/dist/src/connection/Simulator/pings.d.ts +21 -0
  47. package/dist/src/connection/Simulator/pings.js +61 -0
  48. package/dist/src/connection/Simulator/pings.js.map +1 -0
  49. package/dist/src/connection/WebRTC/IWebRtcConnection.d.ts +20 -0
  50. package/dist/src/connection/WebRTC/IWebRtcConnection.js +9 -0
  51. package/dist/src/connection/WebRTC/IWebRtcConnection.js.map +1 -0
  52. package/dist/src/connection/WebRTC/NodeWebRtcConnection.d.ts +47 -0
  53. package/dist/src/connection/WebRTC/NodeWebRtcConnection.js +233 -0
  54. package/dist/src/connection/WebRTC/NodeWebRtcConnection.js.map +1 -0
  55. package/dist/src/connection/WebRTC/RemoteWebrtcConnector.d.ts +12 -0
  56. package/dist/src/connection/WebRTC/RemoteWebrtcConnector.js +74 -0
  57. package/dist/src/connection/WebRTC/RemoteWebrtcConnector.js.map +1 -0
  58. package/dist/src/connection/WebRTC/WebRtcConnector.d.ts +47 -0
  59. package/dist/src/connection/WebRTC/WebRtcConnector.js +227 -0
  60. package/dist/src/connection/WebRTC/WebRtcConnector.js.map +1 -0
  61. package/dist/src/connection/WebRTC/iceServerAsString.d.ts +2 -0
  62. package/dist/src/connection/WebRTC/iceServerAsString.js +18 -0
  63. package/dist/src/connection/WebRTC/iceServerAsString.js.map +1 -0
  64. package/dist/src/connection/WebSocket/ClientWebSocket.d.ts +15 -0
  65. package/dist/src/connection/WebSocket/ClientWebSocket.js +113 -0
  66. package/dist/src/connection/WebSocket/ClientWebSocket.js.map +1 -0
  67. package/dist/src/connection/WebSocket/RemoteWebSocketConnector.d.ts +9 -0
  68. package/dist/src/connection/WebSocket/RemoteWebSocketConnector.js +63 -0
  69. package/dist/src/connection/WebSocket/RemoteWebSocketConnector.js.map +1 -0
  70. package/dist/src/connection/WebSocket/ServerWebSocket.d.ts +18 -0
  71. package/dist/src/connection/WebSocket/ServerWebSocket.js +103 -0
  72. package/dist/src/connection/WebSocket/ServerWebSocket.js.map +1 -0
  73. package/dist/src/connection/WebSocket/WebSocketConnector.d.ts +31 -0
  74. package/dist/src/connection/WebSocket/WebSocketConnector.js +202 -0
  75. package/dist/src/connection/WebSocket/WebSocketConnector.js.map +1 -0
  76. package/dist/src/connection/WebSocket/WebSocketServer.d.ts +9 -0
  77. package/dist/src/connection/WebSocket/WebSocketServer.js +101 -0
  78. package/dist/src/connection/WebSocket/WebSocketServer.js.map +1 -0
  79. package/dist/src/dht/DhtNode.d.ts +153 -0
  80. package/dist/src/dht/DhtNode.js +599 -0
  81. package/dist/src/dht/DhtNode.js.map +1 -0
  82. package/dist/src/dht/DhtPeer.d.ts +18 -0
  83. package/dist/src/dht/DhtPeer.js +74 -0
  84. package/dist/src/dht/DhtPeer.js.map +1 -0
  85. package/dist/src/dht/ExternalApi.d.ts +8 -0
  86. package/dist/src/dht/ExternalApi.js +26 -0
  87. package/dist/src/dht/ExternalApi.js.map +1 -0
  88. package/dist/src/dht/RemoteExternalApi.d.ts +6 -0
  89. package/dist/src/dht/RemoteExternalApi.js +26 -0
  90. package/dist/src/dht/RemoteExternalApi.js.map +1 -0
  91. package/dist/src/dht/contact/Contact.d.ts +22 -0
  92. package/dist/src/dht/contact/Contact.js +25 -0
  93. package/dist/src/dht/contact/Contact.js.map +1 -0
  94. package/dist/src/dht/contact/RandomContactList.d.ts +20 -0
  95. package/dist/src/dht/contact/RandomContactList.js +78 -0
  96. package/dist/src/dht/contact/RandomContactList.js.map +1 -0
  97. package/dist/src/dht/contact/Remote.d.ts +15 -0
  98. package/dist/src/dht/contact/Remote.js +24 -0
  99. package/dist/src/dht/contact/Remote.js.map +1 -0
  100. package/dist/src/dht/contact/SortedContactList.d.ts +35 -0
  101. package/dist/src/dht/contact/SortedContactList.js +156 -0
  102. package/dist/src/dht/contact/SortedContactList.js.map +1 -0
  103. package/dist/src/dht/discovery/DiscoverySession.d.ts +36 -0
  104. package/dist/src/dht/discovery/DiscoverySession.js +116 -0
  105. package/dist/src/dht/discovery/DiscoverySession.js.map +1 -0
  106. package/dist/src/dht/discovery/PeerDiscovery.d.ts +42 -0
  107. package/dist/src/dht/discovery/PeerDiscovery.js +157 -0
  108. package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -0
  109. package/dist/src/dht/find/RecursiveFindSession.d.ts +46 -0
  110. package/dist/src/dht/find/RecursiveFindSession.js +142 -0
  111. package/dist/src/dht/find/RecursiveFindSession.js.map +1 -0
  112. package/dist/src/dht/find/RecursiveFinder.d.ts +54 -0
  113. package/dist/src/dht/find/RecursiveFinder.js +180 -0
  114. package/dist/src/dht/find/RecursiveFinder.js.map +1 -0
  115. package/dist/src/dht/find/RemoteRecursiveFindSession.d.ts +6 -0
  116. package/dist/src/dht/find/RemoteRecursiveFindSession.js +25 -0
  117. package/dist/src/dht/find/RemoteRecursiveFindSession.js.map +1 -0
  118. package/dist/src/dht/routing/DuplicateDetector.d.ts +13 -0
  119. package/dist/src/dht/routing/DuplicateDetector.js +41 -0
  120. package/dist/src/dht/routing/DuplicateDetector.js.map +1 -0
  121. package/dist/src/dht/routing/RemoteRouter.d.ts +8 -0
  122. package/dist/src/dht/routing/RemoteRouter.js +106 -0
  123. package/dist/src/dht/routing/RemoteRouter.js.map +1 -0
  124. package/dist/src/dht/routing/Router.d.ts +60 -0
  125. package/dist/src/dht/routing/Router.js +207 -0
  126. package/dist/src/dht/routing/Router.js.map +1 -0
  127. package/dist/src/dht/routing/RoutingSession.d.ts +42 -0
  128. package/dist/src/dht/routing/RoutingSession.js +178 -0
  129. package/dist/src/dht/routing/RoutingSession.js.map +1 -0
  130. package/dist/src/dht/store/DataStore.d.ts +45 -0
  131. package/dist/src/dht/store/DataStore.js +244 -0
  132. package/dist/src/dht/store/DataStore.js.map +1 -0
  133. package/dist/src/dht/store/LocalDataStore.d.ts +19 -0
  134. package/dist/src/dht/store/LocalDataStore.js +104 -0
  135. package/dist/src/dht/store/LocalDataStore.js.map +1 -0
  136. package/dist/src/dht/store/RemoteStore.d.ts +8 -0
  137. package/dist/src/dht/store/RemoteStore.js +44 -0
  138. package/dist/src/dht/store/RemoteStore.js.map +1 -0
  139. package/dist/src/exports.d.ts +19 -0
  140. package/dist/src/exports.js +41 -0
  141. package/dist/src/exports.js.map +1 -0
  142. package/dist/src/helpers/AddressTools.d.ts +2 -0
  143. package/dist/src/helpers/AddressTools.js +31 -0
  144. package/dist/src/helpers/AddressTools.js.map +1 -0
  145. package/dist/src/helpers/PeerID.d.ts +25 -0
  146. package/dist/src/helpers/PeerID.js +84 -0
  147. package/dist/src/helpers/PeerID.js.map +1 -0
  148. package/dist/src/helpers/UUID.d.ts +7 -0
  149. package/dist/src/helpers/UUID.js +32 -0
  150. package/dist/src/helpers/UUID.js.map +1 -0
  151. package/dist/src/helpers/debugHelpers.d.ts +3 -0
  152. package/dist/src/helpers/debugHelpers.js +11 -0
  153. package/dist/src/helpers/debugHelpers.js.map +1 -0
  154. package/dist/src/helpers/errors.d.ts +72 -0
  155. package/dist/src/helpers/errors.js +95 -0
  156. package/dist/src/helpers/errors.js.map +1 -0
  157. package/dist/src/helpers/peerIdFromPeerDescriptor.d.ts +5 -0
  158. package/dist/src/helpers/peerIdFromPeerDescriptor.js +17 -0
  159. package/dist/src/helpers/peerIdFromPeerDescriptor.js.map +1 -0
  160. package/dist/src/helpers/protoClasses.d.ts +2 -0
  161. package/dist/src/helpers/protoClasses.js +35 -0
  162. package/dist/src/helpers/protoClasses.js.map +1 -0
  163. package/dist/src/helpers/protoToString.d.ts +2 -0
  164. package/dist/src/helpers/protoToString.js +20 -0
  165. package/dist/src/helpers/protoToString.js.map +1 -0
  166. package/dist/src/proto/google/protobuf/any.d.ts +173 -0
  167. package/dist/src/proto/google/protobuf/any.js +155 -0
  168. package/dist/src/proto/google/protobuf/any.js.map +1 -0
  169. package/dist/src/proto/google/protobuf/empty.d.ts +32 -0
  170. package/dist/src/proto/google/protobuf/empty.js +34 -0
  171. package/dist/src/proto/google/protobuf/empty.js.map +1 -0
  172. package/dist/src/proto/google/protobuf/timestamp.d.ts +149 -0
  173. package/dist/src/proto/google/protobuf/timestamp.js +136 -0
  174. package/dist/src/proto/google/protobuf/timestamp.js.map +1 -0
  175. package/dist/src/proto/packages/dht/protos/DhtRpc.client.d.ts +320 -0
  176. package/dist/src/proto/packages/dht/protos/DhtRpc.client.js +245 -0
  177. package/dist/src/proto/packages/dht/protos/DhtRpc.client.js.map +1 -0
  178. package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +1089 -0
  179. package/dist/src/proto/packages/dht/protos/DhtRpc.js +710 -0
  180. package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -0
  181. package/dist/src/proto/packages/dht/protos/DhtRpc.server.d.ts +145 -0
  182. package/dist/src/proto/packages/dht/protos/DhtRpc.server.js +3 -0
  183. package/dist/src/proto/packages/dht/protos/DhtRpc.server.js.map +1 -0
  184. package/dist/src/proto/packages/proto-rpc/protos/ProtoRpc.d.ts +87 -0
  185. package/dist/src/proto/packages/proto-rpc/protos/ProtoRpc.js +66 -0
  186. package/dist/src/proto/packages/proto-rpc/protos/ProtoRpc.js.map +1 -0
  187. package/dist/src/proto/tests.d.ts +39 -0
  188. package/dist/src/proto/tests.js +34 -0
  189. package/dist/src/proto/tests.js.map +1 -0
  190. package/dist/src/rpc-protocol/DhtCallContext.d.ts +12 -0
  191. package/dist/src/rpc-protocol/DhtCallContext.js +8 -0
  192. package/dist/src/rpc-protocol/DhtCallContext.js.map +1 -0
  193. package/dist/src/rpc-protocol/DhtRpcOptions.d.ts +8 -0
  194. package/dist/src/rpc-protocol/DhtRpcOptions.js +3 -0
  195. package/dist/src/rpc-protocol/DhtRpcOptions.js.map +1 -0
  196. package/dist/src/transport/ITransport.d.ts +22 -0
  197. package/dist/src/transport/ITransport.js +3 -0
  198. package/dist/src/transport/ITransport.js.map +1 -0
  199. package/dist/src/transport/ListeningRpcCommunicator.d.ts +6 -0
  200. package/dist/src/transport/ListeningRpcCommunicator.js +14 -0
  201. package/dist/src/transport/ListeningRpcCommunicator.js.map +1 -0
  202. package/dist/src/transport/RoutingRpcCommunicator.d.ts +8 -0
  203. package/dist/src/transport/RoutingRpcCommunicator.js +52 -0
  204. package/dist/src/transport/RoutingRpcCommunicator.js.map +1 -0
  205. package/jest.config.js +2 -0
  206. package/karma.config.js +20 -0
  207. package/package.json +64 -0
  208. package/proto.sh +3 -0
  209. package/protos/DhtRpc.proto +330 -0
  210. package/protos/tests.proto +16 -0
  211. package/src/connection/Connection.ts +23 -0
  212. package/src/connection/ConnectionLockHandler.ts +105 -0
  213. package/src/connection/ConnectionManager.ts +676 -0
  214. package/src/connection/ConnectivityChecker.ts +173 -0
  215. package/src/connection/Handshaker.ts +92 -0
  216. package/src/connection/IConnection.ts +47 -0
  217. package/src/connection/IConnectionSource.ts +6 -0
  218. package/src/connection/ManagedConnection.ts +398 -0
  219. package/src/connection/ManagedWebRtcConnection.ts +27 -0
  220. package/src/connection/RemoteConnectionLocker.ts +88 -0
  221. package/src/connection/Simulator/Simulator.ts +399 -0
  222. package/src/connection/Simulator/SimulatorConnection.ts +137 -0
  223. package/src/connection/Simulator/SimulatorConnector.ts +104 -0
  224. package/src/connection/Simulator/SimulatorTransport.ts +9 -0
  225. package/src/connection/Simulator/pings.ts +42 -0
  226. package/src/connection/WebRTC/BrowserWebRtcConnection.ts +227 -0
  227. package/src/connection/WebRTC/IWebRtcConnection.ts +24 -0
  228. package/src/connection/WebRTC/NodeWebRtcConnection.ts +256 -0
  229. package/src/connection/WebRTC/RemoteWebrtcConnector.ts +93 -0
  230. package/src/connection/WebRTC/WebRtcConnector.ts +306 -0
  231. package/src/connection/WebRTC/iceServerAsString.ts +15 -0
  232. package/src/connection/WebSocket/ClientWebSocket.ts +118 -0
  233. package/src/connection/WebSocket/RemoteWebSocketConnector.ts +49 -0
  234. package/src/connection/WebSocket/ServerWebSocket.ts +119 -0
  235. package/src/connection/WebSocket/WebSocketConnector.ts +264 -0
  236. package/src/connection/WebSocket/WebSocketServer.ts +97 -0
  237. package/src/dht/DhtNode.ts +776 -0
  238. package/src/dht/DhtPeer.ts +96 -0
  239. package/src/dht/ExternalApi.ts +29 -0
  240. package/src/dht/RemoteExternalApi.ts +25 -0
  241. package/src/dht/contact/Contact.ts +36 -0
  242. package/src/dht/contact/RandomContactList.ts +92 -0
  243. package/src/dht/contact/Remote.ts +40 -0
  244. package/src/dht/contact/SortedContactList.ts +196 -0
  245. package/src/dht/discovery/DiscoverySession.ts +150 -0
  246. package/src/dht/discovery/PeerDiscovery.ts +162 -0
  247. package/src/dht/find/RecursiveFindSession.ts +178 -0
  248. package/src/dht/find/RecursiveFinder.ts +272 -0
  249. package/src/dht/find/RemoteRecursiveFindSession.ts +33 -0
  250. package/src/dht/routing/DuplicateDetector.ts +53 -0
  251. package/src/dht/routing/RemoteRouter.ts +115 -0
  252. package/src/dht/routing/Router.ts +266 -0
  253. package/src/dht/routing/RoutingSession.ts +222 -0
  254. package/src/dht/store/DataStore.ts +321 -0
  255. package/src/dht/store/LocalDataStore.ts +114 -0
  256. package/src/dht/store/RemoteStore.ts +58 -0
  257. package/src/exports.ts +19 -0
  258. package/src/helpers/AddressTools.ts +26 -0
  259. package/src/helpers/PeerID.ts +95 -0
  260. package/src/helpers/UUID.ts +30 -0
  261. package/src/helpers/debugHelpers.ts +9 -0
  262. package/src/helpers/errors.ts +49 -0
  263. package/src/helpers/peerIdFromPeerDescriptor.ts +14 -0
  264. package/src/helpers/protoClasses.ts +63 -0
  265. package/src/helpers/protoToString.ts +21 -0
  266. package/src/proto/google/protobuf/any.ts +319 -0
  267. package/src/proto/google/protobuf/empty.ts +84 -0
  268. package/src/proto/google/protobuf/timestamp.ts +281 -0
  269. package/src/proto/packages/dht/protos/DhtRpc.client.ts +373 -0
  270. package/src/proto/packages/dht/protos/DhtRpc.server.ts +148 -0
  271. package/src/proto/packages/dht/protos/DhtRpc.ts +1399 -0
  272. package/src/proto/packages/proto-rpc/protos/ProtoRpc.ts +108 -0
  273. package/src/proto/tests.ts +52 -0
  274. package/src/rpc-protocol/DhtCallContext.ts +15 -0
  275. package/src/rpc-protocol/DhtRpcOptions.ts +9 -0
  276. package/src/transport/ITransport.ts +31 -0
  277. package/src/transport/ListeningRpcCommunicator.ts +14 -0
  278. package/src/transport/RoutingRpcCommunicator.ts +59 -0
  279. package/src/types/glogal.d.ts +1 -0
  280. package/src/types/textencoding.d.ts +7 -0
  281. package/test/RandomGraphSimulation.ts +52 -0
  282. package/test/benchmark/KademliaCorrectness.test.ts +115 -0
  283. package/test/benchmark/RecursiveFind.test.ts +87 -0
  284. package/test/benchmark/any.test.ts +28 -0
  285. package/test/benchmark/kademlia-simulation/Contact.ts +32 -0
  286. package/test/benchmark/kademlia-simulation/KademliaSimulation.ts +94 -0
  287. package/test/benchmark/kademlia-simulation/SimulationNode.ts +125 -0
  288. package/test/data/generateGroundTruthData.ts +70 -0
  289. package/test/end-to-end/Layer0-Layer1.test.ts +87 -0
  290. package/test/end-to-end/Layer0.test.ts +60 -0
  291. package/test/end-to-end/Layer0MixedConnectionTypes.test.ts +94 -0
  292. package/test/end-to-end/Layer0WebRTC-Layer1.test.ts +134 -0
  293. package/test/end-to-end/Layer0WebRTC.test.ts +98 -0
  294. package/test/end-to-end/Layer1-Scale-WebRTC.test.ts +69 -0
  295. package/test/end-to-end/Layer1-Scale-WebSocket.test.ts +73 -0
  296. package/test/end-to-end/WebSocketConnectionRequest.test.ts +62 -0
  297. package/test/integration/ConnectionLocking.test.ts +166 -0
  298. package/test/integration/ConnectionManager.test.ts +291 -0
  299. package/test/integration/DhtNodeExternalAPI.test.ts +43 -0
  300. package/test/integration/DhtPeer.test.ts +73 -0
  301. package/test/integration/DhtRpc.test.ts +131 -0
  302. package/test/integration/DhtWithMockConnectionLatencies.test.ts +46 -0
  303. package/test/integration/DhtWithMockConnections.test.ts +46 -0
  304. package/test/integration/DhtWithRealConnectionLatencies.test.ts +47 -0
  305. package/test/integration/Layer1-scale.test.ts +200 -0
  306. package/test/integration/MigrateData.test.ts +203 -0
  307. package/test/integration/Mock-Layer1-Layer0.test.ts +106 -0
  308. package/test/integration/MultipleEntryPointJoining.test.ts +105 -0
  309. package/test/integration/RecursiveFind.test.ts +50 -0
  310. package/test/integration/RemoteRouter.test.ts +83 -0
  311. package/test/integration/RemoteStore.test.ts +66 -0
  312. package/test/integration/RouteMessage.test.ts +254 -0
  313. package/test/integration/RpcErrors.test.ts +153 -0
  314. package/test/integration/ScaleDownDht.test.ts +66 -0
  315. package/test/integration/SimultaneousConnections.test.ts +308 -0
  316. package/test/integration/Store.test.ts +72 -0
  317. package/test/integration/StoreAndDelete.test.ts +93 -0
  318. package/test/integration/StoreOnDhtWithTwoNodes.test.ts +71 -0
  319. package/test/integration/WebRtcConnectionManagement.test.ts +205 -0
  320. package/test/integration/WebRtcConnectorRpc.test.ts +145 -0
  321. package/test/integration/WebSocket.test.ts +64 -0
  322. package/test/integration/WebSocketConnectionManagement.test.ts +131 -0
  323. package/test/integration/WebSocketConnectorRpc.test.ts +86 -0
  324. package/test/kademlia-simulation/data/nodeids.json +13002 -0
  325. package/test/kademlia-simulation/data/orderedneighbors.json +1001 -0
  326. package/test/unit/AddressTools.test.ts +40 -0
  327. package/test/unit/DuplicateDetector.test.ts +29 -0
  328. package/test/unit/LocalDataStore.test.ts +107 -0
  329. package/test/unit/PeerID.test.ts +22 -0
  330. package/test/unit/ProtobufMessage.test.ts +21 -0
  331. package/test/unit/RandomContactList.test.ts +87 -0
  332. package/test/unit/RecursiveFinder.test.ts +112 -0
  333. package/test/unit/Router.test.ts +124 -0
  334. package/test/unit/SortedContactList.test.ts +127 -0
  335. package/test/unit/UUID.test.ts +49 -0
  336. package/test/unit/WebSocketServer.test.ts +42 -0
  337. package/test/utils/mock/RecursiveFinder.ts +19 -0
  338. package/test/utils/mock/Router.ts +53 -0
  339. package/test/utils/mock/Transport.ts +26 -0
  340. package/test/utils/utils.ts +311 -0
  341. package/tsconfig.browser.json +15 -0
  342. package/tsconfig.jest.json +19 -0
  343. package/tsconfig.json +3 -0
  344. package/tsconfig.node.json +18 -0
@@ -0,0 +1,676 @@
1
+ import { EventEmitter } from 'eventemitter3'
2
+ import {
3
+ ConnectivityResponse,
4
+ DisconnectMode,
5
+ DisconnectNotice,
6
+ DisconnectNoticeResponse,
7
+ LockRequest,
8
+ LockResponse,
9
+ Message,
10
+ MessageType,
11
+ PeerDescriptor,
12
+ UnlockRequest
13
+ } from '../proto/packages/dht/protos/DhtRpc'
14
+ import { WebSocketConnector } from './WebSocket/WebSocketConnector'
15
+ import { PeerIDKey } from '../helpers/PeerID'
16
+ import { protoToString } from '../helpers/protoToString'
17
+ import { DisconnectionType, ITransport, TransportEvents } from '../transport/ITransport'
18
+ import { IceServer, WebRtcConnector } from './WebRTC/WebRtcConnector'
19
+ import { CountMetric, LevelMetric, Logger, Metric, MetricsContext, MetricsDefinition, RateMetric, waitForEvent3 } from '@streamr/utils'
20
+ import * as Err from '../helpers/errors'
21
+ import { WEB_RTC_CLEANUP } from './WebRTC/NodeWebRtcConnection'
22
+ import { ManagedConnection, Events as ManagedConnectionEvents } from './ManagedConnection'
23
+ import { RoutingRpcCommunicator } from '../transport/RoutingRpcCommunicator'
24
+ import { toProtoRpcClient } from '@streamr/proto-rpc'
25
+ import { ConnectionLockerClient } from '../proto/packages/dht/protos/DhtRpc.client'
26
+ import { RemoteConnectionLocker } from './RemoteConnectionLocker'
27
+ import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
28
+ import { Empty } from '../proto/google/protobuf/empty'
29
+ import { Simulator } from './Simulator/Simulator'
30
+ import { SimulatorConnector } from './Simulator/SimulatorConnector'
31
+ import { ConnectionLockHandler } from './ConnectionLockHandler'
32
+ import { DuplicateDetector } from '../dht/routing/DuplicateDetector'
33
+ import { SortedContactList } from '../dht/contact/SortedContactList'
34
+ import { Contact } from '../dht/contact/Contact'
35
+ import {
36
+ isSamePeerDescriptor,
37
+ keyFromPeerDescriptor,
38
+ peerIdFromPeerDescriptor
39
+ } from '../helpers/peerIdFromPeerDescriptor'
40
+
41
+ export class ConnectionManagerConfig {
42
+ transportLayer?: ITransport
43
+ webSocketHost?: string
44
+ webSocketPort?: number
45
+ entryPoints?: PeerDescriptor[]
46
+ nodeName?: string
47
+ maxConnections: number = 80
48
+ iceServers?: IceServer[]
49
+ metricsContext?: MetricsContext
50
+ webrtcAllowPrivateAddresses?: boolean
51
+ webrtcDatachannelBufferThresholdLow?: number
52
+ webrtcDatachannelBufferThresholdHigh?: number
53
+ webrtcNewConnectionTimeout?: number
54
+
55
+ // the following fields are used in simulation only
56
+ simulator?: Simulator
57
+ ownPeerDescriptor?: PeerDescriptor
58
+ serviceIdPrefix?: string
59
+
60
+ constructor(conf: Partial<ConnectionManagerConfig>) {
61
+ // assign given non-undefined config vars over defaults
62
+ let k: keyof typeof conf
63
+ for (k in conf) {
64
+ if (conf[k] === undefined) {
65
+ delete conf[k]
66
+ }
67
+ }
68
+ Object.assign(this, conf)
69
+ }
70
+ }
71
+
72
+ export enum NatType {
73
+ OPEN_INTERNET = 'open_internet',
74
+ UNKNOWN = 'unknown'
75
+ }
76
+
77
+ interface ConnectionManagerMetrics extends MetricsDefinition {
78
+ sendMessagesPerSecond: Metric
79
+ sendBytesPerSecond: Metric
80
+ receiveMessagesPerSecond: Metric
81
+ receiveBytesPerSecond: Metric
82
+ connectionAverageCount: Metric
83
+ connectionTotalFailureCount: Metric
84
+ }
85
+
86
+ type ServiceId = string
87
+
88
+ export type PeerDescriptorGeneratorCallback = (connectivityResponse: ConnectivityResponse) => PeerDescriptor
89
+
90
+ const logger = new Logger(module)
91
+
92
+ enum ConnectionManagerState {
93
+ IDLE = 'idle',
94
+ RUNNING = 'running',
95
+ STOPPING = 'stopping',
96
+ STOPPED = 'stopped'
97
+ }
98
+
99
+ interface ConnectionManagerEvents {
100
+ newConnection: (connection: ManagedConnection) => void
101
+ }
102
+
103
+ export interface ConnectionLocker {
104
+ lockConnection(targetDescriptor: PeerDescriptor, serviceId: ServiceId): void
105
+ unlockConnection(targetDescriptor: PeerDescriptor, serviceId: ServiceId): void
106
+ weakLockConnection(targetDescriptor: PeerDescriptor): void
107
+ weakUnlockConnection(targetDescriptor: PeerDescriptor): void
108
+ }
109
+
110
+ export type Events = TransportEvents & ConnectionManagerEvents
111
+
112
+ export class ConnectionManager extends EventEmitter<Events> implements ITransport, ConnectionLocker {
113
+ public static PROTOCOL_VERSION = '1.0'
114
+ private config: ConnectionManagerConfig
115
+ private readonly metricsContext: MetricsContext
116
+ private ownPeerDescriptor?: PeerDescriptor
117
+ private readonly messageDuplicateDetector: DuplicateDetector = new DuplicateDetector(100000, 100)
118
+ private readonly metrics: ConnectionManagerMetrics
119
+ private locks = new ConnectionLockHandler()
120
+ private connections: Map<PeerIDKey, ManagedConnection> = new Map()
121
+ private webSocketConnector?: WebSocketConnector
122
+ private webrtcConnector?: WebRtcConnector
123
+ private simulatorConnector?: SimulatorConnector
124
+ private rpcCommunicator?: RoutingRpcCommunicator
125
+ private disconnectorIntervalRef?: NodeJS.Timer
126
+ private serviceId: ServiceId
127
+ private state = ConnectionManagerState.IDLE
128
+
129
+ constructor(conf: Partial<ConnectionManagerConfig>) {
130
+ super()
131
+ this.config = new ConnectionManagerConfig(conf)
132
+ this.onData = this.onData.bind(this)
133
+ this.incomingConnectionCallback = this.incomingConnectionCallback.bind(this)
134
+ this.metricsContext = this.config.metricsContext || new MetricsContext()
135
+ this.metrics = {
136
+ sendMessagesPerSecond: new RateMetric(),
137
+ sendBytesPerSecond: new RateMetric(),
138
+ receiveMessagesPerSecond: new RateMetric(),
139
+ receiveBytesPerSecond: new RateMetric(),
140
+ connectionAverageCount: new LevelMetric(0),
141
+ connectionTotalFailureCount: new CountMetric()
142
+ }
143
+ this.metricsContext.addMetrics('node', this.metrics)
144
+ if (this.config.simulator) {
145
+ logger.trace(`Creating SimulatorConnector`)
146
+ this.simulatorConnector = new SimulatorConnector(
147
+ ConnectionManager.PROTOCOL_VERSION,
148
+ this.config.ownPeerDescriptor!,
149
+ this.config.simulator,
150
+ this.incomingConnectionCallback
151
+ )
152
+ this.config.simulator.addConnector(this.simulatorConnector)
153
+ this.ownPeerDescriptor = this.config.ownPeerDescriptor
154
+ this.state = ConnectionManagerState.RUNNING
155
+ } else {
156
+ logger.trace(`Creating WebSocketConnector`)
157
+ this.webSocketConnector = new WebSocketConnector(
158
+ ConnectionManager.PROTOCOL_VERSION,
159
+ this.config.transportLayer!,
160
+ this.canConnect.bind(this),
161
+ this.incomingConnectionCallback,
162
+ this.config.webSocketPort,
163
+ this.config.webSocketHost,
164
+ this.config.entryPoints
165
+ )
166
+ logger.trace(`Creating WebRTCConnector`)
167
+ this.webrtcConnector = new WebRtcConnector({
168
+ rpcTransport: this.config.transportLayer!,
169
+ protocolVersion: ConnectionManager.PROTOCOL_VERSION,
170
+ iceServers: this.config.iceServers,
171
+ allowPrivateAddresses: this.config.webrtcAllowPrivateAddresses,
172
+ bufferThresholdLow: this.config.webrtcDatachannelBufferThresholdLow,
173
+ bufferThresholdHigh: this.config.webrtcDatachannelBufferThresholdHigh,
174
+ connectionTimeout: this.config.webrtcNewConnectionTimeout
175
+ }, this.incomingConnectionCallback)
176
+ }
177
+ this.serviceId = (this.config.serviceIdPrefix ? this.config.serviceIdPrefix : '') + 'ConnectionManager'
178
+ this.send = this.send.bind(this)
179
+ this.rpcCommunicator = new RoutingRpcCommunicator(this.serviceId, this.send, {
180
+ rpcRequestTimeout: 10000
181
+ })
182
+ this.rpcCommunicator.registerRpcMethod(LockRequest, LockResponse, 'lockRequest',
183
+ (req: LockRequest, context) => this.lockRequest(req, context))
184
+ this.rpcCommunicator.registerRpcNotification(UnlockRequest, 'unlockRequest',
185
+ (req: UnlockRequest, context) => this.unlockRequest(req, context))
186
+ this.rpcCommunicator.registerRpcMethod(DisconnectNotice, DisconnectNoticeResponse, 'gracefulDisconnect',
187
+ (req: DisconnectNotice, context) => this.gracefulDisconnect(req, context))
188
+ }
189
+
190
+ public garbageCollectConnections(maxConnections: number, lastUsedLimit: number): void {
191
+ if (this.connections.size <= maxConnections) {
192
+ return
193
+ }
194
+ const disconnectionCandidates = new SortedContactList(peerIdFromPeerDescriptor(this.ownPeerDescriptor!), 100000)
195
+ this.connections.forEach((connection) => {
196
+ if (!this.locks.isLocked(connection.peerIdKey) && Date.now() - connection.getLastUsed() > lastUsedLimit) {
197
+ logger.trace('disconnecting in timeout interval: ' + this.config.nodeName + ', '
198
+ + connection.getPeerDescriptor()?.nodeName + ' ')
199
+ disconnectionCandidates.addContact(new Contact(connection.getPeerDescriptor()!))
200
+ }
201
+ })
202
+ const sortedCandidates = disconnectionCandidates.getAllContacts()
203
+ const targetNum = this.connections.size - maxConnections
204
+ for (let i = 0; i < sortedCandidates.length && i < targetNum; i++) {
205
+ logger.trace(this.config.nodeName + ' garbageCollecting '
206
+ + sortedCandidates[sortedCandidates.length - 1 - i].getPeerDescriptor().nodeName)
207
+ this.gracefullyDisconnectAsync(sortedCandidates[sortedCandidates.length - 1 - i].getPeerDescriptor(),
208
+ DisconnectMode.NORMAL).catch((_e) => { })
209
+ }
210
+ }
211
+
212
+ public async start(peerDescriptorGeneratorCallback?: PeerDescriptorGeneratorCallback): Promise<void> {
213
+ if (this.state === ConnectionManagerState.RUNNING || this.state === ConnectionManagerState.STOPPED) {
214
+ throw new Err.CouldNotStart(`Cannot start already ${this.state} module`)
215
+ }
216
+ this.state = ConnectionManagerState.RUNNING
217
+ logger.trace(`Starting ConnectionManager...`)
218
+ // Garbage collection of connections
219
+ this.disconnectorIntervalRef = setInterval(() => {
220
+ logger.trace('disconnectorInterval')
221
+ const LAST_USED_LIMIT = 20000
222
+ this.garbageCollectConnections(this.config.maxConnections, LAST_USED_LIMIT)
223
+ }, 5000)
224
+ if (!this.config.simulator) {
225
+ await this.webSocketConnector!.start()
226
+ const connectivityResponse = await this.webSocketConnector!.checkConnectivity()
227
+ const ownPeerDescriptor = peerDescriptorGeneratorCallback!(connectivityResponse)
228
+ this.ownPeerDescriptor = ownPeerDescriptor
229
+ this.webSocketConnector!.setOwnPeerDescriptor(ownPeerDescriptor)
230
+ this.webrtcConnector!.setOwnPeerDescriptor(ownPeerDescriptor)
231
+ }
232
+ }
233
+
234
+ public async stop(): Promise<void> {
235
+ if (this.state === ConnectionManagerState.STOPPED || this.state === ConnectionManagerState.STOPPING) {
236
+ return
237
+ }
238
+ this.state = ConnectionManagerState.STOPPING
239
+ logger.trace(`Stopping ConnectionManager`)
240
+ if (this.disconnectorIntervalRef) {
241
+ clearInterval(this.disconnectorIntervalRef)
242
+ }
243
+ if (!this.config.simulator) {
244
+ await this.webSocketConnector!.stop()
245
+ this.webSocketConnector = undefined
246
+ await this.webrtcConnector!.stop()
247
+ this.webrtcConnector = undefined
248
+ } else {
249
+ await this.simulatorConnector!.stop()
250
+ this.simulatorConnector = undefined
251
+ }
252
+
253
+ await Promise.all(Array.from(this.connections.values()).map((peer) => {
254
+ return new Promise<void>((resolve, _reject) => {
255
+
256
+ if (peer.isHandshakeCompleted()) {
257
+
258
+ this.gracefullyDisconnectAsync(peer.getPeerDescriptor()!, DisconnectMode.LEAVING)
259
+ .then(() => { resolve() })
260
+ .catch((e) => {
261
+ logger.error(e)
262
+ resolve()
263
+ })
264
+ } else {
265
+ logger.trace('handshake of connection not completed, force-closing')
266
+
267
+ waitForEvent3<ManagedConnectionEvents>(peer!, 'disconnected', 2000)
268
+ .then(() => {
269
+ logger.trace('resolving after receiving disconnected event from non-handshaked connection')
270
+ resolve()
271
+ })
272
+ .catch((e) => {
273
+ logger.trace('force-closing non-handshaked connection timed out ' + e)
274
+ resolve()
275
+ })
276
+
277
+ peer.close('OTHER')
278
+ }
279
+ })
280
+ }))
281
+
282
+ this.state = ConnectionManagerState.STOPPED
283
+ this.rpcCommunicator!.stop()
284
+ this.config.transportLayer = undefined
285
+ this.messageDuplicateDetector.clear()
286
+ this.locks.clear()
287
+ this.removeAllListeners()
288
+ if (!this.config.simulator) {
289
+
290
+ WEB_RTC_CLEANUP.cleanUp()
291
+ }
292
+ }
293
+
294
+ public getConnectionTo(id: PeerIDKey): ManagedConnection {
295
+ return this.connections.get(id)!
296
+ }
297
+
298
+ public getNumberOfLocalLockedConnections(): number {
299
+ return this.locks.getNumberOfLocalLockedConnections()
300
+ }
301
+
302
+ public getNumberOfRemoteLockedConnections(): number {
303
+ return this.locks.getNumberOfRemoteLockedConnections()
304
+ }
305
+
306
+ public getNumberOfWeakLockedConnections(): number {
307
+ return this.locks.getNumberOfWeakLockedConnections()
308
+ }
309
+
310
+ public async send(message: Message, doNotConnect = false, doNotMindStopped = false): Promise<void> {
311
+ if (this.state === ConnectionManagerState.STOPPED && !doNotMindStopped) {
312
+ return
313
+ }
314
+
315
+ const peerDescriptor = message.targetDescriptor!
316
+ if (isSamePeerDescriptor(peerDescriptor, this.ownPeerDescriptor!)) {
317
+ throw new Err.CannotConnectToSelf('Cannot send to self')
318
+ }
319
+ logger.trace(`Sending message to: ${peerDescriptor.kademliaId.toString()}`)
320
+ message = {
321
+ ...message,
322
+ targetDescriptor: message.targetDescriptor || peerDescriptor,
323
+ sourceDescriptor: message.sourceDescriptor || this.ownPeerDescriptor,
324
+ }
325
+ const hexId = keyFromPeerDescriptor(peerDescriptor)
326
+ let connection = this.connections.get(hexId)
327
+ if (!connection && !doNotConnect) {
328
+ connection = this.createConnection(peerDescriptor)
329
+ this.incomingConnectionCallback(connection)
330
+ } else if (!connection) {
331
+ throw new Err.SendFailed('No connection to target, doNotConnect flag is true')
332
+ }
333
+ const binary = Message.toBinary(message)
334
+ this.metrics.sendBytesPerSecond.record(binary.byteLength)
335
+ this.metrics.sendMessagesPerSecond.record(1)
336
+ return connection!.send(binary, doNotConnect)
337
+ }
338
+
339
+ private createConnection(peerDescriptor: PeerDescriptor): ManagedConnection {
340
+ if (this.simulatorConnector) {
341
+ return this.simulatorConnector!.connect(peerDescriptor)
342
+ } else if (peerDescriptor.websocket || this.ownPeerDescriptor!.websocket) {
343
+ return this.webSocketConnector!.connect(peerDescriptor)
344
+ }
345
+ return this.webrtcConnector!.connect(peerDescriptor)
346
+ }
347
+
348
+ public getConnection(peerDescriptor: PeerDescriptor): ManagedConnection | undefined {
349
+ const hexId = keyFromPeerDescriptor(peerDescriptor)
350
+ return this.connections.get(hexId)
351
+ }
352
+
353
+ public getPeerDescriptor(): PeerDescriptor {
354
+ return this.ownPeerDescriptor!
355
+ }
356
+
357
+ public hasConnection(peerDescriptor: PeerDescriptor): boolean {
358
+ const hexId = keyFromPeerDescriptor(peerDescriptor)
359
+ return this.connections.has(hexId)
360
+ }
361
+
362
+ public hasLocalLockedConnection(peerDescriptor: PeerDescriptor, _serviceId?: ServiceId): boolean {
363
+ const hexId = keyFromPeerDescriptor(peerDescriptor)
364
+ return this.locks.isLocalLocked(hexId)
365
+ }
366
+
367
+ public hasRemoteLockedConnection(peerDescriptor: PeerDescriptor, _serviceId?: ServiceId): boolean {
368
+ const hexId = keyFromPeerDescriptor(peerDescriptor)
369
+ return this.locks.isRemoteLocked(hexId)
370
+ }
371
+
372
+ public canConnect(peerDescriptor: PeerDescriptor, _ip: string, _port: number): boolean {
373
+ // Perhaps the connection's state should be checked here
374
+ return !this.hasConnection(peerDescriptor) // TODO: Add port range check
375
+ }
376
+
377
+ public handleMessage(message: Message): void {
378
+ logger.trace('Received message of type ' + message!.messageType)
379
+ if (message!.messageType !== MessageType.RPC) {
380
+ logger.trace('Filtered out non-RPC message of type ' + message!.messageType)
381
+ return
382
+ }
383
+ if (this.messageDuplicateDetector.isMostLikelyDuplicate(message.messageId)) {
384
+ logger.trace('handleMessage filtered duplicate ' + this.config.nodeName + ', '
385
+ + message.sourceDescriptor?.nodeName + ' ' + message.serviceId + ' ' + message.messageId)
386
+ return
387
+ }
388
+ this.messageDuplicateDetector.add(message.messageId, message.sourceDescriptor!.nodeName!, message)
389
+ if (message.serviceId === this.serviceId) {
390
+ this.rpcCommunicator?.handleMessageFromPeer(message)
391
+ } else {
392
+ logger.trace('emit "message" ' + this.config.nodeName + ', ' + message.sourceDescriptor?.nodeName
393
+ + ' ' + message.serviceId + ' ' + message.messageId)
394
+ this.emit('message', message)
395
+ }
396
+ }
397
+
398
+ private onData(data: Uint8Array, peerDescriptor: PeerDescriptor): void {
399
+ if (this.state === ConnectionManagerState.STOPPED) {
400
+ return
401
+ }
402
+ this.metrics.receiveBytesPerSecond.record(data.byteLength)
403
+ this.metrics.receiveMessagesPerSecond.record(1)
404
+ let message: Message | undefined
405
+ try {
406
+ message = Message.fromBinary(data)
407
+ logger.trace(`${this.config.nodeName} received protojson: ${protoToString(message, Message)}`)
408
+ } catch (e) {
409
+ logger.debug(`Parsing incoming data into Message failed: ${e}`)
410
+ return
411
+ }
412
+ message.sourceDescriptor = peerDescriptor
413
+ try {
414
+ this.handleMessage(message)
415
+ } catch (e) {
416
+ logger.debug(`Handling incoming data failed: ${e}`)
417
+ }
418
+ }
419
+
420
+ private onConnected = (connection: ManagedConnection) => {
421
+ const peerDescriptor = connection.getPeerDescriptor()!
422
+ this.emit('connected', peerDescriptor)
423
+ logger.trace(' ' + this.ownPeerDescriptor?.nodeName + ', ' + peerDescriptor.nodeName + ' onConnected() ' + connection.connectionType)
424
+ this.onConnectionCountChange()
425
+ }
426
+
427
+ private onDisconnected = (connection: ManagedConnection, disconnectionType: DisconnectionType) => {
428
+ logger.trace(' ' + this.config.nodeName + ', ' + connection.getPeerDescriptor()?.nodeName +
429
+ ' onDisconnected() ' + disconnectionType)
430
+
431
+ const hexKey = keyFromPeerDescriptor(connection.getPeerDescriptor()!)
432
+ const storedConnection = this.connections.get(hexKey)
433
+ if (storedConnection && storedConnection.connectionId.equals(connection.connectionId)) {
434
+ this.locks.clearAllLocks(hexKey)
435
+ this.connections.delete(hexKey)
436
+ logger.trace(' ' + this.config.nodeName + ', ' + connection.getPeerDescriptor()?.nodeName +
437
+ ' deleted connection in onDisconnected() ' + disconnectionType)
438
+ this.emit('disconnected', connection.getPeerDescriptor()!, disconnectionType)
439
+ this.onConnectionCountChange()
440
+ } else {
441
+ logger.trace(' ' + this.config.nodeName + ', ' + connection.getPeerDescriptor()?.nodeName +
442
+ ' onDisconnected() did nothing, no such connection in connectionManager')
443
+ if (storedConnection) {
444
+ logger.trace(this.config.nodeName + ', ' + connection.getPeerDescriptor()?.nodeName +
445
+ ' connectionIds do not match ' + storedConnection.connectionId + ' ' + connection.connectionId)
446
+ }
447
+ }
448
+
449
+ }
450
+
451
+ private incomingConnectionCallback(connection: ManagedConnection): boolean {
452
+ if (this.state === ConnectionManagerState.STOPPED) {
453
+ return false
454
+ }
455
+ logger.trace('incomingConnectionCallback() objectId ' + connection.objectId)
456
+ connection.offeredAsIncoming = true
457
+ if (!this.acceptIncomingConnection(connection)) {
458
+ return false
459
+ }
460
+ connection.on('managedData', this.onData)
461
+ connection.on('disconnected', (disconnectionType: DisconnectionType, _code?: number, _reason?: string) => {
462
+ this.onDisconnected(connection, disconnectionType)
463
+ })
464
+ this.emit('newConnection', connection)
465
+ if (connection.isHandshakeCompleted()) {
466
+ this.onConnected(connection)
467
+ } else {
468
+ connection.once('handshakeCompleted', (_peerDescriptor: PeerDescriptor) => {
469
+ this.onConnected(connection)
470
+ })
471
+ }
472
+ return true
473
+ }
474
+
475
+ private acceptIncomingConnection(newConnection: ManagedConnection): boolean {
476
+ logger.trace(' ' + this.config.nodeName + ', ' + newConnection.getPeerDescriptor()?.nodeName + ' acceptIncomingConnection()')
477
+ const newPeerID = peerIdFromPeerDescriptor(newConnection.getPeerDescriptor()!)
478
+ const hexKey = keyFromPeerDescriptor(newConnection.getPeerDescriptor()!)
479
+ if (this.connections.has(hexKey)) {
480
+ if (newPeerID.hasSmallerHashThan(peerIdFromPeerDescriptor(this.ownPeerDescriptor!))) {
481
+ logger.trace(' ' + this.config.nodeName + ', ' + newConnection.getPeerDescriptor()?.nodeName +
482
+ ' acceptIncomingConnection() replace current connection')
483
+ // replace the current connection
484
+ const oldConnection = this.connections.get(newPeerID.toKey())!
485
+ logger.trace('replaced: ' + this.config.nodeName + ', ' + newConnection.getPeerDescriptor()?.nodeName + ' ')
486
+ const buffer = oldConnection!.stealOutputBuffer()
487
+
488
+ for (const data of buffer) {
489
+ newConnection.sendNoWait(data)
490
+ }
491
+
492
+ oldConnection!.reportBufferSentByOtherConnection()
493
+ oldConnection.replacedByOtherConnection = true
494
+ } else {
495
+ newConnection.rejectedAsIncoming = true
496
+ return false
497
+ }
498
+ }
499
+
500
+ logger.trace(' ' + this.ownPeerDescriptor?.nodeName + ', ' + newConnection.getPeerDescriptor()?.nodeName +
501
+ ' added to connections at acceptIncomingConnection')
502
+ this.connections.set(hexKey, newConnection)
503
+
504
+ return true
505
+ }
506
+
507
+ private async closeConnection(peerDescriptor: PeerDescriptor, disconnectionType: DisconnectionType, reason?: string): Promise<void> {
508
+ logger.trace(' ' + this.ownPeerDescriptor?.nodeName + ', ' + peerDescriptor.nodeName + ' ' + 'closeConnection()')
509
+ const id = keyFromPeerDescriptor(peerDescriptor)
510
+ this.locks.clearAllLocks(id)
511
+ if (this.connections.has(id)) {
512
+ logger.trace(' ' + this.ownPeerDescriptor?.nodeName + ', ' + peerDescriptor.nodeName + ' ' +
513
+ 'closeConnection() this.connections had the id')
514
+ logger.trace(`Closeconnection called to Peer ${id}${reason ? `: ${reason}` : ''}`)
515
+ const connectionToClose = this.connections.get(id)!
516
+ logger.trace('disconnecting: ' + this.config.nodeName + ', ' + connectionToClose.getPeerDescriptor()?.nodeName)
517
+ logger.trace(' ' + this.ownPeerDescriptor?.nodeName + ', ' + peerDescriptor.nodeName + ' ' +
518
+ 'closeConnection() calling connection.close()')
519
+ await connectionToClose.close(disconnectionType)
520
+ logger.trace(' ' + this.ownPeerDescriptor?.nodeName + ', ' + peerDescriptor.nodeName + ' ' +
521
+ 'closeConnection() connection.close() called')
522
+
523
+ } else {
524
+ logger.trace(' ' + this.ownPeerDescriptor?.nodeName + ', ' + peerDescriptor.nodeName + ' ' +
525
+ 'closeConnection() this.connections did not have the id')
526
+ this.emit('disconnected', peerDescriptor, 'OTHER')
527
+ }
528
+ }
529
+
530
+ public lockConnection(targetDescriptor: PeerDescriptor, serviceId: ServiceId): void {
531
+ if (this.state === ConnectionManagerState.STOPPED || isSamePeerDescriptor(targetDescriptor, this.ownPeerDescriptor!)) {
532
+ return
533
+ }
534
+ const hexKey = keyFromPeerDescriptor(targetDescriptor)
535
+ const remoteConnectionLocker = new RemoteConnectionLocker(
536
+ this.ownPeerDescriptor!,
537
+ targetDescriptor,
538
+ ConnectionManager.PROTOCOL_VERSION,
539
+ toProtoRpcClient(new ConnectionLockerClient(this.rpcCommunicator!.getRpcClientTransport()))
540
+ )
541
+ this.locks.addLocalLocked(hexKey, serviceId)
542
+ remoteConnectionLocker.lockRequest(serviceId)
543
+ .then((_accepted) => logger.trace('LockRequest successful'))
544
+ .catch((err) => { logger.debug(err) })
545
+ }
546
+
547
+ public unlockConnection(targetDescriptor: PeerDescriptor, serviceId: ServiceId): void {
548
+ if (this.state === ConnectionManagerState.STOPPED || isSamePeerDescriptor(targetDescriptor, this.ownPeerDescriptor!)) {
549
+ return
550
+ }
551
+ const hexKey = keyFromPeerDescriptor(targetDescriptor)
552
+ this.locks.removeLocalLocked(hexKey, serviceId)
553
+ const remoteConnectionLocker = new RemoteConnectionLocker(
554
+ this.ownPeerDescriptor!,
555
+ targetDescriptor,
556
+ ConnectionManager.PROTOCOL_VERSION,
557
+ toProtoRpcClient(new ConnectionLockerClient(this.rpcCommunicator!.getRpcClientTransport()))
558
+ )
559
+ if (this.connections.has(hexKey)) {
560
+ remoteConnectionLocker.unlockRequest(serviceId)
561
+ }
562
+ }
563
+
564
+ public weakLockConnection(targetDescriptor: PeerDescriptor): void {
565
+ if (this.state === ConnectionManagerState.STOPPED || isSamePeerDescriptor(targetDescriptor, this.ownPeerDescriptor!)) {
566
+ return
567
+ }
568
+ const hexKey = keyFromPeerDescriptor(targetDescriptor)
569
+ this.locks.addWeakLocked(hexKey)
570
+ }
571
+
572
+ public weakUnlockConnection(targetDescriptor: PeerDescriptor): void {
573
+ if (this.state === ConnectionManagerState.STOPPED || isSamePeerDescriptor(targetDescriptor, this.ownPeerDescriptor!)) {
574
+ return
575
+ }
576
+ const hexKey = keyFromPeerDescriptor(targetDescriptor)
577
+ this.locks.removeWeakLocked(hexKey)
578
+
579
+ }
580
+
581
+ private async gracefullyDisconnectAsync(targetDescriptor: PeerDescriptor, disconnectMode: DisconnectMode): Promise<void> {
582
+
583
+ const connection = this.connections.get(peerIdFromPeerDescriptor(targetDescriptor).toKey())
584
+
585
+ if (!connection) {
586
+ logger.debug('gracefullyDisconnectedAsync() tried on a non-existing connection')
587
+ return
588
+ }
589
+
590
+ const promise = new Promise<void>((resolve, _reject) => {
591
+ // eslint-disable-next-line promise/catch-or-return
592
+ waitForEvent3<ManagedConnectionEvents>(connection!, 'disconnected', 2000).then(() => {
593
+ logger.trace('disconnected event received in gracefullyDisconnectAsync()')
594
+ return
595
+ })
596
+ .catch((e) => {
597
+ logger.trace('force-closing connection after timeout ' + e)
598
+ connection.close('OTHER')
599
+ })
600
+ .finally(() => {
601
+ logger.trace('resolving after receiving disconnected event')
602
+ resolve()
603
+ })
604
+ })
605
+
606
+ this.doGracefullyDisconnectAsync(targetDescriptor, disconnectMode)
607
+ .then(() => { return })
608
+ .catch((e) => {
609
+ logger.error(e)
610
+ })
611
+
612
+ await promise
613
+ }
614
+
615
+ private async doGracefullyDisconnectAsync(targetDescriptor: PeerDescriptor, disconnectMode: DisconnectMode): Promise<void> {
616
+ logger.trace(' ' + this.ownPeerDescriptor?.nodeName + ', ' + targetDescriptor.nodeName + ' gracefullyDisconnectAsync()')
617
+ const remoteConnectionLocker = new RemoteConnectionLocker(
618
+ this.ownPeerDescriptor!,
619
+ targetDescriptor,
620
+ ConnectionManager.PROTOCOL_VERSION,
621
+ toProtoRpcClient(new ConnectionLockerClient(this.rpcCommunicator!.getRpcClientTransport()))
622
+ )
623
+ try {
624
+ await remoteConnectionLocker.gracefulDisconnect(disconnectMode)
625
+ } catch (ex) {
626
+ logger.debug(' ' + this.ownPeerDescriptor?.nodeName + ', ' + targetDescriptor.nodeName +
627
+ ' remoteConnectionLocker.gracefulDisconnect() failed' + ex)
628
+ }
629
+ }
630
+
631
+ public getAllConnectionPeerDescriptors(): PeerDescriptor[] {
632
+ return Array.from(this.connections.values())
633
+ .filter((managedConnection: ManagedConnection) => managedConnection.isHandshakeCompleted())
634
+ .map((managedConnection: ManagedConnection) => managedConnection.getPeerDescriptor()! as PeerDescriptor)
635
+ }
636
+
637
+ // IConnectionLocker server implementation
638
+ private async lockRequest(lockRequest: LockRequest, _context: ServerCallContext): Promise<LockResponse> {
639
+ const remotePeerId = peerIdFromPeerDescriptor(lockRequest.peerDescriptor!)
640
+ if (isSamePeerDescriptor(lockRequest.peerDescriptor!, this.ownPeerDescriptor!)) {
641
+ const response: LockResponse = {
642
+ accepted: false
643
+ }
644
+ return response
645
+ }
646
+ this.locks.addRemoteLocked(remotePeerId.toKey(), lockRequest.serviceId)
647
+ const response: LockResponse = {
648
+ accepted: true
649
+ }
650
+ return response
651
+ }
652
+
653
+ // IConnectionLocker server implementation
654
+ private async unlockRequest(unlockRequest: UnlockRequest, _context: ServerCallContext): Promise<Empty> {
655
+ const hexKey = keyFromPeerDescriptor(unlockRequest.peerDescriptor!)
656
+ this.locks.removeRemoteLocked(hexKey, unlockRequest.serviceId)
657
+ return {}
658
+ }
659
+
660
+ // IConnectionLocker server implementation
661
+ private async gracefulDisconnect(disconnectNotice: DisconnectNotice, _context: ServerCallContext): Promise<Empty> {
662
+ logger.trace(' ' + this.config.nodeName + ', ' + disconnectNotice.peerDescriptor?.nodeName
663
+ + ' received gracefulDisconnect notice')
664
+
665
+ if (disconnectNotice.disconnecMode === DisconnectMode.LEAVING) {
666
+ this.closeConnection(disconnectNotice.peerDescriptor!, 'INCOMING_GRACEFUL_LEAVE', 'graceful leave notified')
667
+ } else {
668
+ this.closeConnection(disconnectNotice.peerDescriptor!, 'INCOMING_GRACEFUL_DISCONNECT', 'graceful disconnect notified')
669
+ }
670
+ return {}
671
+ }
672
+
673
+ private onConnectionCountChange() {
674
+ this.metrics.connectionAverageCount.record(this.connections.size)
675
+ }
676
+ }