@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,776 @@
1
+ import { DhtPeer } from './DhtPeer'
2
+ import KBucket from 'k-bucket'
3
+ import { EventEmitter } from 'eventemitter3'
4
+ import { SortedContactList } from './contact/SortedContactList'
5
+ import { RoutingRpcCommunicator } from '../transport/RoutingRpcCommunicator'
6
+ import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
7
+ import { PeerID, PeerIDKey } from '../helpers/PeerID'
8
+ import {
9
+ ClosestPeersRequest,
10
+ ClosestPeersResponse,
11
+ LeaveNotice,
12
+ ConnectivityResponse,
13
+ Message,
14
+ NodeType,
15
+ PeerDescriptor,
16
+ PingRequest,
17
+ PingResponse,
18
+ FindMode,
19
+ DataEntry,
20
+ } from '../proto/packages/dht/protos/DhtRpc'
21
+ import * as Err from '../helpers/errors'
22
+ import { DisconnectionType, ITransport, TransportEvents } from '../transport/ITransport'
23
+ import { ConnectionManager, ConnectionManagerConfig } from '../connection/ConnectionManager'
24
+ import { DhtRpcServiceClient, ExternalApiServiceClient } from '../proto/packages/dht/protos/DhtRpc.client'
25
+ import {
26
+ Logger,
27
+ MetricsContext
28
+ } from '@streamr/utils'
29
+ import { toProtoRpcClient } from '@streamr/proto-rpc'
30
+ import { RandomContactList } from './contact/RandomContactList'
31
+ import { Empty } from '../proto/google/protobuf/empty'
32
+ import { DhtCallContext } from '../rpc-protocol/DhtCallContext'
33
+ import { Any } from '../proto/google/protobuf/any'
34
+ import { isSamePeerDescriptor, keyFromPeerDescriptor, peerIdFromPeerDescriptor } from '../helpers/peerIdFromPeerDescriptor'
35
+ import { Router } from './routing/Router'
36
+ import { RecursiveFinder, RecursiveFindResult } from './find/RecursiveFinder'
37
+ import { DataStore } from './store/DataStore'
38
+ import { PeerDiscovery } from './discovery/PeerDiscovery'
39
+ import { LocalDataStore } from './store/LocalDataStore'
40
+ import { IceServer } from '../connection/WebRTC/WebRtcConnector'
41
+ import { ExternalApi } from './ExternalApi'
42
+ import { RemoteExternalApi } from './RemoteExternalApi'
43
+ import { UUID } from '../exports'
44
+
45
+ export interface DhtNodeEvents {
46
+ newContact: (peerDescriptor: PeerDescriptor, closestPeers: PeerDescriptor[]) => void
47
+ contactRemoved: (peerDescriptor: PeerDescriptor, closestPeers: PeerDescriptor[]) => void
48
+ joinCompleted: () => void
49
+ newKbucketContact: (peerDescriptor: PeerDescriptor, closestPeers: PeerDescriptor[]) => void
50
+ kbucketContactRemoved: (peerDescriptor: PeerDescriptor) => void
51
+ newOpenInternetContact: (peerDescriptor: PeerDescriptor, closestPeers: PeerDescriptor[]) => void
52
+ openInternetContactRemoved: (peerDescriptor: PeerDescriptor, closestPeers: PeerDescriptor[]) => void
53
+ newRandomContact: (peerDescriptor: PeerDescriptor, closestPeers: PeerDescriptor[]) => void
54
+ randomContactRemoved: (peerDescriptor: PeerDescriptor, closestPeers: PeerDescriptor[]) => void
55
+ }
56
+
57
+ export interface DhtNodeOptions {
58
+ serviceId?: string
59
+ joinParallelism?: number
60
+ maxNeighborListSize?: number
61
+ numberOfNodesPerKBucket?: number
62
+ joinNoProgressLimit?: number
63
+ dhtJoinTimeout?: number
64
+ metricsContext?: MetricsContext
65
+ storeHighestTtl?: number
66
+ storeMaxTtl?: number
67
+
68
+ transportLayer?: ITransport
69
+ peerDescriptor?: PeerDescriptor
70
+ entryPoints?: PeerDescriptor[]
71
+ webSocketHost?: string
72
+ webSocketPort?: number
73
+ peerIdString?: string
74
+
75
+ nodeName?: string
76
+ rpcRequestTimeout?: number
77
+ iceServers?: IceServer[]
78
+ webrtcAllowPrivateAddresses?: boolean
79
+ webrtcDatachannelBufferThresholdLow?: number
80
+ webrtcDatachannelBufferThresholdHigh?: number
81
+ webrtcNewConnectionTimeout?: number
82
+ maxConnections?: number
83
+ }
84
+
85
+ export class DhtNodeConfig {
86
+ serviceId = 'layer0'
87
+ joinParallelism = 3
88
+ maxNeighborListSize = 200
89
+ numberOfNodesPerKBucket = 8
90
+ joinNoProgressLimit = 4
91
+ dhtJoinTimeout = 60000
92
+ getClosestContactsLimit = 5
93
+ maxConnections = 80
94
+ storeHighestTtl = 60000
95
+ storeMaxTtl = 60000
96
+ storeNumberOfCopies = 5
97
+ metricsContext = new MetricsContext()
98
+ peerIdString = new UUID().toString()
99
+
100
+ transportLayer?: ITransport
101
+ peerDescriptor?: PeerDescriptor
102
+ entryPoints?: PeerDescriptor[]
103
+ webSocketHost?: string
104
+ webSocketPort?: number
105
+ nodeName?: string
106
+ rpcRequestTimeout?: number
107
+ iceServers?: IceServer[]
108
+ webrtcAllowPrivateAddresses?: boolean
109
+ webrtcDatachannelBufferThresholdLow?: number
110
+ webrtcDatachannelBufferThresholdHigh?: number
111
+ webrtcNewConnectionTimeout?: number
112
+
113
+ constructor(conf: Partial<DhtNodeOptions>) {
114
+ // assign given non-undefined config vars over defaults
115
+ let k: keyof typeof conf
116
+ for (k in conf) {
117
+ if (conf[k] === undefined) {
118
+ delete conf[k]
119
+ }
120
+ }
121
+ Object.assign(this, conf)
122
+ }
123
+ }
124
+
125
+ const logger = new Logger(module)
126
+
127
+ export type Events = TransportEvents & DhtNodeEvents
128
+
129
+ export const createPeerDescriptor = (msg?: ConnectivityResponse, peerIdString?: string, nodeName?: string): PeerDescriptor => {
130
+ let peerId: Uint8Array
131
+ if (msg) {
132
+ peerId = peerIdString ? PeerID.fromString(peerIdString).value : PeerID.fromIp(msg.ip).value
133
+ } else {
134
+ peerId = PeerID.fromString(peerIdString!).value
135
+ }
136
+ const ret: PeerDescriptor = { kademliaId: peerId, nodeName: nodeName, type: NodeType.NODEJS }
137
+ if (msg && msg.websocket) {
138
+ ret.websocket = { ip: msg.websocket!.ip, port: msg.websocket!.port }
139
+ ret.openInternet = true
140
+ }
141
+ return ret
142
+ }
143
+
144
+ export class DhtNode extends EventEmitter<Events> implements ITransport {
145
+ private readonly config: DhtNodeConfig
146
+
147
+ private bucket?: KBucket<DhtPeer>
148
+ private connections: Map<PeerIDKey, DhtPeer> = new Map()
149
+ private neighborList?: SortedContactList<DhtPeer>
150
+ private openInternetPeers?: SortedContactList<DhtPeer>
151
+ private randomPeers?: RandomContactList<DhtPeer>
152
+ private rpcCommunicator?: RoutingRpcCommunicator
153
+ private transportLayer?: ITransport
154
+ private ownPeerDescriptor?: PeerDescriptor
155
+ private ownPeerId?: PeerID
156
+ public router?: Router
157
+ public dataStore?: DataStore
158
+ private localDataStore = new LocalDataStore()
159
+ private recursiveFinder?: RecursiveFinder
160
+ private peerDiscovery?: PeerDiscovery
161
+ private externalApi?: ExternalApi
162
+
163
+ public connectionManager?: ConnectionManager
164
+ private started = false
165
+ private stopped = false
166
+ private entryPointDisconnectTimeout?: NodeJS.Timeout
167
+
168
+ public contactAddCounter = 0
169
+ public contactOnAddedCounter = 0
170
+
171
+ constructor(conf: Partial<DhtNodeConfig>) {
172
+ super()
173
+ this.config = new DhtNodeConfig(conf)
174
+ this.send = this.send.bind(this)
175
+ }
176
+
177
+ public async start(): Promise<void> {
178
+ if (this.started || this.stopped) {
179
+ return
180
+ }
181
+ logger.trace(`Starting new Streamr Network DHT Node with serviceId ${this.config.serviceId}`)
182
+ this.started = true
183
+
184
+ // If transportLayer is given, do not create a ConnectionManager
185
+ if (this.config.transportLayer) {
186
+ this.transportLayer = this.config.transportLayer
187
+ this.ownPeerDescriptor = this.transportLayer.getPeerDescriptor()
188
+ if (this.config.transportLayer instanceof ConnectionManager) {
189
+ this.connectionManager = this.config.transportLayer
190
+ }
191
+ } else {
192
+ const connectionManagerConfig: ConnectionManagerConfig = {
193
+ transportLayer: this,
194
+ entryPoints: this.config.entryPoints,
195
+ iceServers: this.config.iceServers,
196
+ metricsContext: this.config.metricsContext,
197
+ webrtcAllowPrivateAddresses: this.config.webrtcAllowPrivateAddresses,
198
+ webrtcDatachannelBufferThresholdLow: this.config.webrtcDatachannelBufferThresholdLow,
199
+ webrtcDatachannelBufferThresholdHigh: this.config.webrtcDatachannelBufferThresholdHigh,
200
+ webrtcNewConnectionTimeout: this.config.webrtcNewConnectionTimeout,
201
+ nodeName: this.getNodeName(),
202
+ maxConnections: this.config.maxConnections
203
+ }
204
+ // If own PeerDescriptor is given in config, create a ConnectionManager with ws server
205
+ if (this.config.peerDescriptor && this.config.peerDescriptor.websocket) {
206
+ connectionManagerConfig.webSocketHost = this.config.peerDescriptor.websocket.ip
207
+ connectionManagerConfig.webSocketPort = this.config.peerDescriptor.websocket.port
208
+ } else {
209
+ // If webSocketPort is given, create ws server using it, webSocketHost can be undefined
210
+ if (this.config.webSocketPort) {
211
+ connectionManagerConfig.webSocketHost = this.config.webSocketHost
212
+ connectionManagerConfig.webSocketPort = this.config.webSocketPort
213
+ }
214
+ }
215
+
216
+ const connectionManager = new ConnectionManager(connectionManagerConfig)
217
+ await connectionManager.start(this.generatePeerDescriptorCallBack)
218
+ this.connectionManager = connectionManager
219
+ this.transportLayer = connectionManager
220
+ }
221
+
222
+ this.rpcCommunicator = new RoutingRpcCommunicator(
223
+ this.config.serviceId,
224
+ this.transportLayer.send,
225
+ { rpcRequestTimeout: this.config.rpcRequestTimeout }
226
+ )
227
+
228
+ this.transportLayer.on('message', (message: Message) => this.handleMessage(message))
229
+
230
+ this.bindDefaultServerMethods()
231
+ this.ownPeerId = peerIdFromPeerDescriptor(this.ownPeerDescriptor!)
232
+ this.initKBuckets(this.ownPeerId!)
233
+ this.peerDiscovery = new PeerDiscovery({
234
+ rpcCommunicator: this.rpcCommunicator!,
235
+ ownPeerDescriptor: this.ownPeerDescriptor!,
236
+ ownPeerId: this.ownPeerId!,
237
+ bucket: this.bucket!,
238
+ connections: this.connections!,
239
+ neighborList: this.neighborList!,
240
+ randomPeers: this.randomPeers!,
241
+ openInternetPeers: this.openInternetPeers!,
242
+ joinNoProgressLimit: this.config.joinNoProgressLimit,
243
+ getClosestContactsLimit: this.config.getClosestContactsLimit,
244
+ joinTimeout: this.config.dhtJoinTimeout,
245
+ serviceId: this.config.serviceId,
246
+ parallelism: this.config.joinParallelism,
247
+ addContact: this.addNewContact.bind(this),
248
+ connectionManager: this.connectionManager
249
+ })
250
+ this.router = new Router({
251
+ rpcCommunicator: this.rpcCommunicator!,
252
+ connections: this.connections,
253
+ ownPeerDescriptor: this.ownPeerDescriptor!,
254
+ ownPeerId: this.ownPeerId!,
255
+ addContact: this.addNewContact.bind(this),
256
+ serviceId: this.config.serviceId,
257
+ connectionManager: this.connectionManager
258
+ })
259
+ this.recursiveFinder = new RecursiveFinder({
260
+ rpcCommunicator: this.rpcCommunicator!,
261
+ router: this.router!,
262
+ sessionTransport: this,
263
+ connections: this.connections,
264
+ ownPeerDescriptor: this.ownPeerDescriptor!,
265
+ serviceId: this.config.serviceId,
266
+ ownPeerId: this.ownPeerId!,
267
+ addContact: this.addNewContact.bind(this),
268
+ isPeerCloserToIdThanSelf: this.isPeerCloserToIdThanSelf.bind(this),
269
+ localDataStore: this.localDataStore
270
+ })
271
+ this.dataStore = new DataStore({
272
+ rpcCommunicator: this.rpcCommunicator!,
273
+ recursiveFinder: this.recursiveFinder,
274
+ ownPeerDescriptor: this.ownPeerDescriptor!,
275
+ serviceId: this.config.serviceId,
276
+ storeHighestTtl: this.config.storeHighestTtl,
277
+ storeMaxTtl: this.config.storeMaxTtl,
278
+ storeNumberOfCopies: this.config.storeNumberOfCopies,
279
+ localDataStore: this.localDataStore,
280
+ dhtNodeEmitter: this,
281
+ getNodesClosestToIdFromBucket: (id: Uint8Array, n?: number) => {
282
+ return this.bucket!.closest(id, n)
283
+ }
284
+ })
285
+ this.externalApi = new ExternalApi(this)
286
+ if (this.connectionManager! && this.config.entryPoints && this.config.entryPoints.length > 0
287
+ && !isSamePeerDescriptor(this.config.entryPoints[0], this.ownPeerDescriptor!)) {
288
+ this.connectToEntryPoint(this.config.entryPoints[0])
289
+ }
290
+ }
291
+
292
+ private initKBuckets = (selfId: PeerID) => {
293
+ this.bucket = new KBucket<DhtPeer>({
294
+ localNodeId: selfId.value,
295
+ numberOfNodesPerKBucket: this.config.numberOfNodesPerKBucket,
296
+ numberOfNodesToPing: this.config.numberOfNodesPerKBucket
297
+ })
298
+ this.bucket.on('ping', (oldContacts: DhtPeer[], newContact: DhtPeer) => this.onKBucketPing(oldContacts, newContact))
299
+ this.bucket.on('removed', (contact: DhtPeer) => this.onKBucketRemoved(contact))
300
+ this.bucket.on('added', (contact: DhtPeer) => this.onKBucketAdded(contact))
301
+ this.bucket.on('updated', (_oldContact: DhtPeer, _newContact: DhtPeer) => {
302
+ // TODO: Update contact info to the connection manager and reconnect
303
+ })
304
+ this.neighborList = new SortedContactList(selfId, this.config.maxNeighborListSize)
305
+ this.neighborList.on('contactRemoved', (peerDescriptor: PeerDescriptor, activeContacts: PeerDescriptor[]) => {
306
+ if (this.stopped) {
307
+ return
308
+ }
309
+ this.emit('contactRemoved', peerDescriptor, activeContacts)
310
+ this.randomPeers!.addContact(
311
+ new DhtPeer(
312
+ this.ownPeerDescriptor!,
313
+ peerDescriptor,
314
+ toProtoRpcClient(new DhtRpcServiceClient(this.rpcCommunicator!.getRpcClientTransport())),
315
+ this.config.serviceId
316
+ )
317
+ )
318
+ })
319
+ this.neighborList.on('newContact', (peerDescriptor: PeerDescriptor, activeContacts: PeerDescriptor[]) =>
320
+ this.emit('newContact', peerDescriptor, activeContacts)
321
+ )
322
+ this.openInternetPeers = new SortedContactList(selfId, this.config.maxNeighborListSize / 2)
323
+ this.openInternetPeers.on('contactRemoved', (peerDescriptor: PeerDescriptor, activeContacts: PeerDescriptor[]) =>
324
+ this.emit('openInternetContactRemoved', peerDescriptor, activeContacts)
325
+ )
326
+ this.openInternetPeers.on('newContact', (peerDescriptor: PeerDescriptor, activeContacts: PeerDescriptor[]) =>
327
+ this.emit('newOpenInternetContact', peerDescriptor, activeContacts)
328
+ )
329
+ this.transportLayer!.on('connected', (peerDescriptor: PeerDescriptor) => this.onTransportConnected(peerDescriptor))
330
+
331
+ this.transportLayer!.on('disconnected', (peerDescriptor: PeerDescriptor, disonnectionType: DisconnectionType) => {
332
+ this.onTransportDisconnected(peerDescriptor, disonnectionType)
333
+ })
334
+
335
+ this.transportLayer!.getAllConnectionPeerDescriptors().map((peer) => {
336
+ const peerId = peerIdFromPeerDescriptor(peer)
337
+ const dhtPeer = new DhtPeer(
338
+ this.ownPeerDescriptor!,
339
+ peer,
340
+ toProtoRpcClient(new DhtRpcServiceClient(this.rpcCommunicator!.getRpcClientTransport())),
341
+ this.config.serviceId
342
+ )
343
+ if (peerId.equals(this.ownPeerId!)) {
344
+ logger.error('own peerdescriptor added to connections in initKBucket')
345
+ }
346
+ this.connections.set(peerId.toKey(), dhtPeer)
347
+ })
348
+ this.randomPeers = new RandomContactList(selfId, this.config.maxNeighborListSize)
349
+ this.randomPeers.on('contactRemoved', (peerDescriptor: PeerDescriptor, activeContacts: PeerDescriptor[]) =>
350
+ this.emit('randomContactRemoved', peerDescriptor, activeContacts)
351
+ )
352
+ this.randomPeers.on('newContact', (peerDescriptor: PeerDescriptor, activeContacts: PeerDescriptor[]) =>
353
+ this.emit('newRandomContact', peerDescriptor, activeContacts)
354
+ )
355
+ }
356
+
357
+ private onTransportConnected(peerDescriptor: PeerDescriptor): void {
358
+
359
+ if (this.ownPeerId!.equals(PeerID.fromValue(peerDescriptor.kademliaId))) {
360
+ logger.error('onTransportConnected() to self')
361
+ }
362
+
363
+ const dhtPeer = new DhtPeer(
364
+ this.ownPeerDescriptor!,
365
+ peerDescriptor,
366
+ toProtoRpcClient(new DhtRpcServiceClient(this.rpcCommunicator!.getRpcClientTransport())),
367
+ this.config.serviceId
368
+ )
369
+ if (!this.connections.has(PeerID.fromValue(dhtPeer.id).toKey())) {
370
+ this.connections.set(PeerID.fromValue(dhtPeer.id).toKey(), dhtPeer)
371
+ logger.trace(' ' + this.config.nodeName + ' connectionschange add ' + this.connections.size)
372
+ } else {
373
+ logger.trace('new connection not set to connections, there is already a connection with the peer ID')
374
+ }
375
+ if (this.ownPeerDescriptor!.nodeName === 'entrypoint') {
376
+ logger.trace('connected: ' + this.ownPeerDescriptor!.nodeName + ', ' + peerDescriptor.nodeName + ' ' + this.connections.size)
377
+ }
378
+ this.emit('connected', peerDescriptor)
379
+ }
380
+
381
+ private onTransportDisconnected(peerDescriptor: PeerDescriptor, dicsonnectionType: DisconnectionType): void {
382
+ logger.trace('disconnected: ' + this.config.nodeName + ', ' + peerDescriptor.nodeName + ' ')
383
+ this.connections.delete(keyFromPeerDescriptor(peerDescriptor))
384
+ // only remove from bucket if we are on layer 0
385
+ if (this.connectionManager) {
386
+ this.bucket!.remove(peerDescriptor.kademliaId)
387
+
388
+ if (dicsonnectionType === 'OUTGOING_GRACEFUL_LEAVE' || dicsonnectionType === 'INCOMING_GRACEFUL_LEAVE') {
389
+ logger.trace( this.config.nodeName + ', ' + peerDescriptor.nodeName + ' ' + 'onTransportDisconnected with type ' + dicsonnectionType)
390
+ this.removeContact(peerDescriptor, true)
391
+ } else {
392
+ logger.trace( this.config.nodeName + ', ' + peerDescriptor.nodeName + ' ' + 'onTransportDisconnected with type ' + dicsonnectionType)
393
+ }
394
+ }
395
+
396
+ this.emit('disconnected', peerDescriptor, dicsonnectionType)
397
+ }
398
+
399
+ private bindDefaultServerMethods(): void {
400
+ if (!this.started || this.stopped) {
401
+ return
402
+ }
403
+ logger.trace(`Binding default DHT RPC methods`)
404
+ this.rpcCommunicator!.registerRpcMethod(ClosestPeersRequest, ClosestPeersResponse, 'getClosestPeers',
405
+ (req: ClosestPeersRequest, context) => this.getClosestPeers(req, context))
406
+ this.rpcCommunicator!.registerRpcMethod(PingRequest, PingResponse, 'ping',
407
+ (req: PingRequest, context) => this.ping(req, context))
408
+ this.rpcCommunicator!.registerRpcNotification(LeaveNotice, 'leaveNotice',
409
+ (req: LeaveNotice, context) => this.leaveNotice(req, context))
410
+ }
411
+
412
+ private isPeerCloserToIdThanSelf(peer1: PeerDescriptor, compareToId: PeerID): boolean {
413
+ const distance1 = this.bucket!.distance(peer1.kademliaId, compareToId.value)
414
+ const distance2 = this.bucket!.distance(this.ownPeerDescriptor!.kademliaId, compareToId.value)
415
+ return distance1 < distance2
416
+ }
417
+
418
+ public handleMessage(message: Message): void {
419
+ if (message.serviceId === this.config.serviceId) {
420
+ logger.trace('callig this.handleMessageFromPeer ' + this.config.nodeName + ', ' +
421
+ message.sourceDescriptor?.nodeName + ' ' + message.serviceId + ' ' + message.messageId)
422
+ this.rpcCommunicator?.handleMessageFromPeer(message)
423
+ } else {
424
+ logger.trace('emit "message" ' + this.config.nodeName + ', ' + message.sourceDescriptor?.nodeName +
425
+ ' ' + message.serviceId + ' ' + message.messageId)
426
+ this.emit('message', message)
427
+ }
428
+ }
429
+
430
+ private generatePeerDescriptorCallBack = (connectivityResponse: ConnectivityResponse) => {
431
+ if (this.config.peerDescriptor) {
432
+ this.ownPeerDescriptor = this.config.peerDescriptor
433
+ } else {
434
+ this.ownPeerDescriptor = createPeerDescriptor(connectivityResponse,
435
+ this.config.peerIdString,
436
+ this.config.nodeName)
437
+ }
438
+ return this.ownPeerDescriptor
439
+ }
440
+
441
+ private getClosestPeerDescriptors(kademliaId: Uint8Array, limit: number): PeerDescriptor[] {
442
+ const closestPeers = this.bucket!.closest(kademliaId, limit)
443
+ return closestPeers.map((dhtPeer: DhtPeer) => dhtPeer.getPeerDescriptor())
444
+ }
445
+
446
+ private onKBucketPing(oldContacts: DhtPeer[], newContact: DhtPeer): void {
447
+ if (this.stopped) {
448
+ return
449
+ }
450
+ const sortingList: SortedContactList<DhtPeer> = new SortedContactList(this.ownPeerId!, 100)
451
+ sortingList.addContacts(oldContacts)
452
+ const sortedContacts = sortingList.getAllContacts()
453
+ this.connectionManager?.weakUnlockConnection(sortedContacts[sortedContacts.length - 1].getPeerDescriptor())
454
+ this.bucket?.remove(sortedContacts[sortedContacts.length - 1].getPeerId().value)
455
+ this.bucket!.add(newContact)
456
+ }
457
+
458
+ private onKBucketRemoved(contact: DhtPeer): void {
459
+ if (this.stopped) {
460
+ return
461
+ }
462
+ this.connectionManager?.weakUnlockConnection(contact.getPeerDescriptor())
463
+ logger.trace(`Removed contact ${contact.getPeerId().value.toString()}`)
464
+ this.emit(
465
+ 'kbucketContactRemoved',
466
+ contact.getPeerDescriptor()
467
+ )
468
+ if (this.bucket!.count() === 0
469
+ && !this.peerDiscovery!.isJoinOngoing()
470
+ && this.config.entryPoints
471
+ && this.config.entryPoints.length > 0
472
+ ) {
473
+ setImmediate(async () => {
474
+ await Promise.all(this.config.entryPoints!.map((entryPoint) =>
475
+ this.peerDiscovery!.rejoinDht(entryPoint)
476
+ ))
477
+ })
478
+ }
479
+ }
480
+
481
+ private onKBucketAdded(contact: DhtPeer): void {
482
+ if (this.stopped) {
483
+ return
484
+ }
485
+ this.contactOnAddedCounter++
486
+ if (!this.stopped && !contact.getPeerId().equals(this.ownPeerId!)) {
487
+ // Important to lock here, before the ping result is known
488
+ this.connectionManager?.weakLockConnection(contact.getPeerDescriptor())
489
+ if (this.connections.has(contact.getPeerId().toKey())) {
490
+ logger.trace(`Added new contact ${contact.getPeerId().value.toString()}`)
491
+ this.emit(
492
+ 'newKbucketContact',
493
+ contact.getPeerDescriptor(),
494
+ this.neighborList!.getClosestContacts(this.config.getClosestContactsLimit).map((peer) => peer.getPeerDescriptor())
495
+ )
496
+ } else { // open connection by pinging
497
+ logger.trace('starting ping ' + this.config.nodeName + ', ' + contact.getPeerDescriptor().nodeName + ' ')
498
+ contact.ping().then((result) => {
499
+ if (result) {
500
+ logger.trace(`Added new contact ${contact.getPeerId().value.toString()}`)
501
+ this.emit(
502
+ 'newKbucketContact',
503
+ contact.getPeerDescriptor(),
504
+ this.neighborList!.getClosestContacts(this.config.getClosestContactsLimit).map((peer) => peer.getPeerDescriptor())
505
+ )
506
+ } else {
507
+ logger.trace('ping failed ' + this.config.nodeName + ', ' + contact.getPeerDescriptor().nodeName + ' ')
508
+ this.connectionManager?.weakUnlockConnection(contact.getPeerDescriptor())
509
+ this.removeContact(contact.getPeerDescriptor())
510
+ this.addClosestContactToBucket()
511
+ }
512
+ return
513
+ }).catch((_e) => {
514
+ this.connectionManager?.weakUnlockConnection(contact.getPeerDescriptor())
515
+ this.removeContact(contact.getPeerDescriptor())
516
+ this.addClosestContactToBucket()
517
+ })
518
+ }
519
+ }
520
+ }
521
+
522
+ private addClosestContactToBucket(): void {
523
+ if (!this.started || this.stopped) {
524
+ return
525
+ }
526
+ const closest = this.getClosestActiveContactNotInBucket()
527
+ if (closest) {
528
+ this.addNewContact(closest.getPeerDescriptor())
529
+ }
530
+ }
531
+
532
+ private getClosestActiveContactNotInBucket(): DhtPeer | undefined {
533
+ for (const contactId of this.neighborList!.getContactIds()) {
534
+ if (!this.bucket!.get(contactId.value) && this.neighborList!.isActive(contactId)) {
535
+ return this.neighborList!.getContact(contactId).contact
536
+ }
537
+ }
538
+ return undefined
539
+ }
540
+
541
+ public getNeighborList(): SortedContactList<DhtPeer> {
542
+ return this.neighborList!
543
+ }
544
+
545
+ public getNodeId(): PeerID {
546
+ return this.ownPeerId!
547
+ }
548
+
549
+ public getBucketSize(): number {
550
+ return this.bucket!.count()
551
+ }
552
+
553
+ private addNewContact(contact: PeerDescriptor, setActive = false): void {
554
+ if (!this.started || this.stopped) {
555
+ return
556
+ }
557
+ const peerId = peerIdFromPeerDescriptor(contact)
558
+ if (!peerId.equals(this.ownPeerId!)) {
559
+ logger.trace(`Adding new contact ${contact.kademliaId.toString()}`)
560
+ const dhtPeer = new DhtPeer(
561
+ this.ownPeerDescriptor!,
562
+ contact,
563
+ toProtoRpcClient(new DhtRpcServiceClient(this.rpcCommunicator!.getRpcClientTransport())),
564
+ this.config.serviceId
565
+ )
566
+ if (!this.bucket!.get(contact.kademliaId) && !this.neighborList!.getContact(peerIdFromPeerDescriptor(contact))) {
567
+ this.neighborList!.addContact(dhtPeer)
568
+ if (contact.openInternet) {
569
+ this.openInternetPeers!.addContact(dhtPeer)
570
+ }
571
+ if (setActive) {
572
+ this.neighborList!.setActive(peerId)
573
+ this.openInternetPeers!.setActive(peerId)
574
+ }
575
+ this.contactAddCounter++
576
+ this.bucket!.add(dhtPeer)
577
+ } else {
578
+ this.randomPeers!.addContact(dhtPeer)
579
+ }
580
+ }
581
+ }
582
+
583
+ private connectToEntryPoint(entryPoint: PeerDescriptor): void {
584
+ this.connectionManager!.lockConnection(entryPoint, 'temporary-layer0-connection')
585
+ this.entryPointDisconnectTimeout = setTimeout(() => {
586
+ this.connectionManager!.unlockConnection(entryPoint, 'temporary-layer0-connection')
587
+ }, 10 * 1000)
588
+ }
589
+
590
+ public removeContact(contact: PeerDescriptor, removeFromOpenInternetPeers = false): void {
591
+ if (!this.started || this.stopped) {
592
+ return
593
+ }
594
+ logger.trace(`Removing contact ${contact.kademliaId.toString()}`)
595
+ const peerId = peerIdFromPeerDescriptor(contact)
596
+ this.bucket!.remove(peerId.value)
597
+ this.neighborList!.removeContact(peerId)
598
+ this.randomPeers!.removeContact(peerId)
599
+ if (removeFromOpenInternetPeers) {
600
+ this.openInternetPeers!.removeContact(peerId)
601
+ }
602
+ }
603
+
604
+ public async send(msg: Message, _doNotConnect?: boolean): Promise<void> {
605
+ if (!this.started || this.stopped) {
606
+ return
607
+ }
608
+ const reachableThrough = this.peerDiscovery!.isJoinOngoing() ? this.config.entryPoints || [] : []
609
+ await this.router!.send(msg, reachableThrough)
610
+ }
611
+
612
+ public async joinDht(entryPointDescriptors: PeerDescriptor[], doRandomJoin?: boolean): Promise<void> {
613
+ if (!this.started) {
614
+ throw new Error('Cannot join DHT before calling start() on DhtNode')
615
+ }
616
+ await Promise.all(entryPointDescriptors.map((entryPoint) =>
617
+ this.peerDiscovery!.joinDht(entryPoint, doRandomJoin)
618
+ ))
619
+ }
620
+
621
+ public async startRecursiveFind(idToFind: Uint8Array, findMode?: FindMode, excludedPeer?: PeerDescriptor): Promise<RecursiveFindResult> {
622
+ return this.recursiveFinder!.startRecursiveFind(idToFind, findMode, excludedPeer)
623
+ }
624
+
625
+ public async storeDataToDht(key: Uint8Array, data: Any): Promise<PeerDescriptor[]> {
626
+ return this.dataStore!.storeDataToDht(key, data)
627
+ }
628
+
629
+ public async getDataFromDht(idToFind: Uint8Array): Promise<RecursiveFindResult> {
630
+ return this.recursiveFinder!.startRecursiveFind(idToFind, FindMode.DATA)
631
+ }
632
+
633
+ public async deleteDataFromDht(idToDelete: Uint8Array): Promise<void> {
634
+ if (!this.stopped) {
635
+ return this.dataStore!.deleteDataFromDht(idToDelete)
636
+ }
637
+ }
638
+
639
+ public async findDataViaPeer(idToFind: Uint8Array, peer: PeerDescriptor): Promise<DataEntry[]> {
640
+ const target = new RemoteExternalApi(
641
+ this.ownPeerDescriptor!,
642
+ peer,
643
+ toProtoRpcClient(new ExternalApiServiceClient(this.rpcCommunicator!.getRpcClientTransport())),
644
+ this.config.serviceId
645
+ )
646
+ return await target.findData(idToFind)
647
+ }
648
+
649
+ public getRpcCommunicator(): RoutingRpcCommunicator {
650
+ return this.rpcCommunicator!
651
+ }
652
+
653
+ public getTransport(): ITransport {
654
+ return this.transportLayer!
655
+ }
656
+
657
+ public getPeerDescriptor(): PeerDescriptor {
658
+ return this.ownPeerDescriptor!
659
+ }
660
+
661
+ public getAllConnectionPeerDescriptors(): PeerDescriptor[] {
662
+ return Array.from(this.connections.values()).map((peer) => peer.getPeerDescriptor())
663
+ }
664
+
665
+ public getK(): number {
666
+ return this.config.numberOfNodesPerKBucket
667
+ }
668
+
669
+ public getKBucketPeers(): PeerDescriptor[] {
670
+ return this.bucket!.toArray().map((dhtPeer: DhtPeer) => dhtPeer.getPeerDescriptor())
671
+ }
672
+
673
+ public getOpenInternetPeerDescriptors(): PeerDescriptor[] {
674
+ return this.openInternetPeers!.getAllContacts().map((contact) => contact.getPeerDescriptor())
675
+ }
676
+
677
+ public getNumberOfConnections(): number {
678
+ return this.connections.size
679
+ }
680
+
681
+ public getNumberOfLocalLockedConnections(): number {
682
+ return this.connectionManager!.getNumberOfLocalLockedConnections()
683
+ }
684
+
685
+ public getNumberOfRemoteLockedConnections(): number {
686
+ return this.connectionManager!.getNumberOfRemoteLockedConnections()
687
+ }
688
+
689
+ public getNumberOfWeakLockedConnections(): number {
690
+ return this.connectionManager!.getNumberOfWeakLockedConnections()
691
+ }
692
+
693
+ public getNodeName(): string {
694
+ if (this.config.nodeName) {
695
+ return this.config.nodeName
696
+ } else {
697
+ return 'unnamed node'
698
+ }
699
+ }
700
+
701
+ public isJoinOngoing(): boolean {
702
+ return this.peerDiscovery!.isJoinOngoing()
703
+ }
704
+
705
+ public hasJoined(): boolean {
706
+ return this.peerDiscovery!.isJoinCalled()
707
+ }
708
+
709
+ public getKnownEntryPoints(): PeerDescriptor[] {
710
+ return this.config.entryPoints || []
711
+ }
712
+
713
+ public async stop(): Promise<void> {
714
+ if (this.stopped) {
715
+ return
716
+ }
717
+ logger.trace('stop()')
718
+ if (!this.started) {
719
+ throw new Err.CouldNotStop('Cannot not stop() before start()')
720
+ }
721
+ this.stopped = true
722
+
723
+ if (this.entryPointDisconnectTimeout) {
724
+ clearTimeout(this.entryPointDisconnectTimeout)
725
+ }
726
+ this.bucket!.toArray().map((dhtPeer: DhtPeer) => this.bucket!.remove(dhtPeer.id))
727
+ this.bucket!.removeAllListeners()
728
+ this.localDataStore.clear()
729
+ this.neighborList!.stop()
730
+ this.randomPeers!.stop()
731
+ this.openInternetPeers!.stop()
732
+ this.rpcCommunicator!.stop()
733
+ this.router!.stop()
734
+ this.recursiveFinder!.stop()
735
+ this.peerDiscovery!.stop()
736
+ if (this.connectionManager) {
737
+ await this.connectionManager.stop()
738
+ }
739
+ this.transportLayer = undefined
740
+ this.connectionManager = undefined
741
+ this.externalApi = undefined
742
+ this.connections.clear()
743
+ this.removeAllListeners()
744
+ }
745
+
746
+ // IDHTRpcService implementation
747
+ private async getClosestPeers(request: ClosestPeersRequest, context: ServerCallContext): Promise<ClosestPeersResponse> {
748
+ this.addNewContact((context as DhtCallContext).incomingSourceDescriptor!)
749
+ const response = {
750
+ peers: this.getClosestPeerDescriptors(request.kademliaId, this.config.getClosestContactsLimit),
751
+ requestId: request.requestId
752
+ }
753
+ return response
754
+ }
755
+
756
+ // IDHTRpcService implementation
757
+ private async ping(request: PingRequest, context: ServerCallContext): Promise<PingResponse> {
758
+ logger.trace('received ping request: ' + this.config.nodeName + ', ' + (context as DhtCallContext).incomingSourceDescriptor?.nodeName)
759
+ setImmediate(() => {
760
+ this.addNewContact((context as DhtCallContext).incomingSourceDescriptor!)
761
+ })
762
+ const response: PingResponse = {
763
+ requestId: request.requestId
764
+ }
765
+ return response
766
+ }
767
+
768
+ // IDHTRpcService implementation
769
+ public async leaveNotice(request: LeaveNotice, context: ServerCallContext): Promise<Empty> {
770
+ // TODO check signature??
771
+ if (request.serviceId === this.config.serviceId) {
772
+ this.removeContact((context as DhtCallContext).incomingSourceDescriptor!)
773
+ }
774
+ return {}
775
+ }
776
+ }