@streamr/dht 100.0.0-pretestnet.6 → 100.0.0-rc.1

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 (444) hide show
  1. package/README.md +90 -8
  2. package/dist/package.json +70 -0
  3. package/dist/src/connection/Connection.d.ts +1 -0
  4. package/dist/src/connection/Connection.js +10 -3
  5. package/dist/src/connection/Connection.js.map +1 -1
  6. package/dist/src/connection/ConnectionLockHandler.d.ts +14 -14
  7. package/dist/src/connection/ConnectionLockHandler.js +22 -16
  8. package/dist/src/connection/ConnectionLockHandler.js.map +1 -1
  9. package/dist/src/connection/ConnectionLockRpcLocal.d.ts +3 -3
  10. package/dist/src/connection/ConnectionLockRpcLocal.js +7 -6
  11. package/dist/src/connection/ConnectionLockRpcLocal.js.map +1 -1
  12. package/dist/src/connection/ConnectionLockRpcRemote.d.ts +4 -6
  13. package/dist/src/connection/ConnectionLockRpcRemote.js +10 -37
  14. package/dist/src/connection/ConnectionLockRpcRemote.js.map +1 -1
  15. package/dist/src/connection/ConnectionManager.d.ts +19 -20
  16. package/dist/src/connection/ConnectionManager.js +132 -117
  17. package/dist/src/connection/ConnectionManager.js.map +1 -1
  18. package/dist/src/connection/ConnectorFacade.d.ts +3 -2
  19. package/dist/src/connection/ConnectorFacade.js +10 -3
  20. package/dist/src/connection/ConnectorFacade.js.map +1 -1
  21. package/dist/src/connection/Handshaker.d.ts +3 -1
  22. package/dist/src/connection/Handshaker.js +19 -10
  23. package/dist/src/connection/Handshaker.js.map +1 -1
  24. package/dist/src/connection/IConnection.d.ts +2 -7
  25. package/dist/src/connection/IConnection.js +1 -8
  26. package/dist/src/connection/IConnection.js.map +1 -1
  27. package/dist/src/connection/ManagedConnection.d.ts +5 -7
  28. package/dist/src/connection/ManagedConnection.js +42 -26
  29. package/dist/src/connection/ManagedConnection.js.map +1 -1
  30. package/dist/src/connection/ManagedWebrtcConnection.js.map +1 -1
  31. package/dist/src/connection/connectivityChecker.d.ts +9 -0
  32. package/dist/src/connection/connectivityChecker.js +130 -0
  33. package/dist/src/connection/connectivityChecker.js.map +1 -0
  34. package/dist/src/connection/connectivityRequestHandler.d.ts +3 -0
  35. package/dist/src/connection/connectivityRequestHandler.js +101 -0
  36. package/dist/src/connection/connectivityRequestHandler.js.map +1 -0
  37. package/dist/src/connection/simulator/Simulator.d.ts +0 -3
  38. package/dist/src/connection/simulator/Simulator.js +34 -69
  39. package/dist/src/connection/simulator/Simulator.js.map +1 -1
  40. package/dist/src/connection/simulator/SimulatorConnection.js +27 -25
  41. package/dist/src/connection/simulator/SimulatorConnection.js.map +1 -1
  42. package/dist/src/connection/simulator/SimulatorConnector.js +16 -12
  43. package/dist/src/connection/simulator/SimulatorConnector.js.map +1 -1
  44. package/dist/src/connection/simulator/pings.js.map +1 -1
  45. package/dist/src/connection/webrtc/NodeWebrtcConnection.d.ts +2 -3
  46. package/dist/src/connection/webrtc/NodeWebrtcConnection.js +40 -27
  47. package/dist/src/connection/webrtc/NodeWebrtcConnection.js.map +1 -1
  48. package/dist/src/connection/webrtc/WebrtcConnector.d.ts +1 -2
  49. package/dist/src/connection/webrtc/WebrtcConnector.js +36 -32
  50. package/dist/src/connection/webrtc/WebrtcConnector.js.map +1 -1
  51. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.d.ts +4 -2
  52. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js +28 -22
  53. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js.map +1 -1
  54. package/dist/src/connection/webrtc/WebrtcConnectorRpcRemote.d.ts +3 -6
  55. package/dist/src/connection/webrtc/WebrtcConnectorRpcRemote.js +2 -5
  56. package/dist/src/connection/webrtc/WebrtcConnectorRpcRemote.js.map +1 -1
  57. package/dist/src/connection/webrtc/iceServerAsString.js +1 -1
  58. package/dist/src/connection/webrtc/iceServerAsString.js.map +1 -1
  59. package/dist/src/connection/websocket/AutoCertifierClientFacade.d.ts +1 -2
  60. package/dist/src/connection/websocket/AutoCertifierClientFacade.js +6 -4
  61. package/dist/src/connection/websocket/AutoCertifierClientFacade.js.map +1 -1
  62. package/dist/src/connection/websocket/ClientWebsocket.d.ts +1 -0
  63. package/dist/src/connection/websocket/ClientWebsocket.js +14 -7
  64. package/dist/src/connection/websocket/ClientWebsocket.js.map +1 -1
  65. package/dist/src/connection/websocket/WebsocketConnector.d.ts +3 -9
  66. package/dist/src/connection/websocket/WebsocketConnector.js +142 -74
  67. package/dist/src/connection/websocket/WebsocketConnector.js.map +1 -1
  68. package/dist/src/connection/websocket/WebsocketConnectorRpcLocal.d.ts +5 -3
  69. package/dist/src/connection/websocket/WebsocketConnectorRpcLocal.js +9 -12
  70. package/dist/src/connection/websocket/WebsocketConnectorRpcLocal.js.map +1 -1
  71. package/dist/src/connection/websocket/WebsocketConnectorRpcRemote.d.ts +4 -7
  72. package/dist/src/connection/websocket/WebsocketConnectorRpcRemote.js +7 -44
  73. package/dist/src/connection/websocket/WebsocketConnectorRpcRemote.js.map +1 -1
  74. package/dist/src/connection/websocket/WebsocketServer.d.ts +1 -4
  75. package/dist/src/connection/websocket/WebsocketServer.js +49 -40
  76. package/dist/src/connection/websocket/WebsocketServer.js.map +1 -1
  77. package/dist/src/connection/websocket/{ServerWebsocket.d.ts → WebsocketServerConnection.d.ts} +8 -4
  78. package/dist/src/connection/websocket/WebsocketServerConnection.js +97 -0
  79. package/dist/src/connection/websocket/WebsocketServerConnection.js.map +1 -0
  80. package/dist/src/dht/DhtNode.d.ts +45 -49
  81. package/dist/src/dht/DhtNode.js +229 -317
  82. package/dist/src/dht/DhtNode.js.map +1 -1
  83. package/dist/src/dht/DhtNodeRpcLocal.d.ts +10 -9
  84. package/dist/src/dht/DhtNodeRpcLocal.js +19 -11
  85. package/dist/src/dht/DhtNodeRpcLocal.js.map +1 -1
  86. package/dist/src/dht/DhtNodeRpcRemote.d.ts +15 -10
  87. package/dist/src/dht/DhtNodeRpcRemote.js +38 -21
  88. package/dist/src/dht/DhtNodeRpcRemote.js.map +1 -1
  89. package/dist/src/dht/ExternalApiRpcLocal.d.ts +7 -6
  90. package/dist/src/dht/ExternalApiRpcLocal.js +9 -13
  91. package/dist/src/dht/ExternalApiRpcLocal.js.map +1 -1
  92. package/dist/src/dht/ExternalApiRpcRemote.d.ts +6 -5
  93. package/dist/src/dht/ExternalApiRpcRemote.js +10 -7
  94. package/dist/src/dht/ExternalApiRpcRemote.js.map +1 -1
  95. package/dist/src/dht/PeerManager.d.ts +61 -0
  96. package/dist/src/dht/PeerManager.js +288 -0
  97. package/dist/src/dht/PeerManager.js.map +1 -0
  98. package/dist/src/dht/contact/Contact.d.ts +2 -2
  99. package/dist/src/dht/contact/Contact.js +4 -3
  100. package/dist/src/dht/contact/Contact.js.map +1 -1
  101. package/dist/src/dht/contact/ContactList.d.ts +8 -8
  102. package/dist/src/dht/contact/ContactList.js +12 -7
  103. package/dist/src/dht/contact/ContactList.js.map +1 -1
  104. package/dist/src/dht/contact/RandomContactList.d.ts +4 -4
  105. package/dist/src/dht/contact/RandomContactList.js +13 -12
  106. package/dist/src/dht/contact/RandomContactList.js.map +1 -1
  107. package/dist/src/dht/contact/RingContactList.d.ts +31 -0
  108. package/dist/src/dht/contact/RingContactList.js +133 -0
  109. package/dist/src/dht/contact/RingContactList.js.map +1 -0
  110. package/dist/src/dht/contact/{Remote.d.ts → RpcRemote.d.ts} +8 -7
  111. package/dist/src/dht/contact/{Remote.js → RpcRemote.js} +16 -13
  112. package/dist/src/dht/contact/RpcRemote.js.map +1 -0
  113. package/dist/src/dht/contact/SortedContactList.d.ts +29 -15
  114. package/dist/src/dht/contact/SortedContactList.js +79 -42
  115. package/dist/src/dht/contact/SortedContactList.js.map +1 -1
  116. package/dist/src/dht/contact/ringIdentifiers.d.ts +16 -0
  117. package/dist/src/dht/contact/ringIdentifiers.js +54 -0
  118. package/dist/src/dht/contact/ringIdentifiers.js.map +1 -0
  119. package/dist/src/dht/discovery/DiscoverySession.d.ts +8 -18
  120. package/dist/src/dht/discovery/DiscoverySession.js +32 -48
  121. package/dist/src/dht/discovery/DiscoverySession.js.map +1 -1
  122. package/dist/src/dht/discovery/PeerDiscovery.d.ts +16 -12
  123. package/dist/src/dht/discovery/PeerDiscovery.js +82 -39
  124. package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
  125. package/dist/src/dht/discovery/RingDiscoverySession.d.ts +29 -0
  126. package/dist/src/dht/discovery/RingDiscoverySession.js +123 -0
  127. package/dist/src/dht/discovery/RingDiscoverySession.js.map +1 -0
  128. package/dist/src/dht/recursive-operation/RecursiveOperationManager.d.ts +36 -0
  129. package/dist/src/dht/recursive-operation/RecursiveOperationManager.js +166 -0
  130. package/dist/src/dht/recursive-operation/RecursiveOperationManager.js.map +1 -0
  131. package/dist/src/dht/recursive-operation/RecursiveOperationRpcLocal.d.ts +14 -0
  132. package/dist/src/dht/recursive-operation/RecursiveOperationRpcLocal.js +26 -0
  133. package/dist/src/dht/recursive-operation/RecursiveOperationRpcLocal.js.map +1 -0
  134. package/dist/src/dht/recursive-operation/RecursiveOperationRpcRemote.d.ts +6 -0
  135. package/dist/src/dht/recursive-operation/RecursiveOperationRpcRemote.js +44 -0
  136. package/dist/src/dht/recursive-operation/RecursiveOperationRpcRemote.js.map +1 -0
  137. package/dist/src/dht/recursive-operation/RecursiveOperationSession.d.ts +44 -0
  138. package/dist/src/dht/recursive-operation/RecursiveOperationSession.js +187 -0
  139. package/dist/src/dht/recursive-operation/RecursiveOperationSession.js.map +1 -0
  140. package/dist/src/dht/recursive-operation/RecursiveOperationSessionRpcLocal.d.ts +14 -0
  141. package/dist/src/dht/recursive-operation/RecursiveOperationSessionRpcLocal.js +20 -0
  142. package/dist/src/dht/recursive-operation/RecursiveOperationSessionRpcLocal.js.map +1 -0
  143. package/dist/src/dht/recursive-operation/RecursiveOperationSessionRpcRemote.d.ts +6 -0
  144. package/dist/src/dht/recursive-operation/RecursiveOperationSessionRpcRemote.js +21 -0
  145. package/dist/src/dht/recursive-operation/RecursiveOperationSessionRpcRemote.js.map +1 -0
  146. package/dist/src/dht/routing/DuplicateDetector.d.ts +2 -4
  147. package/dist/src/dht/routing/DuplicateDetector.js +10 -15
  148. package/dist/src/dht/routing/DuplicateDetector.js.map +1 -1
  149. package/dist/src/dht/routing/Router.d.ts +11 -27
  150. package/dist/src/dht/routing/Router.js +92 -58
  151. package/dist/src/dht/routing/Router.js.map +1 -1
  152. package/dist/src/dht/routing/RouterRpcLocal.d.ts +3 -4
  153. package/dist/src/dht/routing/RouterRpcLocal.js +17 -16
  154. package/dist/src/dht/routing/RouterRpcLocal.js.map +1 -1
  155. package/dist/src/dht/routing/RouterRpcRemote.d.ts +3 -3
  156. package/dist/src/dht/routing/RouterRpcRemote.js +29 -20
  157. package/dist/src/dht/routing/RouterRpcRemote.js.map +1 -1
  158. package/dist/src/dht/routing/RoutingSession.d.ts +29 -21
  159. package/dist/src/dht/routing/RoutingSession.js +93 -68
  160. package/dist/src/dht/routing/RoutingSession.js.map +1 -1
  161. package/dist/src/dht/routing/RoutingTablesCache.d.ts +24 -0
  162. package/dist/src/dht/routing/RoutingTablesCache.js +46 -0
  163. package/dist/src/dht/routing/RoutingTablesCache.js.map +1 -0
  164. package/dist/src/dht/routing/getPreviousPeer.js.map +1 -1
  165. package/dist/src/dht/store/LocalDataStore.d.ts +9 -14
  166. package/dist/src/dht/store/LocalDataStore.js +46 -72
  167. package/dist/src/dht/store/LocalDataStore.js.map +1 -1
  168. package/dist/src/dht/store/StoreManager.d.ts +33 -0
  169. package/dist/src/dht/store/StoreManager.js +182 -0
  170. package/dist/src/dht/store/StoreManager.js.map +1 -0
  171. package/dist/src/dht/store/StoreRpcLocal.d.ts +11 -41
  172. package/dist/src/dht/store/StoreRpcLocal.js +27 -234
  173. package/dist/src/dht/store/StoreRpcLocal.js.map +1 -1
  174. package/dist/src/dht/store/StoreRpcRemote.d.ts +6 -7
  175. package/dist/src/dht/store/StoreRpcRemote.js +10 -20
  176. package/dist/src/dht/store/StoreRpcRemote.js.map +1 -1
  177. package/dist/src/exports.d.ts +5 -3
  178. package/dist/src/exports.js +10 -8
  179. package/dist/src/exports.js.map +1 -1
  180. package/dist/src/helpers/AddressTools.js +2 -0
  181. package/dist/src/helpers/AddressTools.js.map +1 -1
  182. package/dist/src/helpers/Connectivity.js.map +1 -1
  183. package/dist/src/helpers/MapWithTtl.d.ts +14 -0
  184. package/dist/src/helpers/MapWithTtl.js +60 -0
  185. package/dist/src/helpers/MapWithTtl.js.map +1 -0
  186. package/dist/src/helpers/createPeerDescriptor.d.ts +3 -0
  187. package/dist/src/helpers/createPeerDescriptor.js +57 -0
  188. package/dist/src/helpers/createPeerDescriptor.js.map +1 -0
  189. package/dist/src/helpers/createPeerDescriptorSignaturePayload.d.ts +2 -0
  190. package/dist/src/helpers/createPeerDescriptorSignaturePayload.js +30 -0
  191. package/dist/src/helpers/createPeerDescriptorSignaturePayload.js.map +1 -0
  192. package/dist/src/helpers/debugHelpers.js.map +1 -1
  193. package/dist/src/helpers/errors.js +2 -0
  194. package/dist/src/helpers/errors.js.map +1 -1
  195. package/dist/src/helpers/offering.d.ts +4 -0
  196. package/dist/src/helpers/offering.js +18 -0
  197. package/dist/src/helpers/offering.js.map +1 -0
  198. package/dist/src/helpers/protoClasses.js +2 -3
  199. package/dist/src/helpers/protoClasses.js.map +1 -1
  200. package/dist/src/helpers/protoToString.js.map +1 -1
  201. package/dist/src/helpers/version.d.ts +6 -0
  202. package/dist/src/helpers/version.js +38 -0
  203. package/dist/src/helpers/version.js.map +1 -0
  204. package/dist/src/identifiers.d.ts +10 -0
  205. package/dist/src/identifiers.js +31 -0
  206. package/dist/src/identifiers.js.map +1 -0
  207. package/dist/src/proto/google/protobuf/any.js +8 -8
  208. package/dist/src/proto/google/protobuf/any.js.map +1 -1
  209. package/dist/src/proto/google/protobuf/empty.js +2 -4
  210. package/dist/src/proto/google/protobuf/empty.js.map +1 -1
  211. package/dist/src/proto/google/protobuf/timestamp.js +10 -10
  212. package/dist/src/proto/google/protobuf/timestamp.js.map +1 -1
  213. package/dist/src/proto/packages/dht/protos/DhtRpc.client.d.ts +46 -49
  214. package/dist/src/proto/packages/dht/protos/DhtRpc.client.js +63 -54
  215. package/dist/src/proto/packages/dht/protos/DhtRpc.client.js.map +1 -1
  216. package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +226 -232
  217. package/dist/src/proto/packages/dht/protos/DhtRpc.js +146 -168
  218. package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -1
  219. package/dist/src/proto/packages/dht/protos/DhtRpc.server.d.ts +26 -29
  220. package/dist/src/proto/packages/proto-rpc/protos/ProtoRpc.js +1 -1
  221. package/dist/src/rpc-protocol/DhtCallContext.d.ts +2 -2
  222. package/dist/src/rpc-protocol/DhtCallContext.js +8 -0
  223. package/dist/src/rpc-protocol/DhtCallContext.js.map +1 -1
  224. package/dist/src/rpc-protocol/DhtRpcOptions.d.ts +2 -1
  225. package/dist/src/transport/ITransport.d.ts +10 -2
  226. package/dist/src/transport/ITransport.js +5 -0
  227. package/dist/src/transport/ITransport.js.map +1 -1
  228. package/dist/src/transport/ListeningRpcCommunicator.js +3 -1
  229. package/dist/src/transport/ListeningRpcCommunicator.js.map +1 -1
  230. package/dist/src/transport/RoutingRpcCommunicator.d.ts +4 -2
  231. package/dist/src/transport/RoutingRpcCommunicator.js +19 -12
  232. package/dist/src/transport/RoutingRpcCommunicator.js.map +1 -1
  233. package/jest.config.js +4 -1
  234. package/karma-setup.js +2 -0
  235. package/karma.config.js +13 -9
  236. package/package.json +17 -14
  237. package/protos/DhtRpc.proto +76 -76
  238. package/src/connection/Connection.ts +6 -1
  239. package/src/connection/ConnectionLockHandler.ts +30 -22
  240. package/src/connection/ConnectionLockRpcLocal.ts +7 -12
  241. package/src/connection/ConnectionLockRpcRemote.ts +9 -19
  242. package/src/connection/ConnectionManager.ts +132 -138
  243. package/src/connection/ConnectorFacade.ts +10 -9
  244. package/src/connection/Handshaker.ts +24 -12
  245. package/src/connection/IConnection.ts +2 -8
  246. package/src/connection/ManagedConnection.ts +34 -35
  247. package/src/connection/connectivityChecker.ts +109 -0
  248. package/src/connection/connectivityRequestHandler.ts +103 -0
  249. package/src/connection/simulator/Simulator.ts +6 -37
  250. package/src/connection/simulator/SimulatorConnection.ts +23 -25
  251. package/src/connection/simulator/SimulatorConnector.ts +11 -11
  252. package/src/connection/webrtc/BrowserWebrtcConnection.ts +17 -25
  253. package/src/connection/webrtc/NodeWebrtcConnection.ts +25 -27
  254. package/src/connection/webrtc/WebrtcConnector.ts +31 -36
  255. package/src/connection/webrtc/WebrtcConnectorRpcLocal.ts +31 -25
  256. package/src/connection/webrtc/WebrtcConnectorRpcRemote.ts +4 -14
  257. package/src/connection/webrtc/iceServerAsString.ts +1 -1
  258. package/src/connection/websocket/AutoCertifierClientFacade.ts +4 -6
  259. package/src/connection/websocket/ClientWebsocket.ts +10 -4
  260. package/src/connection/websocket/WebsocketConnector.ts +120 -97
  261. package/src/connection/websocket/WebsocketConnectorRpcLocal.ts +13 -15
  262. package/src/connection/websocket/WebsocketConnectorRpcRemote.ts +7 -27
  263. package/src/connection/websocket/WebsocketServer.ts +50 -53
  264. package/src/connection/websocket/WebsocketServerConnection.ts +104 -0
  265. package/src/dht/DhtNode.ts +289 -410
  266. package/src/dht/DhtNodeRpcLocal.ts +25 -17
  267. package/src/dht/DhtNodeRpcRemote.ts +43 -27
  268. package/src/dht/ExternalApiRpcLocal.ts +30 -17
  269. package/src/dht/ExternalApiRpcRemote.ts +14 -11
  270. package/src/dht/PeerManager.ts +339 -0
  271. package/src/dht/contact/Contact.ts +4 -4
  272. package/src/dht/contact/ContactList.ts +11 -10
  273. package/src/dht/contact/RandomContactList.ts +15 -15
  274. package/src/dht/contact/RingContactList.ts +151 -0
  275. package/src/dht/contact/{Remote.ts → RpcRemote.ts} +16 -19
  276. package/src/dht/contact/SortedContactList.ts +120 -72
  277. package/src/dht/contact/ringIdentifiers.ts +62 -0
  278. package/src/dht/discovery/DiscoverySession.ts +36 -61
  279. package/src/dht/discovery/PeerDiscovery.ts +98 -43
  280. package/src/dht/discovery/RingDiscoverySession.ts +160 -0
  281. package/src/dht/recursive-operation/RecursiveOperationManager.ts +246 -0
  282. package/src/dht/recursive-operation/RecursiveOperationRpcLocal.ts +34 -0
  283. package/src/dht/recursive-operation/RecursiveOperationRpcRemote.ts +43 -0
  284. package/src/dht/recursive-operation/RecursiveOperationSession.ts +232 -0
  285. package/src/dht/recursive-operation/RecursiveOperationSessionRpcLocal.ts +35 -0
  286. package/src/dht/recursive-operation/RecursiveOperationSessionRpcRemote.ts +30 -0
  287. package/src/dht/routing/DuplicateDetector.ts +9 -21
  288. package/src/dht/routing/Router.ts +95 -92
  289. package/src/dht/routing/RouterRpcLocal.ts +16 -18
  290. package/src/dht/routing/RouterRpcRemote.ts +26 -24
  291. package/src/dht/routing/RoutingSession.ts +119 -98
  292. package/src/dht/routing/RoutingTablesCache.ts +58 -0
  293. package/src/dht/routing/getPreviousPeer.ts +1 -1
  294. package/src/dht/store/LocalDataStore.ts +47 -77
  295. package/src/dht/store/StoreManager.ts +209 -0
  296. package/src/dht/store/StoreRpcLocal.ts +39 -308
  297. package/src/dht/store/StoreRpcRemote.ts +13 -31
  298. package/src/exports.ts +13 -3
  299. package/src/helpers/AddressTools.ts +2 -0
  300. package/src/helpers/MapWithTtl.ts +71 -0
  301. package/src/helpers/createPeerDescriptor.ts +57 -0
  302. package/src/helpers/createPeerDescriptorSignaturePayload.ts +28 -0
  303. package/src/helpers/offering.ts +15 -0
  304. package/src/helpers/protoClasses.ts +4 -6
  305. package/src/helpers/version.ts +32 -0
  306. package/src/identifiers.ts +29 -0
  307. package/src/proto/google/protobuf/any.ts +4 -4
  308. package/src/proto/google/protobuf/empty.ts +2 -4
  309. package/src/proto/google/protobuf/timestamp.ts +4 -4
  310. package/src/proto/packages/dht/protos/DhtRpc.client.ts +65 -68
  311. package/src/proto/packages/dht/protos/DhtRpc.server.ts +27 -30
  312. package/src/proto/packages/dht/protos/DhtRpc.ts +297 -313
  313. package/src/proto/packages/proto-rpc/protos/ProtoRpc.ts +1 -1
  314. package/src/rpc-protocol/DhtCallContext.ts +2 -2
  315. package/src/rpc-protocol/DhtRpcOptions.ts +2 -1
  316. package/src/transport/ITransport.ts +11 -2
  317. package/src/transport/ListeningRpcCommunicator.ts +1 -1
  318. package/src/transport/RoutingRpcCommunicator.ts +21 -14
  319. package/test/RandomGraphSimulation.ts +3 -2
  320. package/test/benchmark/Find.test.ts +13 -28
  321. package/test/benchmark/KademliaCorrectness.test.ts +24 -28
  322. package/test/benchmark/RingCorrectness.test.ts +157 -0
  323. package/test/benchmark/SortedContactListBenchmark.test.ts +151 -0
  324. package/test/benchmark/WebsocketServerMemoryLeak.test.ts +41 -0
  325. package/test/benchmark/hybrid-network-simulation/RingContactList.test.ts +72 -0
  326. package/test/benchmark/kademlia-simulation/Contact.ts +9 -9
  327. package/test/benchmark/kademlia-simulation/KademliaSimulation.ts +11 -11
  328. package/test/benchmark/kademlia-simulation/SimulationNode.ts +29 -25
  329. package/test/data/generateGroundTruthData.ts +7 -6
  330. package/test/end-to-end/Layer0-Layer1.test.ts +11 -15
  331. package/test/end-to-end/Layer0.test.ts +19 -22
  332. package/test/end-to-end/Layer0MixedConnectionTypes.test.ts +19 -21
  333. package/test/end-to-end/Layer0Webrtc-Layer1.test.ts +26 -28
  334. package/test/end-to-end/Layer0Webrtc.test.ts +19 -19
  335. package/test/end-to-end/Layer1-Scale-WebSocket.test.ts +10 -18
  336. package/test/end-to-end/Layer1-Scale-Webrtc.test.ts +8 -15
  337. package/test/end-to-end/RecoveryFromFailedAutoCertification.test.ts +2 -2
  338. package/test/end-to-end/WebsocketConnectionRequest.test.ts +8 -9
  339. package/test/end-to-end/memory-leak.test.ts +19 -24
  340. package/test/integration/ConnectionLocking.test.ts +66 -60
  341. package/test/integration/ConnectionManager.test.ts +43 -63
  342. package/test/integration/ConnectivityChecking.test.ts +52 -0
  343. package/test/integration/DhtJoinPeerDiscovery.test.ts +8 -12
  344. package/test/integration/DhtNodeExternalAPI.test.ts +17 -21
  345. package/test/integration/DhtNodeRpcRemote.test.ts +19 -26
  346. package/test/integration/DhtRpc.test.ts +20 -24
  347. package/test/integration/Find.test.ts +10 -12
  348. package/test/integration/Layer1-scale.test.ts +25 -37
  349. package/test/integration/Mock-Layer1-Layer0.test.ts +39 -59
  350. package/test/integration/MultipleEntryPointJoining.test.ts +14 -14
  351. package/test/integration/ReplicateData.test.ts +106 -0
  352. package/test/integration/RouteMessage.test.ts +42 -68
  353. package/test/integration/RouterRpcRemote.test.ts +19 -24
  354. package/test/integration/ScaleDownDht.test.ts +14 -12
  355. package/test/integration/SimultaneousConnections.test.ts +112 -111
  356. package/test/integration/Store.test.ts +43 -27
  357. package/test/integration/StoreAndDelete.test.ts +36 -48
  358. package/test/integration/StoreOnDhtWithThreeNodes.test.ts +59 -0
  359. package/test/integration/StoreOnDhtWithTwoNodes.test.ts +17 -37
  360. package/test/integration/StoreRpcRemote.test.ts +20 -32
  361. package/test/integration/WebrtcConnectionManagement.test.ts +39 -25
  362. package/test/integration/WebrtcConnectorRpc.test.ts +6 -11
  363. package/test/integration/WebsocketConnectionManagement.test.ts +87 -22
  364. package/test/integration/WebsocketConnectorRpc.test.ts +14 -24
  365. package/test/integration/{RpcErrors.test.ts → rpc-connections-over-webrpc.test.ts} +15 -26
  366. package/test/unit/AddressTools.test.ts +4 -0
  367. package/test/unit/ConnectivityHelpers.test.ts +9 -17
  368. package/test/unit/DuplicateDetector.test.ts +8 -5
  369. package/test/unit/LocalDataStore.test.ts +78 -75
  370. package/test/unit/PeerManager.test.ts +33 -0
  371. package/test/unit/RandomContactList.test.ts +12 -9
  372. package/test/unit/RecursiveOperationManager.test.ts +157 -0
  373. package/test/unit/RecursiveOperationSession.test.ts +68 -0
  374. package/test/unit/Router.test.ts +52 -35
  375. package/test/unit/RoutingSession.test.ts +79 -0
  376. package/test/unit/SortedContactList.test.ts +61 -30
  377. package/test/unit/StoreManager.test.ts +138 -0
  378. package/test/unit/WebsocketConnector.test.ts +27 -35
  379. package/test/unit/connectivityRequestHandler.test.ts +104 -0
  380. package/test/unit/createPeerDescriptor.test.ts +69 -0
  381. package/test/unit/customMatchers.test.ts +16 -0
  382. package/test/unit/version.test.ts +18 -0
  383. package/test/utils/FakeTransport.ts +47 -0
  384. package/test/utils/customMatchers.ts +71 -0
  385. package/test/utils/mock/MockRpcCommunicator.ts +7 -0
  386. package/test/utils/mock/Router.ts +13 -3
  387. package/test/utils/mock/Transport.ts +1 -1
  388. package/test/utils/mock/mockDataEntry.ts +38 -0
  389. package/test/utils/utils.ts +104 -107
  390. package/tsconfig.browser.json +2 -1
  391. package/tsconfig.jest.json +4 -2
  392. package/tsconfig.node.json +4 -2
  393. package/dist/src/connection/ConnectivityChecker.d.ts +0 -17
  394. package/dist/src/connection/ConnectivityChecker.js +0 -208
  395. package/dist/src/connection/ConnectivityChecker.js.map +0 -1
  396. package/dist/src/connection/websocket/ServerWebsocket.js +0 -100
  397. package/dist/src/connection/websocket/ServerWebsocket.js.map +0 -1
  398. package/dist/src/dht/contact/Remote.js.map +0 -1
  399. package/dist/src/dht/find/FindRpcLocal.d.ts +0 -14
  400. package/dist/src/dht/find/FindRpcLocal.js +0 -25
  401. package/dist/src/dht/find/FindRpcLocal.js.map +0 -1
  402. package/dist/src/dht/find/FindSession.d.ts +0 -44
  403. package/dist/src/dht/find/FindSession.js +0 -145
  404. package/dist/src/dht/find/FindSession.js.map +0 -1
  405. package/dist/src/dht/find/FindSessionRpcLocal.d.ts +0 -12
  406. package/dist/src/dht/find/FindSessionRpcLocal.js +0 -17
  407. package/dist/src/dht/find/FindSessionRpcLocal.js.map +0 -1
  408. package/dist/src/dht/find/FindSessionRpcRemote.d.ts +0 -6
  409. package/dist/src/dht/find/FindSessionRpcRemote.js +0 -21
  410. package/dist/src/dht/find/FindSessionRpcRemote.js.map +0 -1
  411. package/dist/src/dht/find/Finder.d.ts +0 -49
  412. package/dist/src/dht/find/Finder.js +0 -184
  413. package/dist/src/dht/find/Finder.js.map +0 -1
  414. package/dist/src/dht/routing/FindRpcRemote.d.ts +0 -6
  415. package/dist/src/dht/routing/FindRpcRemote.js +0 -41
  416. package/dist/src/dht/routing/FindRpcRemote.js.map +0 -1
  417. package/dist/src/helpers/PeerID.d.ts +0 -24
  418. package/dist/src/helpers/PeerID.js +0 -78
  419. package/dist/src/helpers/PeerID.js.map +0 -1
  420. package/dist/src/helpers/UUID.d.ts +0 -8
  421. package/dist/src/helpers/UUID.js +0 -36
  422. package/dist/src/helpers/UUID.js.map +0 -1
  423. package/dist/src/helpers/kademliaId.d.ts +0 -1
  424. package/dist/src/helpers/kademliaId.js +0 -14
  425. package/dist/src/helpers/kademliaId.js.map +0 -1
  426. package/dist/src/helpers/peerIdFromPeerDescriptor.d.ts +0 -6
  427. package/dist/src/helpers/peerIdFromPeerDescriptor.js +0 -23
  428. package/dist/src/helpers/peerIdFromPeerDescriptor.js.map +0 -1
  429. package/src/connection/ConnectivityChecker.ts +0 -199
  430. package/src/connection/websocket/ServerWebsocket.ts +0 -114
  431. package/src/dht/find/FindRpcLocal.ts +0 -35
  432. package/src/dht/find/FindSession.ts +0 -178
  433. package/src/dht/find/FindSessionRpcLocal.ts +0 -25
  434. package/src/dht/find/FindSessionRpcRemote.ts +0 -30
  435. package/src/dht/find/Finder.ts +0 -275
  436. package/src/dht/routing/FindRpcRemote.ts +0 -40
  437. package/src/helpers/PeerID.ts +0 -88
  438. package/src/helpers/UUID.ts +0 -35
  439. package/src/helpers/kademliaId.ts +0 -8
  440. package/src/helpers/peerIdFromPeerDescriptor.ts +0 -20
  441. package/test/integration/MigrateData.test.ts +0 -204
  442. package/test/unit/Finder.test.ts +0 -110
  443. package/test/unit/PeerID.test.ts +0 -22
  444. package/test/unit/UUID.test.ts +0 -55
@@ -1,48 +1,72 @@
1
1
  import { DiscoverySession } from './DiscoverySession'
2
2
  import { DhtNodeRpcRemote } from '../DhtNodeRpcRemote'
3
- import { areEqualPeerDescriptors, getNodeIdFromPeerDescriptor, peerIdFromPeerDescriptor } from '../../helpers/peerIdFromPeerDescriptor'
4
3
  import { PeerDescriptor } from '../../proto/packages/dht/protos/DhtRpc'
5
4
  import { Logger, scheduleAtInterval, setAbortableTimeout } from '@streamr/utils'
6
- import KBucket from 'k-bucket'
7
- import { SortedContactList } from '../contact/SortedContactList'
8
5
  import { ConnectionManager } from '../../connection/ConnectionManager'
9
- import { RoutingRpcCommunicator } from '../../transport/RoutingRpcCommunicator'
10
- import { createRandomKademliaId } from '../../helpers/kademliaId'
6
+ import { PeerManager } from '../PeerManager'
7
+ import { DhtAddress, areEqualPeerDescriptors, getDhtAddressFromRaw, getNodeIdFromPeerDescriptor, getRawFromDhtAddress } from '../../identifiers'
11
8
  import { ServiceID } from '../../types/ServiceID'
9
+ import { RingDiscoverySession } from './RingDiscoverySession'
10
+ import { RingIdRaw, getRingIdRawFromPeerDescriptor } from '../contact/ringIdentifiers'
12
11
 
13
12
  interface PeerDiscoveryConfig {
14
- rpcCommunicator: RoutingRpcCommunicator
15
13
  localPeerDescriptor: PeerDescriptor
16
- bucket: KBucket<DhtNodeRpcRemote>
17
- neighborList: SortedContactList<DhtNodeRpcRemote>
18
14
  joinNoProgressLimit: number
19
15
  peerDiscoveryQueryBatchSize: number
20
16
  serviceId: ServiceID
21
17
  parallelism: number
22
18
  joinTimeout: number
23
- addContact: (contact: PeerDescriptor, setActive?: boolean) => void
24
19
  connectionManager?: ConnectionManager
25
- rpcRequestTimeout?: number
20
+ peerManager: PeerManager
21
+ }
22
+
23
+ export const createDistantDhtAddress = (address: DhtAddress): DhtAddress => {
24
+ const raw = getRawFromDhtAddress(address)
25
+ const flipped = raw.map((val) => ~val)
26
+ return getDhtAddressFromRaw(flipped)
26
27
  }
27
28
 
28
29
  const logger = new Logger(module)
29
30
 
30
31
  export class PeerDiscovery {
31
32
 
32
- private readonly config: PeerDiscoveryConfig
33
33
  private ongoingDiscoverySessions: Map<string, DiscoverySession> = new Map()
34
+ private ongoingRingDiscoverySessions: Map<string, RingDiscoverySession> = new Map()
35
+
34
36
  private rejoinOngoing = false
35
37
  private joinCalled = false
36
- private rejoinTimeoutRef?: NodeJS.Timeout
37
38
  private readonly abortController: AbortController
38
39
  private recoveryIntervalStarted = false
40
+ private readonly config: PeerDiscoveryConfig
39
41
 
40
42
  constructor(config: PeerDiscoveryConfig) {
41
43
  this.config = config
42
44
  this.abortController = new AbortController()
43
45
  }
44
46
 
45
- async joinDht(entryPointDescriptor: PeerDescriptor, doAdditionalRandomPeerDiscovery = true, retry = true): Promise<void> {
47
+ async joinDht(
48
+ entryPoints: PeerDescriptor[],
49
+ doAdditionalDistantPeerDiscovery = true,
50
+ retry = true
51
+ ): Promise<void> {
52
+ const contactedPeers = new Set<DhtAddress>()
53
+ const distantJoinConfig = doAdditionalDistantPeerDiscovery
54
+ ? { enabled: true, contactedPeers: new Set<DhtAddress>() } : { enabled: false } as const
55
+ await Promise.all(entryPoints.map((entryPoint) => this.joinThroughEntryPoint(
56
+ entryPoint,
57
+ contactedPeers,
58
+ distantJoinConfig,
59
+ retry
60
+ )))
61
+ }
62
+
63
+ async joinThroughEntryPoint(
64
+ entryPointDescriptor: PeerDescriptor,
65
+ // Note that this set is mutated by DiscoverySession
66
+ contactedPeers: Set<DhtAddress>,
67
+ additionalDistantJoin: { enabled: true, contactedPeers: Set<DhtAddress> } | { enabled: false },
68
+ retry = true
69
+ ): Promise<void> {
46
70
  if (this.isStopped()) {
47
71
  return
48
72
  }
@@ -55,53 +79,79 @@ export class PeerDiscovery {
55
79
  return
56
80
  }
57
81
  this.config.connectionManager?.lockConnection(entryPointDescriptor, `${this.config.serviceId}::joinDht`)
58
- this.config.addContact(entryPointDescriptor)
59
- const targetId = peerIdFromPeerDescriptor(this.config.localPeerDescriptor).value
60
- const closest = this.config.bucket.closest(targetId, this.config.peerDiscoveryQueryBatchSize)
61
- this.config.neighborList.addContacts(closest)
62
- const sessions = [this.createSession(targetId)]
63
- if (doAdditionalRandomPeerDiscovery) {
64
- sessions.push(this.createSession(createRandomKademliaId()))
82
+ this.config.peerManager.addContact([entryPointDescriptor])
83
+ const targetId = getNodeIdFromPeerDescriptor(this.config.localPeerDescriptor)
84
+ const sessions = [this.createSession(targetId, contactedPeers)]
85
+ if (additionalDistantJoin.enabled) {
86
+ sessions.push(this.createSession(createDistantDhtAddress(targetId), additionalDistantJoin.contactedPeers))
65
87
  }
66
88
  await this.runSessions(sessions, entryPointDescriptor, retry)
67
89
  this.config.connectionManager?.unlockConnection(entryPointDescriptor, `${this.config.serviceId}::joinDht`)
68
90
 
69
91
  }
70
92
 
71
- private createSession(targetId: Uint8Array): DiscoverySession {
93
+ async joinRing(): Promise<void> {
94
+ const contactedPeers = new Set<DhtAddress>()
95
+ const sessions = [this.createRingSession(getRingIdRawFromPeerDescriptor(this.config.localPeerDescriptor), contactedPeers)]
96
+ await this.runRingSessions(sessions)
97
+ }
98
+
99
+ private createSession(targetId: DhtAddress, contactedPeers: Set<DhtAddress>): DiscoverySession {
72
100
  const sessionOptions = {
73
- bucket: this.config.bucket,
74
- neighborList: this.config.neighborList,
75
101
  targetId,
76
- localPeerDescriptor: this.config.localPeerDescriptor,
77
- serviceId: this.config.serviceId,
78
- rpcCommunicator: this.config.rpcCommunicator,
79
102
  parallelism: this.config.parallelism,
80
103
  noProgressLimit: this.config.joinNoProgressLimit,
81
- newContactListener: (newPeer: DhtNodeRpcRemote) => this.config.addContact(newPeer.getPeerDescriptor())
104
+ peerManager: this.config.peerManager,
105
+ contactedPeers
82
106
  }
83
107
  return new DiscoverySession(sessionOptions)
84
108
  }
85
109
 
110
+ private createRingSession(targetId: RingIdRaw, contactedPeers: Set<DhtAddress>): RingDiscoverySession {
111
+ const sessionOptions = {
112
+ targetId,
113
+ parallelism: this.config.parallelism,
114
+ noProgressLimit: this.config.joinNoProgressLimit,
115
+ peerManager: this.config.peerManager,
116
+ contactedPeers
117
+ }
118
+ return new RingDiscoverySession(sessionOptions)
119
+ }
120
+
86
121
  private async runSessions(sessions: DiscoverySession[], entryPointDescriptor: PeerDescriptor, retry: boolean): Promise<void> {
87
122
  try {
88
123
  for (const session of sessions) {
89
- this.ongoingDiscoverySessions.set(session.sessionId, session)
124
+ this.ongoingDiscoverySessions.set(session.id, session)
90
125
  await session.findClosestNodes(this.config.joinTimeout)
91
126
  }
92
127
  } catch (_e) {
93
128
  logger.debug(`DHT join on ${this.config.serviceId} timed out`)
94
129
  } finally {
95
130
  if (!this.isStopped()) {
96
- if (this.config.bucket.count() === 0) {
131
+ if (this.config.peerManager.getNeighborCount() === 0) {
97
132
  if (retry) {
133
+ // TODO should we catch possible promise rejection?
134
+ // TODO use config option or named constant?
98
135
  setAbortableTimeout(() => this.rejoinDht(entryPointDescriptor), 1000, this.abortController.signal)
99
136
  }
100
137
  } else {
101
138
  await this.ensureRecoveryIntervalIsRunning()
102
139
  }
103
140
  }
104
- sessions.forEach((session) => this.ongoingDiscoverySessions.delete(session.sessionId))
141
+ sessions.forEach((session) => this.ongoingDiscoverySessions.delete(session.id))
142
+ }
143
+ }
144
+
145
+ private async runRingSessions(sessions: RingDiscoverySession[]): Promise<void> {
146
+ try {
147
+ for (const session of sessions) {
148
+ this.ongoingRingDiscoverySessions.set(session.id, session)
149
+ await session.findClosestNodes(this.config.joinTimeout)
150
+ }
151
+ } catch (_e) {
152
+ logger.debug(`Ring join on ${this.config.serviceId} timed out`)
153
+ } finally {
154
+ sessions.forEach((session) => this.ongoingDiscoverySessions.delete(session.id))
105
155
  }
106
156
  }
107
157
 
@@ -112,12 +162,13 @@ export class PeerDiscovery {
112
162
  logger.debug(`Rejoining DHT ${this.config.serviceId}`)
113
163
  this.rejoinOngoing = true
114
164
  try {
115
- this.config.neighborList.clear()
116
- await this.joinDht(entryPoint)
165
+ await this.joinThroughEntryPoint(entryPoint, new Set(), { enabled: false })
117
166
  logger.debug(`Rejoined DHT successfully ${this.config.serviceId}!`)
118
167
  } catch (err) {
119
168
  logger.warn(`Rejoining DHT ${this.config.serviceId} failed`)
120
169
  if (!this.isStopped()) {
170
+ // TODO should we catch possible promise rejection?
171
+ // TODO use config option or named constant?
121
172
  setAbortableTimeout(() => this.rejoinDht(entryPoint), 5000, this.abortController.signal)
122
173
  }
123
174
  } finally {
@@ -128,6 +179,7 @@ export class PeerDiscovery {
128
179
  private async ensureRecoveryIntervalIsRunning(): Promise<void> {
129
180
  if (!this.recoveryIntervalStarted) {
130
181
  this.recoveryIntervalStarted = true
182
+ // TODO use config option or named constant?
131
183
  await scheduleAtInterval(() => this.fetchClosestPeersFromBucket(), 60000, true, this.abortController.signal)
132
184
  }
133
185
  }
@@ -136,13 +188,17 @@ export class PeerDiscovery {
136
188
  if (this.isStopped()) {
137
189
  return
138
190
  }
139
- const nodes = this.config.bucket.closest(peerIdFromPeerDescriptor(this.config.localPeerDescriptor).value, this.config.parallelism)
140
- await Promise.allSettled(nodes.map(async (peer: DhtNodeRpcRemote) => {
141
- const contacts = await peer.getClosestPeers(this.config.localPeerDescriptor.kademliaId)
142
- contacts.forEach((contact) => {
143
- this.config.addContact(contact)
191
+ const localNodeId = getNodeIdFromPeerDescriptor(this.config.localPeerDescriptor)
192
+ const nodes = this.config.peerManager.getClosestNeighborsTo(
193
+ localNodeId,
194
+ this.config.parallelism
195
+ )
196
+ await Promise.allSettled(
197
+ nodes.map(async (peer: DhtNodeRpcRemote) => {
198
+ const contacts = await peer.getClosestPeers(localNodeId)
199
+ this.config.peerManager.addContact(contacts)
144
200
  })
145
- }))
201
+ )
146
202
  }
147
203
 
148
204
  public isJoinOngoing(): boolean {
@@ -159,11 +215,10 @@ export class PeerDiscovery {
159
215
 
160
216
  public stop(): void {
161
217
  this.abortController.abort()
162
- if (this.rejoinTimeoutRef) {
163
- clearTimeout(this.rejoinTimeoutRef)
164
- this.rejoinTimeoutRef = undefined
165
- }
166
- this.ongoingDiscoverySessions.forEach((session, _id) => {
218
+ this.ongoingDiscoverySessions.forEach((session) => {
219
+ session.stop()
220
+ })
221
+ this.ongoingRingDiscoverySessions.forEach((session) => {
167
222
  session.stop()
168
223
  })
169
224
  }
@@ -0,0 +1,160 @@
1
+ import { Logger, runAndWaitForEvents3 } from '@streamr/utils'
2
+ import EventEmitter from 'eventemitter3'
3
+ import { v4 } from 'uuid'
4
+ import { PeerDescriptor } from '../../proto/packages/dht/protos/DhtRpc'
5
+ import { PeerManager } from '../PeerManager'
6
+ import { DhtNodeRpcRemote } from '../DhtNodeRpcRemote'
7
+ import { DhtAddress, getNodeIdFromPeerDescriptor } from '../../identifiers'
8
+ import { RingId, RingIdRaw, getLeftDistance, getRingIdFromPeerDescriptor, getRingIdFromRaw } from '../contact/ringIdentifiers'
9
+ import { RingContacts } from '../contact/RingContactList'
10
+
11
+ const logger = new Logger(module)
12
+
13
+ interface RingDiscoverySessionEvents {
14
+ discoveryCompleted: () => void
15
+ }
16
+
17
+ interface RingDiscoverySessionConfig {
18
+ targetId: RingIdRaw
19
+ parallelism: number
20
+ noProgressLimit: number
21
+ peerManager: PeerManager
22
+ // Note that contacted peers will be mutated by the DiscoverySession or other parallel sessions
23
+ contactedPeers: Set<DhtAddress>
24
+ }
25
+
26
+ export class RingDiscoverySession {
27
+
28
+ public readonly id = v4()
29
+ private stopped = false
30
+ private emitter = new EventEmitter<RingDiscoverySessionEvents>()
31
+ private noProgressCounter = 0
32
+ private ongoingClosestPeersRequests: Set<DhtAddress> = new Set()
33
+ private readonly config: RingDiscoverySessionConfig
34
+ private numContactedPeers = 0
35
+ private targetIdAsRingId: RingId
36
+
37
+ constructor(config: RingDiscoverySessionConfig) {
38
+ this.config = config
39
+ this.targetIdAsRingId = getRingIdFromRaw(this.config.targetId)
40
+ }
41
+
42
+ private addContacts(contacts: PeerDescriptor[]): void {
43
+ if (this.stopped) {
44
+ return
45
+ }
46
+ this.config.peerManager.addContact(contacts)
47
+ }
48
+
49
+ private async getClosestPeersFromContact(contact: DhtNodeRpcRemote): Promise<RingContacts> {
50
+ if (this.stopped) {
51
+ return { left: [], right: [] }
52
+ }
53
+ logger.trace(`Getting closest ring peers from contact: ${getNodeIdFromPeerDescriptor(contact.getPeerDescriptor())}`)
54
+ this.numContactedPeers++
55
+ this.config.contactedPeers.add(contact.getNodeId())
56
+ const returnedContacts = await contact.getClosestRingPeers(this.config.targetId)
57
+ this.config.peerManager.setContactActive(contact.getNodeId())
58
+ return returnedContacts
59
+ }
60
+
61
+ private onClosestPeersRequestSucceeded(nodeId: DhtAddress, contacts: RingContacts) {
62
+ if (!this.ongoingClosestPeersRequests.has(nodeId)) {
63
+ return
64
+ }
65
+ this.ongoingClosestPeersRequests.delete(nodeId)
66
+ const oldClosestContacts = this.config.peerManager.getClosestRingContactsTo(this.config.targetId, 1)
67
+ const oldClosestLeftDistance = getLeftDistance(
68
+ this.targetIdAsRingId,
69
+ getRingIdFromPeerDescriptor(oldClosestContacts.left[0].getPeerDescriptor())
70
+ )
71
+ const oldClosestRightDistance = getLeftDistance(
72
+ this.targetIdAsRingId,
73
+ getRingIdFromPeerDescriptor(oldClosestContacts.right[0].getPeerDescriptor())
74
+ )
75
+ this.addContacts(contacts.left.concat(contacts.right))
76
+ const newClosestContacts = this.config.peerManager.getClosestRingContactsTo(this.config.targetId, 1)
77
+ const newClosestLeftDistance = getLeftDistance(this.targetIdAsRingId,
78
+ getRingIdFromPeerDescriptor(newClosestContacts.left[0].getPeerDescriptor()))
79
+ const newClosestRightDistance = getLeftDistance(this.targetIdAsRingId,
80
+ getRingIdFromPeerDescriptor(newClosestContacts.right[0].getPeerDescriptor()))
81
+ if (newClosestLeftDistance >= oldClosestLeftDistance && newClosestRightDistance >= oldClosestRightDistance) {
82
+ this.noProgressCounter++
83
+ }
84
+ }
85
+
86
+ private onClosestPeersRequestFailed(peer: DhtNodeRpcRemote) {
87
+ if (!this.ongoingClosestPeersRequests.has(peer.getNodeId())) {
88
+ return
89
+ }
90
+ this.ongoingClosestPeersRequests.delete(peer.getNodeId())
91
+ this.config.peerManager.removeContact(peer.getNodeId())
92
+ }
93
+
94
+ private findMoreContacts(): void {
95
+ if (this.stopped) {
96
+ return
97
+ }
98
+ const uncontacted = this.config.peerManager.getClosestRingContactsTo(
99
+ this.config.targetId,
100
+ this.config.parallelism,
101
+ this.config.contactedPeers
102
+ )
103
+ if ((uncontacted.left.length === 0 && uncontacted.right.length === 0)
104
+ || this.noProgressCounter >= this.config.noProgressLimit) {
105
+ this.emitter.emit('discoveryCompleted')
106
+ this.stopped = true
107
+ return
108
+ }
109
+ // ask from both sides equally
110
+ const merged = []
111
+ const alreadyInMerged: Set<DhtAddress> = new Set()
112
+ const length = Math.max(uncontacted.left.length, uncontacted.right.length)
113
+ for (let i = 0; i < length; i++) {
114
+ if (i < uncontacted.left.length) {
115
+ if (!alreadyInMerged.has(uncontacted.left[i].getNodeId())) {
116
+ merged.push(uncontacted.left[i])
117
+ alreadyInMerged.add(uncontacted.left[i].getNodeId())
118
+ }
119
+ }
120
+ if (i < uncontacted.right.length) {
121
+ if (!alreadyInMerged.has(uncontacted.right[i].getNodeId())) {
122
+ merged.push(uncontacted.right[i])
123
+ alreadyInMerged.add(uncontacted.right[i].getNodeId())
124
+ }
125
+ }
126
+ }
127
+
128
+ for (const nextPeer of merged) {
129
+ if (this.ongoingClosestPeersRequests.size >= this.config.parallelism) {
130
+ break
131
+ }
132
+ this.ongoingClosestPeersRequests.add(nextPeer.getNodeId())
133
+ // eslint-disable-next-line promise/catch-or-return
134
+ this.getClosestPeersFromContact(nextPeer)
135
+ .then((contacts) => this.onClosestPeersRequestSucceeded(nextPeer.getNodeId(), contacts))
136
+ .catch(() => this.onClosestPeersRequestFailed(nextPeer))
137
+ .finally(() => {
138
+ this.findMoreContacts()
139
+ })
140
+ }
141
+ }
142
+
143
+ public async findClosestNodes(timeout: number): Promise<void> {
144
+ if (this.config.peerManager.getContactCount(this.config.contactedPeers) === 0) {
145
+ return
146
+ }
147
+ // TODO add abortController and signal it in stop()
148
+ await runAndWaitForEvents3<RingDiscoverySessionEvents>(
149
+ [this.findMoreContacts.bind(this)],
150
+ [[this.emitter, 'discoveryCompleted']],
151
+ timeout
152
+ )
153
+ }
154
+
155
+ public stop(): void {
156
+ this.stopped = true
157
+ this.emitter.emit('discoveryCompleted')
158
+ this.emitter.removeAllListeners()
159
+ }
160
+ }
@@ -0,0 +1,246 @@
1
+ import {
2
+ DataEntry,
3
+ PeerDescriptor,
4
+ RecursiveOperation,
5
+ RecursiveOperationRequest,
6
+ RouteMessageAck,
7
+ RouteMessageError,
8
+ RouteMessageWrapper
9
+ } from '../../proto/packages/dht/protos/DhtRpc'
10
+ import { Router } from '../routing/Router'
11
+ import { RoutingMode } from '../routing/RoutingSession'
12
+ import { Logger, areEqualBinaries, runAndWaitForEvents3, wait } from '@streamr/utils'
13
+ import { RoutingRpcCommunicator } from '../../transport/RoutingRpcCommunicator'
14
+ import { RecursiveOperationSessionRpcRemote } from './RecursiveOperationSessionRpcRemote'
15
+ import { RecursiveOperationSession, RecursiveOperationSessionEvents } from './RecursiveOperationSession'
16
+ import { DhtNodeRpcRemote } from '../DhtNodeRpcRemote'
17
+ import { ITransport } from '../../transport/ITransport'
18
+ import { LocalDataStore } from '../store/LocalDataStore'
19
+ import { ListeningRpcCommunicator } from '../../transport/ListeningRpcCommunicator'
20
+ import { RecursiveOperationSessionRpcClient } from '../../proto/packages/dht/protos/DhtRpc.client'
21
+ import { SortedContactList } from '../contact/SortedContactList'
22
+ import { getPreviousPeer } from '../routing/getPreviousPeer'
23
+ import { createRouteMessageAck } from '../routing/RouterRpcLocal'
24
+ import { ServiceID } from '../../types/ServiceID'
25
+ import { RecursiveOperationRpcLocal } from './RecursiveOperationRpcLocal'
26
+ import { DhtAddress, areEqualPeerDescriptors, getDhtAddressFromRaw, getNodeIdFromPeerDescriptor, getRawFromDhtAddress } from '../../identifiers'
27
+ import { getDistance } from '../PeerManager'
28
+
29
+ interface RecursiveOperationManagerConfig {
30
+ rpcCommunicator: RoutingRpcCommunicator
31
+ sessionTransport: ITransport
32
+ connections: Map<DhtAddress, DhtNodeRpcRemote>
33
+ router: Router
34
+ localPeerDescriptor: PeerDescriptor
35
+ serviceId: ServiceID
36
+ localDataStore: LocalDataStore
37
+ addContact: (contact: PeerDescriptor) => void
38
+ }
39
+
40
+ export interface RecursiveOperationResult { closestNodes: Array<PeerDescriptor>, dataEntries?: Array<DataEntry> }
41
+
42
+ const logger = new Logger(module)
43
+
44
+ export class RecursiveOperationManager {
45
+
46
+ private ongoingSessions: Map<string, RecursiveOperationSession> = new Map()
47
+ private stopped = false
48
+ private readonly config: RecursiveOperationManagerConfig
49
+
50
+ constructor(config: RecursiveOperationManagerConfig) {
51
+ this.config = config
52
+ this.registerLocalRpcMethods()
53
+ }
54
+
55
+ private registerLocalRpcMethods() {
56
+ const rpcLocal = new RecursiveOperationRpcLocal({
57
+ doRouteRequest: (routedMessage: RouteMessageWrapper) => this.doRouteRequest(routedMessage),
58
+ addContact: (contact: PeerDescriptor) => this.config.addContact(contact),
59
+ isMostLikelyDuplicate: (requestId: string) => this.config.router.isMostLikelyDuplicate(requestId),
60
+ addToDuplicateDetector: (requestId: string) => this.config.router.addToDuplicateDetector(requestId)
61
+ })
62
+ this.config.rpcCommunicator.registerRpcMethod(
63
+ RouteMessageWrapper,
64
+ RouteMessageAck,
65
+ 'routeRequest',
66
+ async (routedMessage: RouteMessageWrapper) => {
67
+ if (this.stopped) {
68
+ return createRouteMessageAck(routedMessage, RouteMessageError.STOPPED)
69
+ } else {
70
+ return rpcLocal.routeRequest(routedMessage)
71
+ }
72
+ }
73
+ )
74
+ }
75
+
76
+ public async execute(
77
+ targetId: DhtAddress,
78
+ operation: RecursiveOperation,
79
+ excludedPeer?: DhtAddress,
80
+ waitForCompletion = true
81
+ ): Promise<RecursiveOperationResult> {
82
+ if (this.stopped) {
83
+ return { closestNodes: [] }
84
+ }
85
+ const session = new RecursiveOperationSession({
86
+ transport: this.config.sessionTransport,
87
+ targetId,
88
+ localPeerDescriptor: this.config.localPeerDescriptor,
89
+ // TODO use config option or named constant?
90
+ waitedRoutingPathCompletions: this.config.connections.size > 1 ? 2 : 1,
91
+ operation,
92
+ // TODO would it make sense to give excludedPeer as one of the fields RecursiveOperationSession?
93
+ doRouteRequest: (routedMessage: RouteMessageWrapper) => {
94
+ return this.doRouteRequest(routedMessage, excludedPeer)
95
+ }
96
+ })
97
+ if (this.config.connections.size === 0) {
98
+ const dataEntries = Array.from(this.config.localDataStore.values(targetId))
99
+ session.onResponseReceived(
100
+ getNodeIdFromPeerDescriptor(this.config.localPeerDescriptor),
101
+ [this.config.localPeerDescriptor],
102
+ [this.config.localPeerDescriptor],
103
+ dataEntries,
104
+ true
105
+ )
106
+ return session.getResults()
107
+ }
108
+ this.ongoingSessions.set(session.getId(), session)
109
+ if (waitForCompletion === true) {
110
+ try {
111
+ await runAndWaitForEvents3<RecursiveOperationSessionEvents>(
112
+ [() => session.start(this.config.serviceId)],
113
+ [[session, 'completed']],
114
+ // TODO use config option or named constant?
115
+ 15000
116
+ )
117
+ } catch (err) {
118
+ logger.debug(`start failed with error ${err}`)
119
+ }
120
+ } else {
121
+ session.start(this.config.serviceId)
122
+ // Wait for delete operation to be sent out by the router
123
+ // TODO: Add a feature to wait for the router to pass the message?
124
+ await wait(50)
125
+ }
126
+ if (operation === RecursiveOperation.FETCH_DATA) {
127
+ const dataEntries = Array.from(this.config.localDataStore.values(targetId))
128
+ if (dataEntries.length > 0) {
129
+ this.sendResponse([this.config.localPeerDescriptor], this.config.localPeerDescriptor, session.getId(), [], dataEntries, true)
130
+ }
131
+ } else if (operation === RecursiveOperation.DELETE_DATA) {
132
+ this.config.localDataStore.markAsDeleted(targetId, getNodeIdFromPeerDescriptor(this.config.localPeerDescriptor))
133
+ }
134
+ this.ongoingSessions.delete(session.getId())
135
+ session.stop()
136
+ return session.getResults()
137
+ }
138
+
139
+ private sendResponse(
140
+ routingPath: PeerDescriptor[],
141
+ targetPeerDescriptor: PeerDescriptor,
142
+ serviceId: ServiceID,
143
+ closestNodes: PeerDescriptor[],
144
+ dataEntries: DataEntry[],
145
+ noCloserNodesFound: boolean = false
146
+ ): void {
147
+ const isOwnNode = areEqualPeerDescriptors(this.config.localPeerDescriptor, targetPeerDescriptor)
148
+ if (isOwnNode && this.ongoingSessions.has(serviceId)) {
149
+ this.ongoingSessions.get(serviceId)!
150
+ .onResponseReceived(
151
+ getNodeIdFromPeerDescriptor(this.config.localPeerDescriptor),
152
+ routingPath,
153
+ closestNodes,
154
+ dataEntries,
155
+ noCloserNodesFound
156
+ )
157
+ } else {
158
+ // TODO use config option or named constant?
159
+ const remoteCommunicator = new ListeningRpcCommunicator(serviceId, this.config.sessionTransport, { rpcRequestTimeout: 15000 })
160
+ const rpcRemote = new RecursiveOperationSessionRpcRemote(
161
+ this.config.localPeerDescriptor,
162
+ targetPeerDescriptor,
163
+ remoteCommunicator,
164
+ RecursiveOperationSessionRpcClient,
165
+ // TODO use config option or named constant?
166
+ 10000
167
+ )
168
+ rpcRemote.sendResponse(routingPath, closestNodes, dataEntries, noCloserNodesFound)
169
+ remoteCommunicator.destroy()
170
+ }
171
+ }
172
+
173
+ private doRouteRequest(routedMessage: RouteMessageWrapper, excludedPeer?: DhtAddress): RouteMessageAck {
174
+ if (this.stopped) {
175
+ return createRouteMessageAck(routedMessage, RouteMessageError.STOPPED)
176
+ }
177
+ const targetId = getDhtAddressFromRaw(routedMessage.target)
178
+ const request = (routedMessage.message!.body as { recursiveOperationRequest: RecursiveOperationRequest }).recursiveOperationRequest
179
+ // TODO use config option or named constant?
180
+ const closestPeersToDestination = this.getClosestConnections(targetId, 5)
181
+ const dataEntries = (request.operation === RecursiveOperation.FETCH_DATA)
182
+ ? Array.from(this.config.localDataStore.values(targetId))
183
+ : []
184
+ if (request.operation === RecursiveOperation.DELETE_DATA) {
185
+ this.config.localDataStore.markAsDeleted(targetId, getNodeIdFromPeerDescriptor(routedMessage.sourcePeer!))
186
+ }
187
+ if (areEqualBinaries(this.config.localPeerDescriptor.nodeId, routedMessage.target)) {
188
+ // TODO this is also very similar case to what we do at line 255, could simplify the code paths?
189
+ this.sendResponse(
190
+ routedMessage.routingPath,
191
+ routedMessage.sourcePeer!,
192
+ request.sessionId,
193
+ closestPeersToDestination,
194
+ dataEntries,
195
+ true
196
+ )
197
+ return createRouteMessageAck(routedMessage)
198
+ } else {
199
+ const ack = this.config.router.doRouteMessage(routedMessage, RoutingMode.RECURSIVE, excludedPeer)
200
+ if ((ack.error === undefined) || (ack.error === RouteMessageError.NO_TARGETS)) {
201
+ const noCloserContactsFound = (ack.error === RouteMessageError.NO_TARGETS) ||
202
+ (
203
+ closestPeersToDestination.length > 0
204
+ && getPreviousPeer(routedMessage)
205
+ && !this.isPeerCloserToIdThanSelf(closestPeersToDestination[0], targetId)
206
+ )
207
+ this.sendResponse(
208
+ routedMessage.routingPath,
209
+ routedMessage.sourcePeer!,
210
+ request.sessionId,
211
+ closestPeersToDestination,
212
+ dataEntries,
213
+ noCloserContactsFound
214
+ )
215
+ }
216
+ return ack
217
+ }
218
+ }
219
+
220
+ private getClosestConnections(referenceId: DhtAddress, limit: number): PeerDescriptor[] {
221
+ const connectedPeers = Array.from(this.config.connections.values())
222
+ const closestPeers = new SortedContactList<DhtNodeRpcRemote>({
223
+ referenceId,
224
+ maxSize: limit,
225
+ allowToContainReferenceId: true,
226
+ emitEvents: false
227
+ })
228
+ closestPeers.addContacts(connectedPeers)
229
+ return closestPeers.getClosestContacts(limit).map((peer) => peer.getPeerDescriptor())
230
+ }
231
+
232
+ private isPeerCloserToIdThanSelf(peer: PeerDescriptor, nodeIdOrDataKey: DhtAddress): boolean {
233
+ const nodeIdOrDataKeyRaw = getRawFromDhtAddress(nodeIdOrDataKey)
234
+ const distance1 = getDistance(peer.nodeId, nodeIdOrDataKeyRaw)
235
+ const distance2 = getDistance(this.config.localPeerDescriptor.nodeId, nodeIdOrDataKeyRaw)
236
+ return distance1 < distance2
237
+ }
238
+
239
+ public stop(): void {
240
+ this.stopped = true
241
+ this.ongoingSessions.forEach((session, _id) => {
242
+ session.stop()
243
+ })
244
+ this.ongoingSessions.clear()
245
+ }
246
+ }