@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,53 @@
1
+ import { Message } from '../../proto/packages/dht/protos/DhtRpc'
2
+
3
+ type QueueEntry = [timeStamp: number, value: string, senderId: string, message?: Message]
4
+
5
+ export class DuplicateDetector {
6
+
7
+ private values: Set<string> = new Set()
8
+ private queue: Array<QueueEntry> = []
9
+ private maxAge: number
10
+ private maxNumberOfValues: number
11
+
12
+ constructor(
13
+ maxNumberOfValues: number,
14
+ maxAgeInSeconds: number
15
+ ) {
16
+ this.maxNumberOfValues = maxNumberOfValues
17
+ this.maxAge = maxAgeInSeconds * 1000
18
+ }
19
+
20
+ public add(value: string, senderId: string, message?: Message): void {
21
+ this.values.add(value)
22
+ if (message) {
23
+ this.queue.push([Date.now(), value, senderId, message])
24
+ } else {
25
+ this.queue.push([Date.now(), value, senderId])
26
+ }
27
+ this.cleanUp()
28
+ }
29
+
30
+ public isMostLikelyDuplicate(value: string): boolean {
31
+ return this.values.has(value)
32
+ }
33
+
34
+ private cleanUp(): void {
35
+ const currentTime = Date.now()
36
+
37
+ while (this.queue.length > 0 && (this.queue.length > this.maxNumberOfValues ||
38
+ (currentTime - this.queue[0][0]) > this.maxAge)) {
39
+ const oldestEntry = this.queue.shift()
40
+ this.values.delete(oldestEntry![1])
41
+ }
42
+ }
43
+
44
+ public size(): number {
45
+ return this.values.size
46
+ }
47
+
48
+ public clear(): void {
49
+ this.values.clear()
50
+ this.queue = []
51
+ }
52
+
53
+ }
@@ -0,0 +1,115 @@
1
+ import { PeerDescriptor, RouteMessageWrapper } from '../../proto/packages/dht/protos/DhtRpc'
2
+ import { v4 } from 'uuid'
3
+ import { DhtRpcOptions } from '../../rpc-protocol/DhtRpcOptions'
4
+ import {
5
+ isSamePeerDescriptor,
6
+ keyFromPeerDescriptor,
7
+ peerIdFromPeerDescriptor
8
+ } from '../../helpers/peerIdFromPeerDescriptor'
9
+ import { IRoutingServiceClient } from '../../proto/packages/dht/protos/DhtRpc.client'
10
+ import { Remote } from '../contact/Remote'
11
+ import { Logger } from '@streamr/utils'
12
+
13
+ const logger = new Logger(module)
14
+
15
+ export class RemoteRouter extends Remote<IRoutingServiceClient> {
16
+
17
+ async routeMessage(params: RouteMessageWrapper): Promise<boolean> {
18
+ const message: RouteMessageWrapper = {
19
+ destinationPeer: params.destinationPeer,
20
+ sourcePeer: params.sourcePeer,
21
+ previousPeer: params.previousPeer,
22
+ message: params.message,
23
+ requestId: params.requestId || v4(),
24
+ reachableThrough: params.reachableThrough || [],
25
+ routingPath: params.routingPath
26
+ }
27
+ const options: DhtRpcOptions = {
28
+ sourceDescriptor: params.previousPeer as PeerDescriptor,
29
+ targetDescriptor: this.peerDescriptor as PeerDescriptor,
30
+ timeout: 10000
31
+ }
32
+ try {
33
+ logger.trace('calling dhtClient.routeMessage')
34
+ const ack = await this.client.routeMessage(message, options)
35
+ logger.trace('dhtClient.routeMessage returned')
36
+ // Success signal if sent to destination and error includes duplicate
37
+ if (
38
+ isSamePeerDescriptor(params.destinationPeer!, this.peerDescriptor)
39
+ && ack.error.includes('duplicate')
40
+ ) {
41
+ return true
42
+ } else if (ack.error!.length > 0) {
43
+ return false
44
+ }
45
+ } catch (err) {
46
+ const fromNode = params.previousPeer ?
47
+ peerIdFromPeerDescriptor(params.previousPeer) : keyFromPeerDescriptor(params.sourcePeer!)
48
+ logger.debug(`Failed to send routeMessage from ${fromNode} to ${this.peerId.toKey()} with: ${err}`)
49
+ return false
50
+ }
51
+ return true
52
+ }
53
+
54
+ async forwardMessage(params: RouteMessageWrapper): Promise<boolean> {
55
+ const message: RouteMessageWrapper = {
56
+ destinationPeer: params.destinationPeer,
57
+ sourcePeer: params.sourcePeer,
58
+ previousPeer: params.previousPeer,
59
+ message: params.message,
60
+ requestId: params.requestId || v4(),
61
+ reachableThrough: params.reachableThrough || [],
62
+ routingPath: params.routingPath
63
+ }
64
+ const options: DhtRpcOptions = {
65
+ sourceDescriptor: params.previousPeer as PeerDescriptor,
66
+ targetDescriptor: this.peerDescriptor as PeerDescriptor,
67
+ timeout: 10000
68
+ }
69
+ try {
70
+ const ack = await this.client.forwardMessage(message, options)
71
+ if (ack.error!.length > 0) {
72
+ return false
73
+ }
74
+ } catch (err) {
75
+ const fromNode = params.previousPeer ?
76
+ keyFromPeerDescriptor(params.previousPeer) : keyFromPeerDescriptor(params.sourcePeer!)
77
+
78
+ logger.debug(
79
+ `Failed to send forwardMessage from ${fromNode} to ${this.peerId.toKey()} with: ${err}`
80
+ )
81
+ return false
82
+ }
83
+ return true
84
+ }
85
+
86
+ async findRecursively(params: RouteMessageWrapper): Promise<boolean> {
87
+ const message: RouteMessageWrapper = {
88
+ destinationPeer: params.destinationPeer,
89
+ sourcePeer: params.sourcePeer,
90
+ previousPeer: params.previousPeer,
91
+ message: params.message,
92
+ requestId: params.requestId || v4(),
93
+ reachableThrough: params.reachableThrough || [],
94
+ routingPath: params.routingPath
95
+ }
96
+ const options: DhtRpcOptions = {
97
+ sourceDescriptor: params.previousPeer as PeerDescriptor,
98
+ targetDescriptor: this.peerDescriptor as PeerDescriptor,
99
+ timeout: 10000
100
+ }
101
+ try {
102
+ const ack = await this.client.findRecursively(message, options)
103
+ if (ack.error!.length > 0) {
104
+ logger.debug('Next hop responded with error ' + ack.error)
105
+ return false
106
+ }
107
+ } catch (err) {
108
+ const fromNode = params.previousPeer ? keyFromPeerDescriptor(params.previousPeer) : keyFromPeerDescriptor(params.sourcePeer!)
109
+ logger.debug(`Failed to send recursiveFind message from ${fromNode} to ${this.peerId.toKey()} with: ${err}`)
110
+ return false
111
+ }
112
+ return true
113
+ }
114
+
115
+ }
@@ -0,0 +1,266 @@
1
+ import { Message, PeerDescriptor, RouteMessageAck, RouteMessageWrapper } from '../../proto/packages/dht/protos/DhtRpc'
2
+ import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
3
+ import { keyFromPeerDescriptor, peerIdFromPeerDescriptor } from '../../helpers/peerIdFromPeerDescriptor'
4
+ import { RoutingMode, RoutingSession, RoutingSessionEvents } from './RoutingSession'
5
+ import { Logger, raceEvents3 } from '@streamr/utils'
6
+ import { RoutingRpcCommunicator } from '../../transport/RoutingRpcCommunicator'
7
+ import { PeerID, PeerIDKey } from '../../helpers/PeerID'
8
+ import { DuplicateDetector } from './DuplicateDetector'
9
+ import { ConnectionManager } from '../../connection/ConnectionManager'
10
+ import { DhtPeer } from '../DhtPeer'
11
+ import { v4 } from 'uuid'
12
+ import { IRoutingService } from '../../proto/packages/dht/protos/DhtRpc.server'
13
+
14
+ export const createRouteMessageAck = (routedMessage: RouteMessageWrapper, error?: string): RouteMessageAck => {
15
+ const ack: RouteMessageAck = {
16
+ requestId: routedMessage.requestId,
17
+ destinationPeer: routedMessage.sourcePeer,
18
+ sourcePeer: routedMessage.destinationPeer,
19
+ error: error ? error : ''
20
+ }
21
+ return ack
22
+ }
23
+
24
+ export enum RoutingErrors {
25
+ NO_CANDIDATES_FOUND = 'No routing candidates found',
26
+ STOPPED = 'DhtNode Stopped'
27
+ }
28
+
29
+ export interface RouterConfig {
30
+ rpcCommunicator: RoutingRpcCommunicator
31
+ ownPeerDescriptor: PeerDescriptor
32
+ ownPeerId: PeerID
33
+ connections: Map<PeerIDKey, DhtPeer>
34
+ addContact: (contact: PeerDescriptor, setActive?: boolean) => void
35
+ serviceId: string
36
+ connectionManager?: ConnectionManager
37
+ }
38
+
39
+ interface ForwardingTableEntry {
40
+ timeout: NodeJS.Timeout
41
+ peerDescriptors: PeerDescriptor[]
42
+ }
43
+
44
+ interface IRouterFunc {
45
+ doRouteMessage(routedMessage: RouteMessageWrapper, mode: RoutingMode, excludedPeer?: PeerDescriptor): RouteMessageAck
46
+ send(msg: Message, reachableThrough: PeerDescriptor[]): Promise<void>
47
+ checkDuplicate(messageId: string): boolean
48
+ addToDuplicateDetector(messageId: string, senderId: string, message?: Message): void
49
+ addRoutingSession(session: RoutingSession): void
50
+ removeRoutingSession(sessionId: string): void
51
+ stop(): void
52
+ }
53
+
54
+ export interface IRouter extends Omit<IRoutingService, 'findRecursively'>, IRouterFunc {}
55
+
56
+ const logger = new Logger(module)
57
+
58
+ export class Router implements IRouter {
59
+ private readonly rpcCommunicator: RoutingRpcCommunicator
60
+ private readonly ownPeerDescriptor: PeerDescriptor
61
+ private readonly ownPeerId: PeerID
62
+ private readonly connections: Map<PeerIDKey, DhtPeer>
63
+ private readonly addContact: (contact: PeerDescriptor, setActive?: boolean) => void
64
+ private readonly serviceId: string
65
+ private readonly connectionManager?: ConnectionManager
66
+ private readonly forwardingTable: Map<string, ForwardingTableEntry> = new Map()
67
+ private ongoingRoutingSessions: Map<string, RoutingSession> = new Map()
68
+ private readonly routerDuplicateDetector: DuplicateDetector = new DuplicateDetector(100000, 100)
69
+ private stopped = false
70
+
71
+ constructor(config: RouterConfig) {
72
+ this.rpcCommunicator = config.rpcCommunicator
73
+ this.ownPeerDescriptor = config.ownPeerDescriptor
74
+ this.ownPeerId = config.ownPeerId
75
+ this.connections = config.connections
76
+ this.addContact = config.addContact
77
+ this.serviceId = config.serviceId
78
+ this.connectionManager = config.connectionManager
79
+ this.rpcCommunicator.registerRpcMethod(RouteMessageWrapper, RouteMessageAck, 'forwardMessage',
80
+ (forwardMessage: RouteMessageWrapper, context) => this.forwardMessage(forwardMessage, context))
81
+ this.rpcCommunicator.registerRpcMethod(RouteMessageWrapper, RouteMessageAck, 'routeMessage',
82
+ (routedMessage: RouteMessageWrapper, context) => this.routeMessage(routedMessage, context))
83
+ }
84
+
85
+ public async send(msg: Message, reachableThrough: PeerDescriptor[]): Promise<void> {
86
+ msg.sourceDescriptor = this.ownPeerDescriptor
87
+ const targetPeerDescriptor = msg.targetDescriptor!
88
+ const forwardingEntry = this.forwardingTable.get(keyFromPeerDescriptor(targetPeerDescriptor))
89
+ if (forwardingEntry && forwardingEntry.peerDescriptors.length > 0) {
90
+ const forwardingPeer = forwardingEntry.peerDescriptors[0]
91
+ const forwardedMessage: RouteMessageWrapper = {
92
+ message: msg,
93
+ requestId: v4(),
94
+ destinationPeer: forwardingPeer,
95
+ sourcePeer: this.ownPeerDescriptor!,
96
+ reachableThrough,
97
+ routingPath: []
98
+ }
99
+ this.doRouteMessage(forwardedMessage, RoutingMode.FORWARD)
100
+ } else {
101
+ const routedMessage: RouteMessageWrapper = {
102
+ message: msg,
103
+ requestId: v4(),
104
+ destinationPeer: targetPeerDescriptor,
105
+ sourcePeer: this.ownPeerDescriptor!,
106
+ reachableThrough,
107
+ routingPath: []
108
+ }
109
+ this.doRouteMessage(routedMessage, RoutingMode.ROUTE)
110
+ }
111
+ }
112
+
113
+ public doRouteMessage(routedMessage: RouteMessageWrapper, mode = RoutingMode.ROUTE, excludedPeer?: PeerDescriptor): RouteMessageAck {
114
+ if (this.stopped) {
115
+ return createRouteMessageAck(routedMessage, RoutingErrors.STOPPED)
116
+ }
117
+ logger.trace(`Peer ${this.ownPeerId.value} routing message ${routedMessage.requestId}
118
+ from ${routedMessage.sourcePeer?.kademliaId} to ${routedMessage.destinationPeer?.kademliaId}`)
119
+ routedMessage.routingPath.push(this.ownPeerDescriptor!)
120
+ const session = this.createRoutingSession(routedMessage, mode, excludedPeer)
121
+ this.addRoutingSession(session)
122
+ try {
123
+ // eslint-disable-next-line promise/catch-or-return
124
+ logger.trace('starting to raceEvents from routingSession: ' + session.sessionId)
125
+ raceEvents3<RoutingSessionEvents>(session, ['routingSucceeded', 'partialSuccess', 'routingFailed', 'stopped', 'noCandidatesFound'], 10000)
126
+ .then(() => {
127
+ logger.trace('raceEvents ended from routingSession: ' + session.sessionId)
128
+ this.removeRoutingSession(session.sessionId)
129
+ })
130
+ .catch(() => {
131
+ logger.trace('raceEvents timed out for routingSession ' + session.sessionId)
132
+ this.removeRoutingSession(session.sessionId)
133
+ })
134
+ session.start()
135
+ } catch (e) {
136
+ if (peerIdFromPeerDescriptor(routedMessage.sourcePeer!).equals(this.ownPeerId!)) {
137
+ logger.warn(
138
+ `Failed to send (routeMessage: ${this.serviceId}) to ${keyFromPeerDescriptor(routedMessage.destinationPeer!)}: ${e}`
139
+ )
140
+ }
141
+ return createRouteMessageAck(routedMessage, RoutingErrors.NO_CANDIDATES_FOUND)
142
+ }
143
+ return createRouteMessageAck(routedMessage)
144
+ }
145
+
146
+ private createRoutingSession(routedMessage: RouteMessageWrapper, mode: RoutingMode, excludedPeer?: PeerDescriptor): RoutingSession {
147
+ const excludedPeers = routedMessage.routingPath.map((descriptor) => peerIdFromPeerDescriptor(descriptor))
148
+ if (excludedPeer) {
149
+ excludedPeers.push(peerIdFromPeerDescriptor(excludedPeer))
150
+ }
151
+ logger.trace(' routing session created with connections: ' + this.connections.size )
152
+ return new RoutingSession(
153
+ this.rpcCommunicator,
154
+ this.ownPeerDescriptor!,
155
+ routedMessage,
156
+ this.connections,
157
+ this.ownPeerId!.equals(peerIdFromPeerDescriptor(routedMessage.sourcePeer!)) ? 2 : 1,
158
+ mode,
159
+ undefined,
160
+ excludedPeers
161
+ )
162
+ }
163
+
164
+ public checkDuplicate(messageId: string): boolean {
165
+ return this.routerDuplicateDetector.isMostLikelyDuplicate(messageId)
166
+ }
167
+
168
+ public addToDuplicateDetector(messageId: string, senderId: string, message?: Message): void {
169
+ this.routerDuplicateDetector.add(messageId, senderId, message)
170
+ }
171
+
172
+ public addRoutingSession(session: RoutingSession): void {
173
+ this.ongoingRoutingSessions.set(session.sessionId, session)
174
+ }
175
+
176
+ public removeRoutingSession(sessionId: string): void {
177
+ this.ongoingRoutingSessions.delete(sessionId)
178
+ }
179
+
180
+ public stop(): void {
181
+ this.stopped = true
182
+ this.ongoingRoutingSessions.forEach((session, _id) => {
183
+ session.stop()
184
+ })
185
+ this.ongoingRoutingSessions.clear()
186
+ this.forwardingTable.forEach((entry) => {
187
+ clearTimeout(entry.timeout)
188
+ })
189
+ this.forwardingTable.clear()
190
+ this.routerDuplicateDetector.clear()
191
+ }
192
+
193
+ // IRoutingService method
194
+ async routeMessage(routedMessage: RouteMessageWrapper, _context: ServerCallContext): Promise<RouteMessageAck> {
195
+ if (this.stopped) {
196
+ return createRouteMessageAck(routedMessage, 'routeMessage() service is not running')
197
+ } else if (this.routerDuplicateDetector.isMostLikelyDuplicate(routedMessage.requestId)) {
198
+ logger.trace(`Peer ${this.ownPeerId?.value} routing message ${routedMessage.requestId}
199
+ from ${routedMessage.sourcePeer!.kademliaId} to ${routedMessage.destinationPeer!.kademliaId} is likely a duplicate`)
200
+ return createRouteMessageAck(routedMessage, 'message given to routeMessage() service is likely a duplicate')
201
+ }
202
+ logger.trace(`Processing received routeMessage ${routedMessage.requestId}`)
203
+ this.addContact(routedMessage.sourcePeer!, true)
204
+ this.addToDuplicateDetector(routedMessage.requestId, keyFromPeerDescriptor(routedMessage.sourcePeer!))
205
+ if (this.ownPeerId!.equals(peerIdFromPeerDescriptor(routedMessage.destinationPeer!))) {
206
+ logger.trace(`${this.ownPeerDescriptor.nodeName} routing message targeted to self ${routedMessage.requestId}`)
207
+ this.setForwardingEntries(routedMessage)
208
+ this.connectionManager?.handleMessage(routedMessage.message!)
209
+ return createRouteMessageAck(routedMessage)
210
+ } else {
211
+ return this.doRouteMessage(routedMessage)
212
+ }
213
+ }
214
+
215
+ private setForwardingEntries(routedMessage: RouteMessageWrapper): void {
216
+ const reachableThroughWithoutSelf = routedMessage.reachableThrough.filter((peer) => {
217
+ return !peerIdFromPeerDescriptor(peer).equals(this.ownPeerId!)
218
+ })
219
+
220
+ if (reachableThroughWithoutSelf.length > 0) {
221
+ const sourceKey = keyFromPeerDescriptor(routedMessage.sourcePeer!)
222
+ if (this.forwardingTable.has(sourceKey)) {
223
+ const oldEntry = this.forwardingTable.get(sourceKey)
224
+ clearTimeout(oldEntry!.timeout)
225
+ this.forwardingTable.delete(sourceKey)
226
+ }
227
+ const forwardingEntry: ForwardingTableEntry = {
228
+ peerDescriptors: reachableThroughWithoutSelf,
229
+ timeout: setTimeout(() => {
230
+ this.forwardingTable.delete(sourceKey)
231
+ }, 10000)
232
+ }
233
+ this.forwardingTable.set(sourceKey, forwardingEntry)
234
+ }
235
+ }
236
+
237
+ // IRoutingService method
238
+ async forwardMessage(forwardMessage: RouteMessageWrapper, _context: ServerCallContext): Promise<RouteMessageAck> {
239
+ if (this.stopped) {
240
+ return createRouteMessageAck(forwardMessage, 'forwardMessage() service is not running')
241
+ } else if (this.routerDuplicateDetector.isMostLikelyDuplicate(forwardMessage.requestId)) {
242
+ logger.trace(`Peer ${this.ownPeerId.value} forwarding message ${forwardMessage.requestId}
243
+ from ${forwardMessage.sourcePeer?.kademliaId} to ${forwardMessage.destinationPeer?.kademliaId} is likely a duplicate`)
244
+ return createRouteMessageAck(forwardMessage, 'message given to forwardMessage() service is likely a duplicate')
245
+ }
246
+ logger.trace(`Processing received forward routeMessage ${forwardMessage.requestId}`)
247
+ this.addContact(forwardMessage.sourcePeer!, true)
248
+ this.addToDuplicateDetector(forwardMessage.requestId, keyFromPeerDescriptor(forwardMessage.sourcePeer!))
249
+ if (this.ownPeerId.equals(peerIdFromPeerDescriptor(forwardMessage.destinationPeer!))) {
250
+ return this.forwardToDestination(forwardMessage)
251
+ } else {
252
+ return this.doRouteMessage(forwardMessage, RoutingMode.FORWARD)
253
+ }
254
+ }
255
+
256
+ private forwardToDestination(routedMessage: RouteMessageWrapper): RouteMessageAck {
257
+ logger.trace(`Peer ${this.ownPeerId.value} forwarding found message targeted to self ${routedMessage.requestId}`)
258
+ const forwardedMessage = routedMessage.message!
259
+ if (this.ownPeerId!.equals(peerIdFromPeerDescriptor(forwardedMessage.targetDescriptor!))) {
260
+ this.connectionManager?.handleMessage(forwardedMessage!)
261
+ return createRouteMessageAck(routedMessage)
262
+ }
263
+ return this.doRouteMessage({ ...routedMessage, destinationPeer: forwardedMessage.targetDescriptor })
264
+ }
265
+
266
+ }
@@ -0,0 +1,222 @@
1
+ import { PeerDescriptor } from '../../exports'
2
+ import { DhtPeer } from '../DhtPeer'
3
+ import { SortedContactList } from '../contact/SortedContactList'
4
+ import { PeerID, PeerIDKey } from '../../helpers/PeerID'
5
+ import { Logger } from '@streamr/utils'
6
+ import EventEmitter from 'eventemitter3'
7
+ import { v4 } from 'uuid'
8
+ import { RouteMessageWrapper } from '../../proto/packages/dht/protos/DhtRpc'
9
+ import { RemoteRouter } from './RemoteRouter'
10
+ import { RoutingRpcCommunicator } from '../../transport/RoutingRpcCommunicator'
11
+ import { RoutingServiceClient } from '../../proto/packages/dht/protos/DhtRpc.client'
12
+ import { toProtoRpcClient } from '@streamr/proto-rpc'
13
+
14
+ const logger = new Logger(module)
15
+
16
+ const MAX_FAILED_HOPS = 2
17
+
18
+ export interface RoutingSessionEvents {
19
+ // This event is emitted when a peer responds with a success ack
20
+ // to routeMessage call
21
+ routingSucceeded: (sessionId: string) => void
22
+ partialSuccess: (sessionId: string) => void
23
+
24
+ // This event is emitted when all the candidates have been gone
25
+ // through, and none of them responds with a success ack
26
+ routingFailed: (sessionId: string) => void
27
+ stopped: (sessionId: string) => void
28
+ noCandidatesFound: (sessionId: string) => void
29
+ }
30
+
31
+ export enum RoutingMode { ROUTE, FORWARD, RECURSIVE_FIND }
32
+
33
+ export class RoutingSession extends EventEmitter<RoutingSessionEvents> {
34
+
35
+ public readonly sessionId = v4()
36
+ private readonly rpcCommunicator: RoutingRpcCommunicator
37
+ private ongoingRequests: Set<PeerIDKey> = new Set()
38
+ private contactList: SortedContactList<RemoteRouter>
39
+ private readonly ownPeerDescriptor: PeerDescriptor
40
+ private readonly messageToRoute: RouteMessageWrapper
41
+ private connections: Map<PeerIDKey, DhtPeer>
42
+ private readonly parallelism: number
43
+ private failedHopCounter = 0
44
+ private successfulHopCounter = 0
45
+ private readonly mode: RoutingMode = RoutingMode.ROUTE
46
+ private stopped = false
47
+
48
+ constructor(
49
+ rpcCommunicator: RoutingRpcCommunicator,
50
+ ownPeerDescriptor: PeerDescriptor,
51
+ messageToRoute: RouteMessageWrapper,
52
+ connections: Map<PeerIDKey, DhtPeer>,
53
+ parallelism: number,
54
+ mode: RoutingMode = RoutingMode.ROUTE,
55
+ destinationId?: Uint8Array,
56
+ excludedPeerIDs?: PeerID[]
57
+ ) {
58
+ super()
59
+ this.rpcCommunicator = rpcCommunicator
60
+ this.ownPeerDescriptor = ownPeerDescriptor
61
+ this.messageToRoute = messageToRoute
62
+ this.connections = connections
63
+ this.parallelism = parallelism
64
+ this.mode = mode
65
+ const previousId = messageToRoute.previousPeer ? PeerID.fromValue(messageToRoute.previousPeer.kademliaId) : undefined
66
+ this.contactList = new SortedContactList(
67
+ destinationId ? PeerID.fromValue(destinationId) : PeerID.fromValue(this.messageToRoute!.destinationPeer!.kademliaId),
68
+ 10000,
69
+ undefined,
70
+ true,
71
+ previousId,
72
+ excludedPeerIDs
73
+ )
74
+ }
75
+
76
+ private onRequestFailed = (peerId: PeerID) => {
77
+ logger.trace('onRequestFailed() sessionId: ' + this.sessionId)
78
+ if (this.stopped) {
79
+ return
80
+ }
81
+ if (this.ongoingRequests.has(peerId.toKey())) {
82
+ this.ongoingRequests.delete(peerId.toKey())
83
+ }
84
+ const contacts = this.findMoreContacts()
85
+ if (contacts.length < 1 && this.ongoingRequests.size < 1) {
86
+ logger.trace('routing failed, emitting routingFailed sessionId: ' + this.sessionId)
87
+ this.stopped = true
88
+ this.emitFailure()
89
+ } else {
90
+ this.failedHopCounter += 1
91
+ logger.trace('routing failed, retrying to route sessionId: ' + this.sessionId + ' failedHopCounter: ' + this.failedHopCounter)
92
+ this.sendMoreRequests(contacts)
93
+ }
94
+ }
95
+
96
+ private emitFailure = () => {
97
+ if (this.successfulHopCounter >= 1) {
98
+ this.emit('partialSuccess', this.sessionId)
99
+
100
+ } else {
101
+ this.emit('routingFailed', this.sessionId)
102
+ }
103
+ }
104
+
105
+ private onRequestSucceeded = (_peerId: PeerID) => {
106
+ logger.trace('onRequestSucceeded() sessionId: ' + this.sessionId)
107
+ if (this.stopped) {
108
+ return
109
+ }
110
+ this.successfulHopCounter += 1
111
+ const contacts = this.findMoreContacts()
112
+ if (this.successfulHopCounter >= this.parallelism || contacts.length < 1) {
113
+ this.stopped = true
114
+ this.emit('routingSucceeded', this.sessionId)
115
+ } else if (contacts.length > 0 && this.ongoingRequests.size < 1) {
116
+ this.sendMoreRequests(contacts)
117
+ }
118
+ }
119
+
120
+ private sendRouteMessageRequest = async (contact: RemoteRouter): Promise<boolean> => {
121
+ logger.trace('sendRouteMessageRequest() sessionId: ' + this.sessionId)
122
+ logger.trace(`Sending routeMessage request from ${this.ownPeerDescriptor.kademliaId} to contact: ${contact.getPeerId()}`)
123
+ this.contactList.setContacted(contact.getPeerId())
124
+ this.ongoingRequests.add(contact.getPeerId().toKey())
125
+ if (this.mode === RoutingMode.FORWARD) {
126
+ return contact.forwardMessage({
127
+ ...this.messageToRoute,
128
+ previousPeer: this.ownPeerDescriptor
129
+ })
130
+ } else if (this.mode === RoutingMode.RECURSIVE_FIND) {
131
+ return contact.findRecursively({
132
+ ...this.messageToRoute,
133
+ previousPeer: this.ownPeerDescriptor
134
+ })
135
+ } else {
136
+ return contact.routeMessage({
137
+ ...this.messageToRoute,
138
+ previousPeer: this.ownPeerDescriptor
139
+ })
140
+ }
141
+ }
142
+
143
+ private findMoreContacts = (): RemoteRouter[] => {
144
+ logger.trace('findMoreContacts() sessionId: ' + this.sessionId)
145
+ // the contents of the connections might have changed between the rounds
146
+ // addContacts() will only add new contacts that were not there yet
147
+ const contacts = Array.from(this.connections.values())
148
+ .map((contact) => {
149
+ return new RemoteRouter(
150
+ this.ownPeerDescriptor,
151
+ contact.getPeerDescriptor(),
152
+ toProtoRpcClient(new RoutingServiceClient(this.rpcCommunicator!.getRpcClientTransport())),
153
+ contact.getServiceId()
154
+ )
155
+ })
156
+ this.contactList.addContacts(contacts)
157
+ return this.contactList.getUncontactedContacts(this.parallelism)
158
+ }
159
+
160
+ public getClosestContacts = (limit: number): PeerDescriptor[] => {
161
+ const contacts = this.contactList.getClosestContacts(limit)
162
+ return contacts.map((contact) => contact.getPeerDescriptor())
163
+ }
164
+
165
+ private sendMoreRequests = (uncontacted: RemoteRouter[]) => {
166
+ logger.trace('sendMoreRequests() sessionId: ' + this.sessionId)
167
+ if (this.stopped) {
168
+ return
169
+ }
170
+ if (uncontacted.length < 1) {
171
+ this.emitFailure()
172
+ return
173
+ }
174
+ if (this.failedHopCounter >= MAX_FAILED_HOPS) {
175
+ logger.trace(`Stopping routing after ${MAX_FAILED_HOPS} failed attempts for sessionId: ${this.sessionId}`)
176
+ this.emitFailure()
177
+ return
178
+ }
179
+ while (this.ongoingRequests.size < this.parallelism && uncontacted.length > 0) {
180
+ if (this.stopped) {
181
+ return
182
+ }
183
+ const nextPeer = uncontacted.shift()
184
+ logger.trace('sendRouteMessageRequest')
185
+ // eslint-disable-next-line promise/catch-or-return
186
+ this.sendRouteMessageRequest(nextPeer!)
187
+ .then((succeeded) => {
188
+ if (succeeded) {
189
+ this.onRequestSucceeded(nextPeer!.getPeerId())
190
+ } else {
191
+ this.onRequestFailed(nextPeer!.getPeerId())
192
+ }
193
+ }).catch((e) => {
194
+ logger.error(e)
195
+ }).finally(() => {
196
+ logger.trace('sendRouteMessageRequest returned')
197
+ })
198
+ }
199
+ }
200
+
201
+ public start(): void {
202
+ logger.trace('start() sessionId: ' + this.sessionId)
203
+ const contacts = this.findMoreContacts()
204
+ if (contacts.length < 1) {
205
+ logger.trace('start() throwing noCandidatesFound sessionId: ' + this.sessionId)
206
+
207
+ this.stopped = true
208
+ this.emit('noCandidatesFound', this.sessionId)
209
+ throw new Error('noCandidatesFound ' + this.sessionId)
210
+ }
211
+ this.sendMoreRequests(contacts)
212
+ }
213
+
214
+ public stop(): void {
215
+ this.stopped = true
216
+ this.contactList.stop()
217
+
218
+ this.emit('stopped', this.sessionId)
219
+ this.removeAllListeners()
220
+ }
221
+
222
+ }