@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,162 @@
1
+ import { DiscoverySession } from './DiscoverySession'
2
+ import { DhtPeer } from '../DhtPeer'
3
+ import crypto from 'crypto'
4
+ import * as Err from '../../helpers/errors'
5
+ import { isSamePeerDescriptor, keyFromPeerDescriptor } from '../../helpers/peerIdFromPeerDescriptor'
6
+ import { PeerDescriptor } from '../../proto/packages/dht/protos/DhtRpc'
7
+ import { Logger, scheduleAtInterval, setAbortableTimeout } from '@streamr/utils'
8
+ import KBucket from 'k-bucket'
9
+ import { SortedContactList } from '../contact/SortedContactList'
10
+ import { ConnectionManager } from '../../connection/ConnectionManager'
11
+ import { PeerID, PeerIDKey } from '../../helpers/PeerID'
12
+ import { RoutingRpcCommunicator } from '../../transport/RoutingRpcCommunicator'
13
+ import { RandomContactList } from '../contact/RandomContactList'
14
+
15
+ interface PeerDiscoveryConfig {
16
+ rpcCommunicator: RoutingRpcCommunicator
17
+ ownPeerDescriptor: PeerDescriptor
18
+ ownPeerId: PeerID
19
+ bucket: KBucket<DhtPeer>
20
+ connections: Map<PeerIDKey, DhtPeer>
21
+ neighborList: SortedContactList<DhtPeer>
22
+ randomPeers: RandomContactList<DhtPeer>
23
+ openInternetPeers: SortedContactList<DhtPeer>
24
+ joinNoProgressLimit: number
25
+ getClosestContactsLimit: number
26
+ serviceId: string
27
+ parallelism: number
28
+ joinTimeout: number
29
+ addContact: (contact: PeerDescriptor, setActive?: boolean) => void
30
+ connectionManager?: ConnectionManager
31
+ }
32
+
33
+ const logger = new Logger(module)
34
+
35
+ export class PeerDiscovery {
36
+ private readonly config: PeerDiscoveryConfig
37
+ private ongoingDiscoverySessions: Map<string, DiscoverySession> = new Map()
38
+ private stopped = false
39
+ private rejoinOngoing = false
40
+ private joinCalled = false
41
+
42
+ private rejoinTimeoutRef?: NodeJS.Timeout
43
+ private readonly abortController: AbortController
44
+
45
+ constructor(config: PeerDiscoveryConfig) {
46
+ this.config = config
47
+ this.abortController = new AbortController()
48
+ }
49
+
50
+ async joinDht(entryPointDescriptor: PeerDescriptor, doRandomJoin = true): Promise<void> {
51
+ if (this.stopped) {
52
+ return
53
+ }
54
+ this.joinCalled = true
55
+ logger.debug(
56
+ `Joining ${this.config.serviceId === 'layer0' ? 'The Streamr Network' : `Control Layer for ${this.config.serviceId}`}`
57
+ + ` via entrypoint ${keyFromPeerDescriptor(entryPointDescriptor)}`
58
+ )
59
+ if (isSamePeerDescriptor(entryPointDescriptor, this.config.ownPeerDescriptor)) {
60
+ return
61
+ }
62
+ this.config.connectionManager?.lockConnection(entryPointDescriptor, `${this.config.serviceId}::joinDht`)
63
+ this.config.addContact(entryPointDescriptor)
64
+ const closest = this.config.bucket.closest(this.config.ownPeerId!.value, this.config.getClosestContactsLimit)
65
+ this.config.neighborList.addContacts(closest)
66
+ const sessionOptions = {
67
+ bucket: this.config.bucket,
68
+ neighborList: this.config.neighborList!,
69
+ targetId: this.config.ownPeerId!.value,
70
+ ownPeerDescriptor: this.config.ownPeerDescriptor!,
71
+ serviceId: this.config.serviceId,
72
+ rpcCommunicator: this.config.rpcCommunicator!,
73
+ parallelism: this.config.parallelism,
74
+ noProgressLimit: this.config.joinNoProgressLimit,
75
+ newContactListener: (newPeer: DhtPeer) => this.config.addContact(newPeer.getPeerDescriptor()),
76
+ nodeName: this.config.ownPeerDescriptor.nodeName
77
+ }
78
+ const session = new DiscoverySession(sessionOptions)
79
+ const randomSession = doRandomJoin ? new DiscoverySession({
80
+ ...sessionOptions,
81
+ targetId: crypto.randomBytes(8),
82
+ nodeName: this.config.ownPeerDescriptor.nodeName + '-random'
83
+ }) : null
84
+ this.ongoingDiscoverySessions.set(session.sessionId, session)
85
+ if (randomSession) {
86
+ this.ongoingDiscoverySessions.set(randomSession.sessionId, randomSession)
87
+ }
88
+ try {
89
+ await session.findClosestNodes(this.config.joinTimeout)
90
+ if (randomSession) {
91
+ await randomSession.findClosestNodes(this.config.joinTimeout)
92
+ }
93
+ if (!this.stopped) {
94
+ if (this.config.bucket.count() === 0) {
95
+ this.rejoinDht(entryPointDescriptor).catch(() => {})
96
+ } else {
97
+ await scheduleAtInterval(() => this.getClosestPeersFromBucket(), 60000, true, this.abortController.signal)
98
+ }
99
+ }
100
+ } catch (_e) {
101
+ throw new Err.DhtJoinTimeout('join timed out')
102
+ } finally {
103
+ this.ongoingDiscoverySessions.delete(session.sessionId)
104
+ if (randomSession) {
105
+ this.ongoingDiscoverySessions.delete(randomSession.sessionId)
106
+ }
107
+ this.config.connectionManager?.unlockConnection(entryPointDescriptor, `${this.config.serviceId}::joinDht`)
108
+ }
109
+ }
110
+
111
+ public async rejoinDht(entryPoint: PeerDescriptor): Promise<void> {
112
+ if (this.stopped || this.rejoinOngoing) {
113
+ return
114
+ }
115
+ logger.debug(`Rejoining DHT ${this.config.serviceId} ${this.config.ownPeerDescriptor.nodeName}!`)
116
+ this.rejoinOngoing = true
117
+ try {
118
+ this.config.neighborList.clear()
119
+ await this.joinDht(entryPoint)
120
+ logger.debug(`Rejoined DHT successfully ${this.config.serviceId}!`)
121
+ } catch (err) {
122
+ logger.warn(`Rejoining DHT ${this.config.serviceId} failed`)
123
+ if (!this.stopped) {
124
+ setAbortableTimeout(() => this.rejoinDht(entryPoint), 5000, this.abortController.signal)
125
+ }
126
+ } finally {
127
+ this.rejoinOngoing = false
128
+ }
129
+ }
130
+
131
+ private async getClosestPeersFromBucket(): Promise<void> {
132
+ if (this.stopped) {
133
+ return
134
+ }
135
+ await Promise.allSettled(this.config.bucket.closest(this.config.ownPeerId.value, this.config.parallelism).map(async (peer: DhtPeer) => {
136
+ const contacts = await peer.getClosestPeers(this.config.ownPeerDescriptor.kademliaId!)
137
+ contacts.forEach((contact) => {
138
+ this.config.addContact(contact)
139
+ })
140
+ }))
141
+ }
142
+
143
+ public isJoinOngoing(): boolean {
144
+ return !this.joinCalled ? true : this.ongoingDiscoverySessions.size > 0
145
+ }
146
+
147
+ public isJoinCalled(): boolean {
148
+ return this.joinCalled
149
+ }
150
+
151
+ public stop(): void {
152
+ this.stopped = true
153
+ this.abortController.abort()
154
+ if (this.rejoinTimeoutRef) {
155
+ clearTimeout(this.rejoinTimeoutRef)
156
+ this.rejoinTimeoutRef = undefined
157
+ }
158
+ this.ongoingDiscoverySessions.forEach((session, _id) => {
159
+ session.stop()
160
+ })
161
+ }
162
+ }
@@ -0,0 +1,178 @@
1
+ import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
2
+ import { Logger } from '@streamr/utils'
3
+ import EventEmitter from 'eventemitter3'
4
+ import { PeerID, PeerIDKey } from '../../helpers/PeerID'
5
+ import { DataEntry, FindMode, PeerDescriptor, RecursiveFindReport } from '../../proto/packages/dht/protos/DhtRpc'
6
+ import { IRecursiveFindSessionService } from '../../proto/packages/dht/protos/DhtRpc.server'
7
+ import { Empty } from '../../proto/google/protobuf/empty'
8
+ import { ITransport } from '../../transport/ITransport'
9
+ import { ListeningRpcCommunicator } from '../../transport/ListeningRpcCommunicator'
10
+ import { Contact } from '../contact/Contact'
11
+ import { SortedContactList } from '../contact/SortedContactList'
12
+ import { RecursiveFindResult } from './RecursiveFinder'
13
+ import { keyFromPeerDescriptor } from '../../helpers/peerIdFromPeerDescriptor'
14
+
15
+ export interface RecursiveFindSessionEvents {
16
+ findCompleted: (results: PeerDescriptor[]) => void
17
+ }
18
+
19
+ const logger = new Logger(module)
20
+
21
+ export interface RecursiveFindSessionConfig {
22
+ serviceId: string
23
+ rpcTransport: ITransport
24
+ kademliaIdToFind: Uint8Array
25
+ ownPeerID: PeerID
26
+ waitedRoutingPathCompletions: number
27
+ mode: FindMode
28
+ }
29
+
30
+ export class RecursiveFindSession extends EventEmitter<RecursiveFindSessionEvents> implements IRecursiveFindSessionService {
31
+ private readonly serviceId: string
32
+ private readonly rpcTransport: ITransport
33
+ private readonly kademliaIdToFind: Uint8Array
34
+ private readonly ownPeerID: PeerID
35
+ private readonly waitedRoutingPathCompletions: number
36
+ private readonly rpcCommunicator: ListeningRpcCommunicator
37
+ private readonly mode: FindMode
38
+ private results: SortedContactList<Contact>
39
+ private foundData: Map<string, DataEntry> = new Map()
40
+ private allKnownHops: Set<PeerIDKey> = new Set()
41
+ private reportedHops: Set<PeerIDKey> = new Set()
42
+ private reportFindCompletedTimeout?: NodeJS.Timeout
43
+ private findCompletedEmitted = false
44
+ private noCloserNodesReceivedCounter = 0
45
+
46
+ constructor(config: RecursiveFindSessionConfig) {
47
+ super()
48
+ this.serviceId = config.serviceId
49
+ this.rpcTransport = config.rpcTransport
50
+ this.kademliaIdToFind = config.kademliaIdToFind
51
+ this.ownPeerID = config.ownPeerID
52
+ this.waitedRoutingPathCompletions = config.waitedRoutingPathCompletions
53
+ this.results = new SortedContactList(PeerID.fromValue(this.kademliaIdToFind), 10, undefined, true)
54
+ this.mode = config.mode
55
+ this.rpcCommunicator = new ListeningRpcCommunicator(this.serviceId, this.rpcTransport, {
56
+ rpcRequestTimeout: 15000
57
+ })
58
+ this.rpcCommunicator.registerRpcNotification(RecursiveFindReport, 'reportRecursiveFindResult',
59
+ (req: RecursiveFindReport, context) => this.reportRecursiveFindResult(req, context))
60
+ }
61
+
62
+ private isFindCompleted(): boolean {
63
+ const unreportedHops: Set<PeerIDKey> = new Set(this.allKnownHops)
64
+ this.reportedHops.forEach((id) => {
65
+ unreportedHops.delete(id)
66
+ })
67
+ if (this.noCloserNodesReceivedCounter >= 1 && unreportedHops.size === 0) {
68
+ if (this.mode === FindMode.DATA
69
+ && (this.hasNonStaleData() || this.noCloserNodesReceivedCounter >= this.waitedRoutingPathCompletions)) {
70
+ return true
71
+ } else if (this.mode === FindMode.DATA) {
72
+ return false
73
+ }
74
+ return true
75
+ }
76
+ return false
77
+ }
78
+
79
+ private hasNonStaleData(): boolean {
80
+ return Array.from(this.foundData.values()).some((entry) => entry.stale === false)
81
+ }
82
+
83
+ public doReportRecursiveFindResult(
84
+ routingPath: PeerDescriptor[],
85
+ nodes: PeerDescriptor[],
86
+ dataEntries: DataEntry[],
87
+ noCloserNodesFound?: boolean
88
+ ): void {
89
+ this.addKnownHops(routingPath)
90
+ if (routingPath.length >= 1) {
91
+ this.setHopAsReported(routingPath[routingPath.length - 1])
92
+ }
93
+ nodes.map((descriptor: PeerDescriptor) => {
94
+ this.results.addContact(new Contact(descriptor))
95
+ })
96
+ this.processFoundData(dataEntries)
97
+ if (noCloserNodesFound) {
98
+ this.onNoCloserPeersFound()
99
+ }
100
+ }
101
+
102
+ private addKnownHops(routingPath: PeerDescriptor[]) {
103
+ routingPath.forEach((desc) => {
104
+ const newPeerId = PeerID.fromValue(desc.kademliaId)
105
+ if (!this.ownPeerID.equals(newPeerId)) {
106
+ this.allKnownHops.add(newPeerId.toKey())
107
+ }
108
+ })
109
+ }
110
+
111
+ private setHopAsReported(desc: PeerDescriptor) {
112
+ const newPeerId = PeerID.fromValue(desc.kademliaId)
113
+ if (!this.ownPeerID.equals(newPeerId)) {
114
+ this.reportedHops.add(newPeerId.toKey())
115
+ }
116
+ if (this.isFindCompleted()) {
117
+ if (!this.findCompletedEmitted && this.isFindCompleted()) {
118
+ if (this.reportFindCompletedTimeout) {
119
+ clearTimeout(this.reportFindCompletedTimeout)
120
+ this.reportFindCompletedTimeout = undefined
121
+ }
122
+ this.emit('findCompleted', this.results.getAllContacts().map((contact) => contact.getPeerDescriptor()))
123
+ this.findCompletedEmitted = true
124
+ }
125
+ }
126
+ }
127
+
128
+ private processFoundData(dataEntries: DataEntry[]): void {
129
+ dataEntries.forEach((entry) => {
130
+ const storerKey = keyFromPeerDescriptor(entry.storer!)
131
+ const existingEntry = this.foundData.get(storerKey)
132
+ if (!existingEntry || existingEntry.storerTime! < entry.storerTime!
133
+ || (existingEntry.storerTime! <= entry.storerTime! && entry.deleted)) {
134
+ this.foundData.set(storerKey, entry)
135
+ }
136
+ })
137
+ }
138
+
139
+ private onNoCloserPeersFound(): void {
140
+ this.noCloserNodesReceivedCounter += 1
141
+ if (this.isFindCompleted()) {
142
+ this.emit('findCompleted', this.results.getAllContacts().map((contact) => contact.getPeerDescriptor()))
143
+ this.findCompletedEmitted = true
144
+ if (this.reportFindCompletedTimeout) {
145
+ clearTimeout(this.reportFindCompletedTimeout)
146
+ this.reportFindCompletedTimeout = undefined
147
+ }
148
+ } else {
149
+ if (!this.reportFindCompletedTimeout && !this.findCompletedEmitted) {
150
+ this.reportFindCompletedTimeout = setTimeout(() => {
151
+ if (!this.findCompletedEmitted) {
152
+ this.emit('findCompleted', this.results.getAllContacts().map((contact) => contact.getPeerDescriptor()))
153
+ this.findCompletedEmitted = true
154
+ }
155
+ }, 4000)
156
+ }
157
+ }
158
+ }
159
+
160
+ public async reportRecursiveFindResult(report: RecursiveFindReport, _context: ServerCallContext): Promise<Empty> {
161
+ logger.trace('recursiveFindReport arrived: ' + JSON.stringify(report))
162
+ this.doReportRecursiveFindResult(report.routingPath, report.nodes, report.dataEntries, report.noCloserNodesFound)
163
+ return {}
164
+ }
165
+
166
+ public getResults = (): RecursiveFindResult => ({
167
+ closestNodes: this.results.getAllContacts().map((contact) => contact.getPeerDescriptor()),
168
+ dataEntries: (this.foundData && this.foundData.size > 0) ? Array.from(this.foundData.values()) : undefined
169
+ })
170
+
171
+ public stop(): void {
172
+ if (this.reportFindCompletedTimeout) {
173
+ clearTimeout(this.reportFindCompletedTimeout)
174
+ this.reportFindCompletedTimeout = undefined
175
+ }
176
+ this.emit('findCompleted', [])
177
+ }
178
+ }
@@ -0,0 +1,272 @@
1
+ import {
2
+ DataEntry,
3
+ FindMode,
4
+ Message,
5
+ MessageType,
6
+ NodeType,
7
+ PeerDescriptor,
8
+ RecursiveFindRequest,
9
+ RouteMessageAck,
10
+ RouteMessageWrapper
11
+ } from '../../proto/packages/dht/protos/DhtRpc'
12
+ import { PeerID, PeerIDKey } from '../../helpers/PeerID'
13
+ import { createRouteMessageAck, RoutingErrors, IRouter } from '../routing/Router'
14
+ import { RoutingMode } from '../routing/RoutingSession'
15
+ import { keyFromPeerDescriptor } from '../../helpers/peerIdFromPeerDescriptor'
16
+ import { Logger, runAndWaitForEvents3 } from '@streamr/utils'
17
+ import { RoutingRpcCommunicator } from '../../transport/RoutingRpcCommunicator'
18
+ import { RemoteRecursiveFindSession } from './RemoteRecursiveFindSession'
19
+ import { v4 } from 'uuid'
20
+ import { RecursiveFindSession, RecursiveFindSessionEvents } from './RecursiveFindSession'
21
+ import { DhtPeer } from '../DhtPeer'
22
+ import { ITransport } from '../../transport/ITransport'
23
+ import { LocalDataStore } from '../store/LocalDataStore'
24
+ import { IRoutingService } from '../../proto/packages/dht/protos/DhtRpc.server'
25
+ import { ListeningRpcCommunicator } from '../../transport/ListeningRpcCommunicator'
26
+ import { RecursiveFindSessionServiceClient } from '../../proto/packages/dht/protos/DhtRpc.client'
27
+ import { toProtoRpcClient } from '@streamr/proto-rpc'
28
+ import { SortedContactList } from '../contact/SortedContactList'
29
+
30
+ interface RecursiveFinderConfig {
31
+ rpcCommunicator: RoutingRpcCommunicator
32
+ sessionTransport: ITransport
33
+ connections: Map<PeerIDKey, DhtPeer>
34
+ router: IRouter
35
+ ownPeerDescriptor: PeerDescriptor
36
+ ownPeerId: PeerID
37
+ serviceId: string
38
+ localDataStore: LocalDataStore
39
+ addContact: (contact: PeerDescriptor, setActive?: boolean) => void
40
+ isPeerCloserToIdThanSelf: (peer1: PeerDescriptor, compareToId: PeerID) => boolean
41
+ }
42
+
43
+ interface RecursiveFinderFunc {
44
+ startRecursiveFind(idToFind: Uint8Array, findMode?: FindMode): Promise<RecursiveFindResult>
45
+ }
46
+
47
+ export interface IRecursiveFinder extends Pick<IRoutingService, 'findRecursively'>, RecursiveFinderFunc {}
48
+
49
+ export interface RecursiveFindResult { closestNodes: Array<PeerDescriptor>, dataEntries?: Array<DataEntry> }
50
+
51
+ const logger = new Logger(module)
52
+
53
+ export class RecursiveFinder implements IRecursiveFinder {
54
+
55
+ private readonly rpcCommunicator: RoutingRpcCommunicator
56
+ private readonly sessionTransport: ITransport
57
+ private readonly connections: Map<PeerIDKey, DhtPeer>
58
+ private readonly router: IRouter
59
+ private readonly ownPeerDescriptor: PeerDescriptor
60
+ private readonly ownPeerId: PeerID
61
+ private readonly serviceId: string
62
+ private readonly localDataStore: LocalDataStore
63
+ private readonly addContact: (contact: PeerDescriptor, setActive?: boolean) => void
64
+ private readonly isPeerCloserToIdThanSelf: (peer1: PeerDescriptor, compareToId: PeerID) => boolean
65
+ private ongoingSessions: Map<string, RecursiveFindSession> = new Map()
66
+ private stopped = false
67
+
68
+ constructor(config: RecursiveFinderConfig) {
69
+ this.rpcCommunicator = config.rpcCommunicator
70
+ this.sessionTransport = config.sessionTransport
71
+ this.connections = config.connections
72
+ this.router = config.router
73
+ this.ownPeerDescriptor = config.ownPeerDescriptor
74
+ this.ownPeerId = config.ownPeerId
75
+ this.serviceId = config.serviceId
76
+ this.localDataStore = config.localDataStore
77
+ this.addContact = config.addContact
78
+ this.isPeerCloserToIdThanSelf = config.isPeerCloserToIdThanSelf
79
+ this.rpcCommunicator!.registerRpcMethod(RouteMessageWrapper, RouteMessageAck, 'findRecursively',
80
+ (routedMessage: RouteMessageWrapper) => this.findRecursively(routedMessage))
81
+ }
82
+
83
+ public async startRecursiveFind(
84
+ idToFind: Uint8Array,
85
+ findMode: FindMode = FindMode.NODE,
86
+ excludedPeer?: PeerDescriptor
87
+ ): Promise<RecursiveFindResult> {
88
+ if (this.stopped) {
89
+ return { closestNodes: [] }
90
+ }
91
+ const sessionId = v4()
92
+ const recursiveFindSession = new RecursiveFindSession({
93
+ serviceId: sessionId,
94
+ rpcTransport: this.sessionTransport,
95
+ kademliaIdToFind: idToFind,
96
+ ownPeerID: this.ownPeerId!,
97
+ waitedRoutingPathCompletions: this.connections.size > 1 ? 2 : 1,
98
+ mode: findMode
99
+ })
100
+ if (this.connections.size === 0) {
101
+ const data = this.localDataStore.getEntry(PeerID.fromValue(idToFind))
102
+ recursiveFindSession.doReportRecursiveFindResult(
103
+ [this.ownPeerDescriptor!],
104
+ [this.ownPeerDescriptor!],
105
+ data ? Array.from(data.values()) : [],
106
+ true
107
+ )
108
+ return recursiveFindSession.getResults()
109
+ }
110
+ const routeMessage = this.wrapRecursiveFindRequest(idToFind, sessionId, findMode)
111
+ this.ongoingSessions.set(sessionId, recursiveFindSession)
112
+ try {
113
+ await runAndWaitForEvents3<RecursiveFindSessionEvents>(
114
+ [() => this.doFindRecursevily(routeMessage, excludedPeer)],
115
+ [[recursiveFindSession, 'findCompleted']],
116
+ 15000
117
+ )
118
+ } catch (err) {
119
+ logger.debug(`doFindRecursively failed with error ${this.ownPeerDescriptor.nodeName} ${err}`)
120
+ }
121
+ this.findAndReportLocalData(idToFind, findMode, [], this.ownPeerDescriptor, sessionId)
122
+ this.ongoingSessions.delete(sessionId)
123
+ recursiveFindSession.stop()
124
+ return recursiveFindSession.getResults()
125
+ }
126
+
127
+ private wrapRecursiveFindRequest(idToFind: Uint8Array, sessionId: string, findMode: FindMode): RouteMessageWrapper {
128
+ const targetDescriptor: PeerDescriptor = {
129
+ kademliaId: idToFind,
130
+ type: NodeType.VIRTUAL
131
+ }
132
+ const request: RecursiveFindRequest = {
133
+ recursiveFindSessionId: sessionId,
134
+ findMode
135
+ }
136
+ const msg: Message = {
137
+ messageType: MessageType.RECURSIVE_FIND_REQUEST,
138
+ messageId: v4(),
139
+ serviceId: this.serviceId,
140
+ body: {
141
+ oneofKind: 'recursiveFindRequest',
142
+ recursiveFindRequest: request
143
+ }
144
+ }
145
+ const routeMessage: RouteMessageWrapper = {
146
+ message: msg,
147
+ requestId: v4(),
148
+ destinationPeer: targetDescriptor,
149
+ sourcePeer: this.ownPeerDescriptor,
150
+ reachableThrough: [],
151
+ routingPath: []
152
+ }
153
+ return routeMessage
154
+ }
155
+
156
+ private findAndReportLocalData(
157
+ idToFind: Uint8Array,
158
+ findMode: FindMode,
159
+ routingPath: PeerDescriptor[],
160
+ sourcePeer: PeerDescriptor,
161
+ sessionId: string
162
+ ): boolean {
163
+ if (findMode === FindMode.DATA) {
164
+ const data = this.localDataStore.getEntry(PeerID.fromValue(idToFind))
165
+ if (data.size > 0) {
166
+ this.reportRecursiveFindResult(routingPath, sourcePeer, sessionId, [], data, true)
167
+ return true
168
+ }
169
+ }
170
+ return false
171
+ }
172
+
173
+ private findLocalData(idToFind: Uint8Array, findMode: FindMode): Map<PeerIDKey, DataEntry> | undefined {
174
+ if (findMode === FindMode.DATA) {
175
+ return this.localDataStore.getEntry(PeerID.fromValue(idToFind))
176
+ }
177
+ return undefined
178
+ }
179
+
180
+ private reportRecursiveFindResult(
181
+ routingPath: PeerDescriptor[],
182
+ targetPeerDescriptor: PeerDescriptor,
183
+ serviceId: string,
184
+ closestNodes: PeerDescriptor[],
185
+ data: Map<PeerIDKey, DataEntry> | undefined,
186
+ noCloserNodesFound: boolean = false
187
+ ): void {
188
+ const dataEntries = data ? Array.from(data.values(), DataEntry.create.bind(DataEntry)) : []
189
+ const isOwnPeerId = this.ownPeerId.equals(PeerID.fromValue(targetPeerDescriptor!.kademliaId))
190
+ if (isOwnPeerId && this.ongoingSessions.has(serviceId)) {
191
+ this.ongoingSessions.get(serviceId)!
192
+ .doReportRecursiveFindResult(routingPath, closestNodes, dataEntries, noCloserNodesFound)
193
+ } else {
194
+ const remoteCommunicator = new ListeningRpcCommunicator(serviceId, this.sessionTransport, { rpcRequestTimeout: 15000 })
195
+ const remoteSession = new RemoteRecursiveFindSession(
196
+ this.ownPeerDescriptor,
197
+ targetPeerDescriptor,
198
+ toProtoRpcClient(new RecursiveFindSessionServiceClient(remoteCommunicator.getRpcClientTransport())),
199
+ serviceId
200
+ )
201
+ remoteSession.reportRecursiveFindResult(routingPath, closestNodes, dataEntries, noCloserNodesFound)
202
+ }
203
+ }
204
+
205
+ private doFindRecursevily(routedMessage: RouteMessageWrapper, excludedPeer?: PeerDescriptor): RouteMessageAck {
206
+ if (this.stopped) {
207
+ return createRouteMessageAck(routedMessage, 'DhtNode Stopped')
208
+ }
209
+ const idToFind = PeerID.fromValue(routedMessage.destinationPeer!.kademliaId)
210
+ const msg = routedMessage.message
211
+ const recursiveFindRequest = msg?.body.oneofKind === 'recursiveFindRequest' ? msg.body.recursiveFindRequest : undefined
212
+ const closestPeersToDestination = this.getClosestConnections(routedMessage.destinationPeer!.kademliaId, 5)
213
+ const data = this.findLocalData(idToFind.value, recursiveFindRequest!.findMode)
214
+ if (this.ownPeerId!.equals(idToFind)) {
215
+ this.reportRecursiveFindResult(routedMessage.routingPath, routedMessage.sourcePeer!, recursiveFindRequest!.recursiveFindSessionId,
216
+ closestPeersToDestination, data, true)
217
+ return createRouteMessageAck(routedMessage)
218
+ }
219
+ const ack = this.router.doRouteMessage(routedMessage, RoutingMode.RECURSIVE_FIND, excludedPeer)
220
+ if (ack.error === RoutingErrors.NO_CANDIDATES_FOUND) {
221
+ logger.trace(`findRecursively Node ${this.ownPeerDescriptor.nodeName} found no candidates`)
222
+ this.reportRecursiveFindResult(routedMessage.routingPath, routedMessage.sourcePeer!, recursiveFindRequest!.recursiveFindSessionId,
223
+ closestPeersToDestination, data, true)
224
+ } else if (ack.error) {
225
+ return ack
226
+ } else {
227
+ const noCloserContactsFound = (
228
+ closestPeersToDestination.length > 0
229
+ && routedMessage.previousPeer
230
+ && !this.isPeerCloserToIdThanSelf(closestPeersToDestination[0], idToFind)
231
+ )
232
+ this.reportRecursiveFindResult(routedMessage.routingPath, routedMessage.sourcePeer!, recursiveFindRequest!.recursiveFindSessionId,
233
+ closestPeersToDestination, data, noCloserContactsFound)
234
+ }
235
+ return ack
236
+ }
237
+
238
+ private getClosestConnections(kademliaId: Uint8Array, limit: number): PeerDescriptor[] {
239
+ const connectedPeers = Array.from(this.connections.values())
240
+ const closestPeers = new SortedContactList(
241
+ PeerID.fromValue(kademliaId),
242
+ limit,
243
+ undefined,
244
+ true,
245
+ undefined
246
+ )
247
+ closestPeers.addContacts(connectedPeers)
248
+ return closestPeers.getClosestContacts(limit).map((peer) => peer.getPeerDescriptor())
249
+ }
250
+
251
+ // IRoutingService method
252
+ async findRecursively(routedMessage: RouteMessageWrapper): Promise<RouteMessageAck> {
253
+ if (this.stopped) {
254
+ return createRouteMessageAck(routedMessage, 'findRecursively() service is not running')
255
+ } else if (this.router.checkDuplicate(routedMessage.requestId)) {
256
+ return createRouteMessageAck(routedMessage, 'message given to findRecursively() service is likely a duplicate')
257
+ }
258
+ const senderKey = keyFromPeerDescriptor(routedMessage.previousPeer || routedMessage.sourcePeer!)
259
+ logger.trace(`Node ${this.ownPeerId.toKey()} received findRecursively call from ${senderKey}`)
260
+ this.addContact(routedMessage.sourcePeer!, true)
261
+ this.router!.addToDuplicateDetector(routedMessage.requestId, keyFromPeerDescriptor(routedMessage.sourcePeer!))
262
+ return this.doFindRecursevily(routedMessage)
263
+ }
264
+
265
+ public stop(): void {
266
+ this.stopped = true
267
+ this.ongoingSessions.forEach((session, _id) => {
268
+ session.stop()
269
+ })
270
+ this.ongoingSessions.clear()
271
+ }
272
+ }
@@ -0,0 +1,33 @@
1
+ import {
2
+ DataEntry,
3
+ PeerDescriptor,
4
+ RecursiveFindReport
5
+ } from '../../proto/packages/dht/protos/DhtRpc'
6
+ import { IRecursiveFindSessionServiceClient } from '../../proto/packages/dht/protos/DhtRpc.client'
7
+ import { DhtRpcOptions } from '../../rpc-protocol/DhtRpcOptions'
8
+ import { Logger } from '@streamr/utils'
9
+ import { Remote } from '../contact/Remote'
10
+
11
+ const logger = new Logger(module)
12
+
13
+ export class RemoteRecursiveFindSession extends Remote<IRecursiveFindSessionServiceClient> {
14
+
15
+ reportRecursiveFindResult(routingPath: PeerDescriptor[], closestNodes: PeerDescriptor[],
16
+ dataEntries: DataEntry[], noCloserNodesFound: boolean): void {
17
+
18
+ const report: RecursiveFindReport = {
19
+ routingPath,
20
+ nodes: closestNodes,
21
+ dataEntries,
22
+ noCloserNodesFound
23
+ }
24
+ const options: DhtRpcOptions = {
25
+ sourceDescriptor: this.ownPeerDescriptor,
26
+ targetDescriptor: this.peerDescriptor
27
+ }
28
+
29
+ this.client.reportRecursiveFindResult(report, options).catch((_e) => {
30
+ logger.trace('Failed to send RecursiveFindResult')
31
+ })
32
+ }
33
+ }