@streamr/trackerless-network 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 (262) hide show
  1. package/.eslintignore +7 -0
  2. package/.eslintrc +3 -0
  3. package/README.md +6 -0
  4. package/bin/bootstrap-node.ts +73 -0
  5. package/bin/full-node-webrtc.ts +102 -0
  6. package/bin/full-node-websocket.ts +102 -0
  7. package/bin/network.ts +43 -0
  8. package/dist/package.json +53 -0
  9. package/dist/src/NameDirectory.d.ts +5 -0
  10. package/dist/src/NameDirectory.js +44 -0
  11. package/dist/src/NameDirectory.js.map +1 -0
  12. package/dist/src/NetworkNode.d.ts +35 -0
  13. package/dist/src/NetworkNode.js +130 -0
  14. package/dist/src/NetworkNode.js.map +1 -0
  15. package/dist/src/NetworkStack.d.ts +32 -0
  16. package/dist/src/NetworkStack.js +108 -0
  17. package/dist/src/NetworkStack.js.map +1 -0
  18. package/dist/src/exports.d.ts +6 -0
  19. package/dist/src/exports.js +12 -0
  20. package/dist/src/exports.js.map +1 -0
  21. package/dist/src/identifiers.d.ts +1 -0
  22. package/dist/src/identifiers.js +3 -0
  23. package/dist/src/identifiers.js.map +1 -0
  24. package/dist/src/logic/DuplicateMessageDetector.d.ts +55 -0
  25. package/dist/src/logic/DuplicateMessageDetector.js +155 -0
  26. package/dist/src/logic/DuplicateMessageDetector.js.map +1 -0
  27. package/dist/src/logic/ILayer0.d.ts +13 -0
  28. package/dist/src/logic/ILayer0.js +3 -0
  29. package/dist/src/logic/ILayer0.js.map +1 -0
  30. package/dist/src/logic/IStreamNode.d.ts +12 -0
  31. package/dist/src/logic/IStreamNode.js +3 -0
  32. package/dist/src/logic/IStreamNode.js.map +1 -0
  33. package/dist/src/logic/PeerList.d.ts +27 -0
  34. package/dist/src/logic/PeerList.js +84 -0
  35. package/dist/src/logic/PeerList.js.map +1 -0
  36. package/dist/src/logic/RandomGraphNode.d.ts +68 -0
  37. package/dist/src/logic/RandomGraphNode.js +201 -0
  38. package/dist/src/logic/RandomGraphNode.js.map +1 -0
  39. package/dist/src/logic/Remote.d.ts +9 -0
  40. package/dist/src/logic/Remote.js +15 -0
  41. package/dist/src/logic/Remote.js.map +1 -0
  42. package/dist/src/logic/RemoteRandomGraphNode.d.ts +8 -0
  43. package/dist/src/logic/RemoteRandomGraphNode.js +35 -0
  44. package/dist/src/logic/RemoteRandomGraphNode.js.map +1 -0
  45. package/dist/src/logic/StreamEntryPointDiscovery.d.ts +36 -0
  46. package/dist/src/logic/StreamEntryPointDiscovery.js +179 -0
  47. package/dist/src/logic/StreamEntryPointDiscovery.js.map +1 -0
  48. package/dist/src/logic/StreamNodeServer.d.ts +20 -0
  49. package/dist/src/logic/StreamNodeServer.js +26 -0
  50. package/dist/src/logic/StreamNodeServer.js.map +1 -0
  51. package/dist/src/logic/StreamrNode.d.ts +76 -0
  52. package/dist/src/logic/StreamrNode.js +303 -0
  53. package/dist/src/logic/StreamrNode.js.map +1 -0
  54. package/dist/src/logic/createRandomGraphNode.d.ts +5 -0
  55. package/dist/src/logic/createRandomGraphNode.js +110 -0
  56. package/dist/src/logic/createRandomGraphNode.js.map +1 -0
  57. package/dist/src/logic/inspect/InspectSession.d.ts +18 -0
  58. package/dist/src/logic/inspect/InspectSession.js +38 -0
  59. package/dist/src/logic/inspect/InspectSession.js.map +1 -0
  60. package/dist/src/logic/inspect/Inspector.d.ts +33 -0
  61. package/dist/src/logic/inspect/Inspector.js +63 -0
  62. package/dist/src/logic/inspect/Inspector.js.map +1 -0
  63. package/dist/src/logic/neighbor-discovery/Handshaker.d.ts +35 -0
  64. package/dist/src/logic/neighbor-discovery/Handshaker.js +121 -0
  65. package/dist/src/logic/neighbor-discovery/Handshaker.js.map +1 -0
  66. package/dist/src/logic/neighbor-discovery/HandshakerServer.d.ts +30 -0
  67. package/dist/src/logic/neighbor-discovery/HandshakerServer.js +78 -0
  68. package/dist/src/logic/neighbor-discovery/HandshakerServer.js.map +1 -0
  69. package/dist/src/logic/neighbor-discovery/NeighborFinder.d.ts +23 -0
  70. package/dist/src/logic/neighbor-discovery/NeighborFinder.js +44 -0
  71. package/dist/src/logic/neighbor-discovery/NeighborFinder.js.map +1 -0
  72. package/dist/src/logic/neighbor-discovery/NeighborUpdateManager.d.ts +30 -0
  73. package/dist/src/logic/neighbor-discovery/NeighborUpdateManager.js +42 -0
  74. package/dist/src/logic/neighbor-discovery/NeighborUpdateManager.js.map +1 -0
  75. package/dist/src/logic/neighbor-discovery/NeighborUpdateManagerServer.d.ts +20 -0
  76. package/dist/src/logic/neighbor-discovery/NeighborUpdateManagerServer.js +42 -0
  77. package/dist/src/logic/neighbor-discovery/NeighborUpdateManagerServer.js.map +1 -0
  78. package/dist/src/logic/neighbor-discovery/RemoteHandshaker.d.ts +12 -0
  79. package/dist/src/logic/neighbor-discovery/RemoteHandshaker.js +54 -0
  80. package/dist/src/logic/neighbor-discovery/RemoteHandshaker.js.map +1 -0
  81. package/dist/src/logic/neighbor-discovery/RemoteNeighborUpdateManager.d.ts +11 -0
  82. package/dist/src/logic/neighbor-discovery/RemoteNeighborUpdateManager.js +37 -0
  83. package/dist/src/logic/neighbor-discovery/RemoteNeighborUpdateManager.js.map +1 -0
  84. package/dist/src/logic/propagation/FifoMapWithTTL.d.ts +36 -0
  85. package/dist/src/logic/propagation/FifoMapWithTTL.js +81 -0
  86. package/dist/src/logic/propagation/FifoMapWithTTL.js.map +1 -0
  87. package/dist/src/logic/propagation/Propagation.d.ts +31 -0
  88. package/dist/src/logic/propagation/Propagation.js +64 -0
  89. package/dist/src/logic/propagation/Propagation.js.map +1 -0
  90. package/dist/src/logic/propagation/PropagationTaskStore.d.ts +21 -0
  91. package/dist/src/logic/propagation/PropagationTaskStore.js +32 -0
  92. package/dist/src/logic/propagation/PropagationTaskStore.js.map +1 -0
  93. package/dist/src/logic/protocol-integration/stream-message/ContentMessageTranslator.d.ts +5 -0
  94. package/dist/src/logic/protocol-integration/stream-message/ContentMessageTranslator.js +17 -0
  95. package/dist/src/logic/protocol-integration/stream-message/ContentMessageTranslator.js.map +1 -0
  96. package/dist/src/logic/protocol-integration/stream-message/GroupKeyRequestTranslator.d.ts +6 -0
  97. package/dist/src/logic/protocol-integration/stream-message/GroupKeyRequestTranslator.js +27 -0
  98. package/dist/src/logic/protocol-integration/stream-message/GroupKeyRequestTranslator.js.map +1 -0
  99. package/dist/src/logic/protocol-integration/stream-message/GroupKeyResponseTranslator.d.ts +6 -0
  100. package/dist/src/logic/protocol-integration/stream-message/GroupKeyResponseTranslator.js +33 -0
  101. package/dist/src/logic/protocol-integration/stream-message/GroupKeyResponseTranslator.js.map +1 -0
  102. package/dist/src/logic/protocol-integration/stream-message/StreamMessageTranslator.d.ts +6 -0
  103. package/dist/src/logic/protocol-integration/stream-message/StreamMessageTranslator.js +109 -0
  104. package/dist/src/logic/protocol-integration/stream-message/StreamMessageTranslator.js.map +1 -0
  105. package/dist/src/logic/proxy/ProxyStreamConnectionClient.d.ts +44 -0
  106. package/dist/src/logic/proxy/ProxyStreamConnectionClient.js +189 -0
  107. package/dist/src/logic/proxy/ProxyStreamConnectionClient.js.map +1 -0
  108. package/dist/src/logic/proxy/ProxyStreamConnectionServer.d.ts +34 -0
  109. package/dist/src/logic/proxy/ProxyStreamConnectionServer.js +64 -0
  110. package/dist/src/logic/proxy/ProxyStreamConnectionServer.js.map +1 -0
  111. package/dist/src/logic/proxy/RemoteProxyServer.d.ts +7 -0
  112. package/dist/src/logic/proxy/RemoteProxyServer.js +36 -0
  113. package/dist/src/logic/proxy/RemoteProxyServer.js.map +1 -0
  114. package/dist/src/logic/temporary-connection/RemoteTemporaryConnectionRpcServer.d.ts +6 -0
  115. package/dist/src/logic/temporary-connection/RemoteTemporaryConnectionRpcServer.js +28 -0
  116. package/dist/src/logic/temporary-connection/RemoteTemporaryConnectionRpcServer.js.map +1 -0
  117. package/dist/src/logic/temporary-connection/TemporaryConnectionRpcServer.d.ts +20 -0
  118. package/dist/src/logic/temporary-connection/TemporaryConnectionRpcServer.js +29 -0
  119. package/dist/src/logic/temporary-connection/TemporaryConnectionRpcServer.js.map +1 -0
  120. package/dist/src/logic/utils.d.ts +3 -0
  121. package/dist/src/logic/utils.js +16 -0
  122. package/dist/src/logic/utils.js.map +1 -0
  123. package/dist/src/proto/google/protobuf/any.d.ts +173 -0
  124. package/dist/src/proto/google/protobuf/any.js +155 -0
  125. package/dist/src/proto/google/protobuf/any.js.map +1 -0
  126. package/dist/src/proto/google/protobuf/empty.d.ts +32 -0
  127. package/dist/src/proto/google/protobuf/empty.js +34 -0
  128. package/dist/src/proto/google/protobuf/empty.js.map +1 -0
  129. package/dist/src/proto/google/protobuf/timestamp.d.ts +149 -0
  130. package/dist/src/proto/google/protobuf/timestamp.js +136 -0
  131. package/dist/src/proto/google/protobuf/timestamp.js.map +1 -0
  132. package/dist/src/proto/packages/dht/protos/DhtRpc.client.d.ts +320 -0
  133. package/dist/src/proto/packages/dht/protos/DhtRpc.client.js +245 -0
  134. package/dist/src/proto/packages/dht/protos/DhtRpc.client.js.map +1 -0
  135. package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +1089 -0
  136. package/dist/src/proto/packages/dht/protos/DhtRpc.js +710 -0
  137. package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -0
  138. package/dist/src/proto/packages/dht/protos/DhtRpc.server.d.ts +145 -0
  139. package/dist/src/proto/packages/dht/protos/DhtRpc.server.js +3 -0
  140. package/dist/src/proto/packages/dht/protos/DhtRpc.server.js.map +1 -0
  141. package/dist/src/proto/packages/proto-rpc/protos/ProtoRpc.d.ts +87 -0
  142. package/dist/src/proto/packages/proto-rpc/protos/ProtoRpc.js +66 -0
  143. package/dist/src/proto/packages/proto-rpc/protos/ProtoRpc.js.map +1 -0
  144. package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.client.d.ts +156 -0
  145. package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.client.js +122 -0
  146. package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.client.js.map +1 -0
  147. package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.d.ts +524 -0
  148. package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.js +350 -0
  149. package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.js.map +1 -0
  150. package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.server.d.ts +65 -0
  151. package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.server.js +3 -0
  152. package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.server.js.map +1 -0
  153. package/dist/test/benchmark/first-message.d.ts +1 -0
  154. package/dist/test/benchmark/first-message.js +137 -0
  155. package/dist/test/benchmark/first-message.js.map +1 -0
  156. package/dist/test/utils/utils.d.ts +12 -0
  157. package/dist/test/utils/utils.js +86 -0
  158. package/dist/test/utils/utils.js.map +1 -0
  159. package/jest.config.js +36 -0
  160. package/karma.config.js +20 -0
  161. package/log.txt +501 -0
  162. package/package.json +53 -0
  163. package/proto.sh +2 -0
  164. package/protos/NetworkRpc.proto +161 -0
  165. package/src/NameDirectory.ts +44 -0
  166. package/src/NetworkNode.ts +169 -0
  167. package/src/NetworkStack.ts +144 -0
  168. package/src/exports.ts +6 -0
  169. package/src/identifiers.ts +1 -0
  170. package/src/logic/DuplicateMessageDetector.ts +167 -0
  171. package/src/logic/ILayer0.ts +14 -0
  172. package/src/logic/IStreamNode.ts +17 -0
  173. package/src/logic/PeerList.ts +106 -0
  174. package/src/logic/RandomGraphNode.ts +310 -0
  175. package/src/logic/Remote.ts +19 -0
  176. package/src/logic/RemoteRandomGraphNode.ts +39 -0
  177. package/src/logic/StreamEntryPointDiscovery.ts +221 -0
  178. package/src/logic/StreamNodeServer.ts +44 -0
  179. package/src/logic/StreamrNode.ts +416 -0
  180. package/src/logic/createRandomGraphNode.ts +114 -0
  181. package/src/logic/inspect/InspectSession.ts +49 -0
  182. package/src/logic/inspect/Inspector.ts +89 -0
  183. package/src/logic/neighbor-discovery/Handshaker.ts +180 -0
  184. package/src/logic/neighbor-discovery/HandshakerServer.ts +99 -0
  185. package/src/logic/neighbor-discovery/NeighborFinder.ts +61 -0
  186. package/src/logic/neighbor-discovery/NeighborUpdateManager.ts +67 -0
  187. package/src/logic/neighbor-discovery/NeighborUpdateManagerServer.ts +61 -0
  188. package/src/logic/neighbor-discovery/RemoteHandshaker.ts +64 -0
  189. package/src/logic/neighbor-discovery/RemoteNeighborUpdateManager.ts +41 -0
  190. package/src/logic/propagation/FifoMapWithTTL.ts +108 -0
  191. package/src/logic/propagation/Propagation.ts +83 -0
  192. package/src/logic/propagation/PropagationTaskStore.ts +40 -0
  193. package/src/logic/protocol-integration/stream-message/ContentMessageTranslator.ts +16 -0
  194. package/src/logic/protocol-integration/stream-message/GroupKeyRequestTranslator.ts +28 -0
  195. package/src/logic/protocol-integration/stream-message/GroupKeyResponseTranslator.ts +38 -0
  196. package/src/logic/protocol-integration/stream-message/StreamMessageTranslator.ts +142 -0
  197. package/src/logic/proxy/ProxyStreamConnectionClient.ts +255 -0
  198. package/src/logic/proxy/ProxyStreamConnectionServer.ts +97 -0
  199. package/src/logic/proxy/RemoteProxyServer.ts +36 -0
  200. package/src/logic/temporary-connection/RemoteTemporaryConnectionRpcServer.ts +27 -0
  201. package/src/logic/temporary-connection/TemporaryConnectionRpcServer.ts +50 -0
  202. package/src/logic/utils.ts +17 -0
  203. package/src/proto/google/protobuf/any.ts +319 -0
  204. package/src/proto/google/protobuf/empty.ts +84 -0
  205. package/src/proto/google/protobuf/timestamp.ts +281 -0
  206. package/src/proto/packages/dht/protos/DhtRpc.client.ts +373 -0
  207. package/src/proto/packages/dht/protos/DhtRpc.server.ts +148 -0
  208. package/src/proto/packages/dht/protos/DhtRpc.ts +1399 -0
  209. package/src/proto/packages/proto-rpc/protos/ProtoRpc.ts +108 -0
  210. package/src/proto/packages/trackerless-network/protos/NetworkRpc.client.ts +176 -0
  211. package/src/proto/packages/trackerless-network/protos/NetworkRpc.server.ts +68 -0
  212. package/src/proto/packages/trackerless-network/protos/NetworkRpc.ts +667 -0
  213. package/test/benchmark/first-message.ts +155 -0
  214. package/test/end-to-end/inspect.test.ts +119 -0
  215. package/test/end-to-end/proxy-and-full-node.test.ts +140 -0
  216. package/test/end-to-end/proxy-connections.test.ts +228 -0
  217. package/test/end-to-end/proxy-key-exchange.test.ts +142 -0
  218. package/test/end-to-end/random-graph-with-real-connections.test.ts +154 -0
  219. package/test/end-to-end/webrtc-full-node-network.test.ts +97 -0
  220. package/test/end-to-end/websocket-full-node-network.test.ts +93 -0
  221. package/test/integration/Handshakes.test.ts +167 -0
  222. package/test/integration/Inspect.test.ts +102 -0
  223. package/test/integration/NetworkNode.test.ts +99 -0
  224. package/test/integration/NetworkRpc.test.ts +61 -0
  225. package/test/integration/NetworkStack.test.ts +74 -0
  226. package/test/integration/NetworkStackStoppedDuringStart.test.ts +45 -0
  227. package/test/integration/Propagation.test.ts +79 -0
  228. package/test/integration/RandomGraphNode-Layer1Node-Latencies.test.ts +141 -0
  229. package/test/integration/RandomGraphNode-Layer1Node.test.ts +226 -0
  230. package/test/integration/RemoteHandshaker.test.ts +78 -0
  231. package/test/integration/RemoteNeighborUpdateManager.test.ts +82 -0
  232. package/test/integration/RemoteRandomGraphNode.test.ts +102 -0
  233. package/test/integration/StreamrNode.test.ts +145 -0
  234. package/test/integration/stream-without-default-entrypoints.test.ts +132 -0
  235. package/test/unit/ContentMessageTranslator.test.ts +20 -0
  236. package/test/unit/DuplicateMessageDetector.test.ts +192 -0
  237. package/test/unit/FifoMapWithTtl.test.ts +229 -0
  238. package/test/unit/GroupKeyRequestTranslator.test.ts +36 -0
  239. package/test/unit/GroupKeyResponseTranslator.test.ts +39 -0
  240. package/test/unit/Handshaker.test.ts +63 -0
  241. package/test/unit/HandshakerServer.test.ts +123 -0
  242. package/test/unit/InspectSession.test.ts +78 -0
  243. package/test/unit/Inspector.test.ts +57 -0
  244. package/test/unit/NeighborFinder.test.ts +48 -0
  245. package/test/unit/NumberPair.test.ts +22 -0
  246. package/test/unit/PeerList.test.ts +150 -0
  247. package/test/unit/Propagation.test.ts +134 -0
  248. package/test/unit/RandomGraphNode.test.ts +73 -0
  249. package/test/unit/StreamEntrypointDiscovery.test.ts +152 -0
  250. package/test/unit/StreamMessageTranslator.test.ts +67 -0
  251. package/test/unit/StreamNodeServer.test.ts +63 -0
  252. package/test/unit/StreamrNode.test.ts +74 -0
  253. package/test/utils/mock/MockHandshaker.ts +15 -0
  254. package/test/utils/mock/MockLayer0.ts +71 -0
  255. package/test/utils/mock/MockLayer1.ts +6 -0
  256. package/test/utils/mock/MockNeighborFinder.ts +19 -0
  257. package/test/utils/mock/MockNeighborUpdateManager.ts +21 -0
  258. package/test/utils/mock/Transport.ts +25 -0
  259. package/test/utils/utils.ts +104 -0
  260. package/tsconfig.browser.json +12 -0
  261. package/tsconfig.jest.json +15 -0
  262. package/tsconfig.node.json +18 -0
@@ -0,0 +1,114 @@
1
+ import { ListeningRpcCommunicator, PeerIDKey, peerIdFromPeerDescriptor } from '@streamr/dht'
2
+ import { Handshaker } from './neighbor-discovery/Handshaker'
3
+ import { NeighborFinder } from './neighbor-discovery/NeighborFinder'
4
+ import { NeighborUpdateManager } from './neighbor-discovery/NeighborUpdateManager'
5
+ import { StrictRandomGraphNodeConfig, RandomGraphNode } from './RandomGraphNode'
6
+ import { PeerList } from './PeerList'
7
+ import { Propagation } from './propagation/Propagation'
8
+ import { StreamMessage } from '../proto/packages/trackerless-network/protos/NetworkRpc'
9
+ import { MarkOptional } from 'ts-essentials'
10
+ import { ProxyStreamConnectionServer } from './proxy/ProxyStreamConnectionServer'
11
+ import { Inspector } from './inspect/Inspector'
12
+ import { TemporaryConnectionRpcServer } from './temporary-connection/TemporaryConnectionRpcServer'
13
+
14
+ type RandomGraphNodeConfig = MarkOptional<StrictRandomGraphNodeConfig,
15
+ 'nearbyContactPool' | 'randomContactPool' | 'targetNeighbors' | 'propagation'
16
+ | 'handshaker' | 'neighborFinder' | 'neighborUpdateManager' | 'name' | 'numOfTargetNeighbors'
17
+ | 'maxNumberOfContacts' | 'minPropagationTargets' | 'rpcCommunicator' | 'peerViewSize' | 'acceptProxyConnections'
18
+ | 'neighborUpdateInterval' | 'inspector' | 'temporaryConnectionServer'>
19
+
20
+ const createConfigWithDefaults = (config: RandomGraphNodeConfig): StrictRandomGraphNodeConfig => {
21
+ const peerId = peerIdFromPeerDescriptor(config.ownPeerDescriptor)
22
+ const rpcCommunicator = config.rpcCommunicator ?? new ListeningRpcCommunicator(`layer2-${config.randomGraphId}`, config.P2PTransport)
23
+ const name = config.name ?? peerId.toKey()
24
+ const numOfTargetNeighbors = config.numOfTargetNeighbors ?? 4
25
+ const maxNumberOfContacts = config.maxNumberOfContacts ?? 20
26
+ const minPropagationTargets = config.minPropagationTargets ?? 2
27
+ const acceptProxyConnections = config.acceptProxyConnections ?? false
28
+ const neighborUpdateInterval = config.neighborUpdateInterval ?? 10000
29
+ const nearbyContactPool = config.nearbyContactPool ?? new PeerList(peerId, numOfTargetNeighbors + 1)
30
+ const randomContactPool = config.randomContactPool ?? new PeerList(peerId, maxNumberOfContacts)
31
+ const targetNeighbors = config.targetNeighbors ?? new PeerList(peerId, maxNumberOfContacts)
32
+
33
+ const temporaryConnectionServer = new TemporaryConnectionRpcServer({
34
+ randomGraphId: config.randomGraphId,
35
+ rpcCommunicator,
36
+ ownPeerId: peerId
37
+ })
38
+ const proxyConnectionServer = acceptProxyConnections ? new ProxyStreamConnectionServer({
39
+ ownPeerDescriptor: config.ownPeerDescriptor,
40
+ streamPartId: config.randomGraphId,
41
+ rpcCommunicator
42
+ }) : undefined
43
+ const propagation = config.propagation ?? new Propagation({
44
+ minPropagationTargets,
45
+ sendToNeighbor: async (neighborId: string, msg: StreamMessage): Promise<void> => {
46
+ const remote = targetNeighbors.getNeighborById(neighborId) ?? temporaryConnectionServer.getPeers().getNeighborById(neighborId)
47
+ const proxyConnection = proxyConnectionServer?.getConnection(neighborId as PeerIDKey)
48
+ if (remote) {
49
+ await remote.sendData(config.ownPeerDescriptor, msg)
50
+ } else if (proxyConnection) {
51
+ await proxyConnection.remote.sendData(config.ownPeerDescriptor, msg)
52
+ } else {
53
+ throw new Error('Propagation target not found')
54
+ }
55
+ }
56
+ })
57
+ const handshaker = config.handshaker ?? new Handshaker({
58
+ ownPeerDescriptor: config.ownPeerDescriptor,
59
+ randomGraphId: config.randomGraphId,
60
+ connectionLocker: config.connectionLocker,
61
+ rpcCommunicator,
62
+ nearbyContactPool,
63
+ randomContactPool,
64
+ targetNeighbors,
65
+ N: numOfTargetNeighbors
66
+ })
67
+ const neighborFinder = config.neighborFinder ?? new NeighborFinder({
68
+ targetNeighbors: targetNeighbors,
69
+ nearbyContactPool: nearbyContactPool,
70
+ doFindNeighbors: (excludedIds) => handshaker!.attemptHandshakesOnContacts(excludedIds),
71
+ N: numOfTargetNeighbors
72
+ })
73
+ const neighborUpdateManager = config.neighborUpdateManager ?? new NeighborUpdateManager({
74
+ targetNeighbors,
75
+ nearbyContactPool,
76
+ ownStringId: peerId.toKey(),
77
+ ownPeerDescriptor: config.ownPeerDescriptor,
78
+ neighborFinder,
79
+ randomGraphId: config.randomGraphId,
80
+ rpcCommunicator,
81
+ neighborUpdateInterval
82
+ })
83
+ const inspector = config.inspector ?? new Inspector({
84
+ ownPeerDescriptor: config.ownPeerDescriptor,
85
+ rpcCommunicator,
86
+ graphId: config.randomGraphId,
87
+ connectionLocker: config.connectionLocker
88
+ })
89
+ return {
90
+ ...config,
91
+ nearbyContactPool,
92
+ randomContactPool,
93
+ targetNeighbors,
94
+ rpcCommunicator,
95
+ handshaker,
96
+ neighborFinder,
97
+ neighborUpdateManager,
98
+ propagation,
99
+ numOfTargetNeighbors,
100
+ minPropagationTargets,
101
+ maxNumberOfContacts,
102
+ name,
103
+ peerViewSize: maxNumberOfContacts,
104
+ acceptProxyConnections,
105
+ proxyConnectionServer,
106
+ neighborUpdateInterval,
107
+ inspector,
108
+ temporaryConnectionServer
109
+ }
110
+ }
111
+
112
+ export const createRandomGraphNode = (config: RandomGraphNodeConfig): RandomGraphNode => {
113
+ return new RandomGraphNode(createConfigWithDefaults(config))
114
+ }
@@ -0,0 +1,49 @@
1
+ import { EventEmitter } from 'eventemitter3'
2
+ import { MessageRef } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
3
+ import { PeerIDKey } from '@streamr/dht'
4
+
5
+ export interface Events {
6
+ done: () => void
7
+ }
8
+
9
+ interface InspectSessionConfig {
10
+ inspectedPeer: PeerIDKey
11
+ }
12
+
13
+ const createMessageKey = (messageRef: MessageRef): string => {
14
+ return `${messageRef.publisherId}:${messageRef.messageChainId}:${messageRef.timestamp}:${messageRef.sequenceNumber}`
15
+ }
16
+ export class InspectSession extends EventEmitter<Events> {
17
+
18
+ // Boolean indicates if the message has been received by the inspected node
19
+ private readonly inspectionMessages: Map<string, boolean> = new Map()
20
+ private readonly inspectedPeer: PeerIDKey
21
+
22
+ constructor(config: InspectSessionConfig) {
23
+ super()
24
+ this.inspectedPeer = config.inspectedPeer
25
+ }
26
+
27
+ markMessage(senderId: PeerIDKey, messageRef: MessageRef): void {
28
+ const messageKey = createMessageKey(messageRef)
29
+ if (!this.inspectionMessages.has(messageKey)) {
30
+ this.inspectionMessages.set(messageKey, senderId === this.inspectedPeer)
31
+ } else if (this.inspectionMessages.has(messageKey)
32
+ && this.inspectionMessages.get(messageKey) === false
33
+ && senderId === this.inspectedPeer
34
+ ) {
35
+ this.emit('done')
36
+ } else if (this.inspectionMessages.has(messageKey)
37
+ && this.inspectionMessages.get(messageKey) === true) {
38
+ this.emit('done')
39
+ }
40
+ }
41
+
42
+ getInspectedMessageCount(): number {
43
+ return this.inspectionMessages.size
44
+ }
45
+
46
+ stop(): void {
47
+ this.emit('done')
48
+ }
49
+ }
@@ -0,0 +1,89 @@
1
+ import { PeerIDKey, PeerDescriptor, keyFromPeerDescriptor, ConnectionLocker } from '@streamr/dht'
2
+ import { MessageRef } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
3
+ import { InspectSession, Events as InspectSessionEvents } from './InspectSession'
4
+ import { TemporaryConnectionRpcClient } from '../../proto/packages/trackerless-network/protos/NetworkRpc.client'
5
+ import { ProtoRpcClient, RpcCommunicator, toProtoRpcClient } from '@streamr/proto-rpc'
6
+ import { Logger, waitForEvent3 } from '@streamr/utils'
7
+ import { RemoteTemporaryConnectionRpcServer } from '../temporary-connection/RemoteTemporaryConnectionRpcServer'
8
+
9
+ interface InspectorConfig {
10
+ ownPeerDescriptor: PeerDescriptor
11
+ graphId: string
12
+ rpcCommunicator: RpcCommunicator
13
+ connectionLocker: ConnectionLocker
14
+ inspectionTimeout?: number
15
+ openInspectConnection?: (peerDescriptor: PeerDescriptor, lockId: string) => Promise<void>
16
+ }
17
+
18
+ export interface IInspector {
19
+ inspect(peerDescriptor: PeerDescriptor): Promise<boolean>
20
+ markMessage(sender: PeerIDKey, messageId: MessageRef): void
21
+ isInspected(nodeId: PeerIDKey): boolean
22
+ stop(): void
23
+ }
24
+
25
+ const logger = new Logger(module)
26
+ const DEFAULT_TIMEOUT = 60 * 1000
27
+
28
+ export class Inspector implements IInspector {
29
+
30
+ private readonly sessions: Map<PeerIDKey, InspectSession> = new Map()
31
+ private readonly graphId: string
32
+ private readonly client: ProtoRpcClient<TemporaryConnectionRpcClient>
33
+ private readonly ownPeerDescriptor: PeerDescriptor
34
+ private readonly connectionLocker: ConnectionLocker
35
+ private readonly inspectionTimeout: number
36
+ private readonly openInspectConnection: (peerDescriptor: PeerDescriptor, lockId: string) => Promise<void>
37
+
38
+ constructor(config: InspectorConfig) {
39
+ this.graphId = config.graphId
40
+ this.ownPeerDescriptor = config.ownPeerDescriptor
41
+ this.client = toProtoRpcClient(new TemporaryConnectionRpcClient(config.rpcCommunicator.getRpcClientTransport()))
42
+ this.connectionLocker = config.connectionLocker
43
+ this.inspectionTimeout = config.inspectionTimeout ?? DEFAULT_TIMEOUT
44
+ this.openInspectConnection = config.openInspectConnection ?? this.defaultOpenInspectConnection
45
+ }
46
+
47
+ async defaultOpenInspectConnection(peerDescriptor: PeerDescriptor, lockId: string): Promise<void> {
48
+ const remoteRandomGraphNode = new RemoteTemporaryConnectionRpcServer(peerDescriptor, this.graphId, this.client)
49
+ await remoteRandomGraphNode.openConnection(this.ownPeerDescriptor)
50
+ this.connectionLocker.lockConnection(peerDescriptor, lockId)
51
+ }
52
+
53
+ async inspect(peerDescriptor: PeerDescriptor): Promise<boolean> {
54
+ const nodeId = keyFromPeerDescriptor(peerDescriptor)
55
+ const session = new InspectSession({
56
+ inspectedPeer: nodeId
57
+ })
58
+ const lockId = `inspector-${this.graphId}`
59
+ this.sessions.set(nodeId, session)
60
+ await this.openInspectConnection(peerDescriptor, lockId)
61
+ let success = false
62
+ try {
63
+ await waitForEvent3<InspectSessionEvents>(session, 'done', this.inspectionTimeout)
64
+ success = true
65
+ } catch (err) {
66
+ logger.trace('Inspect session timed out, removing')
67
+ } finally {
68
+ this.sessions.delete(nodeId)
69
+ this.connectionLocker.unlockConnection(peerDescriptor, lockId)
70
+ }
71
+ return success || session.getInspectedMessageCount() < 1
72
+ }
73
+
74
+ markMessage(sender: PeerIDKey, messageId: MessageRef): void {
75
+ this.sessions.forEach((session) => session.markMessage(sender, messageId))
76
+ }
77
+
78
+ isInspected(nodeId: PeerIDKey): boolean {
79
+ return this.sessions.has(nodeId)
80
+ }
81
+
82
+ stop(): void {
83
+ this.sessions.forEach((session) => {
84
+ session.stop()
85
+ })
86
+ this.sessions.clear()
87
+ }
88
+
89
+ }
@@ -0,0 +1,180 @@
1
+ import { ConnectionLocker, keyFromPeerDescriptor, PeerDescriptor } from '@streamr/dht'
2
+ import { PeerList } from '../PeerList'
3
+ import { RemoteRandomGraphNode } from '../RemoteRandomGraphNode'
4
+ import { ProtoRpcClient, RpcCommunicator, toProtoRpcClient } from '@streamr/proto-rpc'
5
+ import {
6
+ HandshakeRpcClient,
7
+ IHandshakeRpcClient, NetworkRpcClient
8
+ } from '../../proto/packages/trackerless-network/protos/NetworkRpc.client'
9
+ import {
10
+ InterleaveNotice,
11
+ StreamHandshakeRequest,
12
+ StreamHandshakeResponse
13
+ } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
14
+ import { Logger } from '@streamr/utils'
15
+ import { IHandshakeRpc } from '../../proto/packages/trackerless-network/protos/NetworkRpc.server'
16
+ import { RemoteHandshaker } from './RemoteHandshaker'
17
+ import { HandshakerServer } from './HandshakerServer'
18
+
19
+ interface HandshakerConfig {
20
+ ownPeerDescriptor: PeerDescriptor
21
+ randomGraphId: string
22
+ connectionLocker: ConnectionLocker
23
+ targetNeighbors: PeerList
24
+ nearbyContactPool: PeerList
25
+ randomContactPool: PeerList
26
+ rpcCommunicator: RpcCommunicator
27
+ N: number
28
+ }
29
+
30
+ const logger = new Logger(module)
31
+
32
+ const PARALLEL_HANDSHAKE_COUNT = 2
33
+
34
+ export interface IHandshaker {
35
+ attemptHandshakesOnContacts(excludedIds: string[]): Promise<string[]>
36
+ getOngoingHandshakes(): Set<string>
37
+ }
38
+
39
+ export class Handshaker implements IHandshaker {
40
+
41
+ private readonly ongoingHandshakes: Set<string> = new Set()
42
+ private config: HandshakerConfig
43
+ private readonly client: ProtoRpcClient<IHandshakeRpcClient>
44
+ private readonly server: IHandshakeRpc
45
+
46
+ constructor(config: HandshakerConfig) {
47
+ this.config = config
48
+ this.client = toProtoRpcClient(new HandshakeRpcClient(this.config.rpcCommunicator.getRpcClientTransport()))
49
+ this.server = new HandshakerServer({
50
+ randomGraphId: this.config.randomGraphId,
51
+ ownPeerDescriptor: this.config.ownPeerDescriptor,
52
+ targetNeighbors: this.config.targetNeighbors,
53
+ connectionLocker: this.config.connectionLocker,
54
+ ongoingHandshakes: this.ongoingHandshakes,
55
+ N: this.config.N,
56
+ handshakeWithInterleaving: (target: PeerDescriptor, senderId: string) => this.handshakeWithInterleaving(target, senderId),
57
+ createRemoteHandshaker: (target: PeerDescriptor) => this.createRemoteHandshaker(target),
58
+ createRemoteNode: (target: PeerDescriptor) => this.createRemoteNode(target)
59
+ })
60
+ this.config.rpcCommunicator.registerRpcNotification(InterleaveNotice, 'interleaveNotice',
61
+ (req: InterleaveNotice, context) => this.server.interleaveNotice(req, context))
62
+ this.config.rpcCommunicator.registerRpcMethod(StreamHandshakeRequest, StreamHandshakeResponse, 'handshake',
63
+ (req: StreamHandshakeRequest, context) => this.server.handshake(req, context))
64
+ }
65
+
66
+ public async attemptHandshakesOnContacts(excludedIds: string[]): Promise<string[]> {
67
+ if (this.config.targetNeighbors!.size() + this.ongoingHandshakes.size < this.config.N - 2) {
68
+ logger.trace(`Attempting parallel handshakes with ${PARALLEL_HANDSHAKE_COUNT} targets`)
69
+ return this.selectParallelTargetsAndHandshake(excludedIds)
70
+ } else if (this.config.targetNeighbors!.size() + this.ongoingHandshakes.size < this.config.N) {
71
+ logger.trace(`Attempting handshake with new target`)
72
+ return this.selectNewTargetAndHandshake(excludedIds)
73
+ }
74
+ return excludedIds
75
+ }
76
+
77
+ private async selectParallelTargetsAndHandshake(excludedIds: string[]): Promise<string[]> {
78
+ const exclude = excludedIds.concat(this.config.targetNeighbors.getStringIds())
79
+ const targetNeighbors = this.selectParallelTargets(exclude)
80
+ targetNeighbors.forEach((contact) => this.ongoingHandshakes.add(keyFromPeerDescriptor(contact.getPeerDescriptor())))
81
+ return this.doParallelHandshakes(targetNeighbors, exclude)
82
+ }
83
+
84
+ private selectParallelTargets(excludedIds: string[]): RemoteHandshaker[] {
85
+ const targetNeighbors = this.config.nearbyContactPool.getClosestAndFurthest(excludedIds)
86
+ while (targetNeighbors.length < PARALLEL_HANDSHAKE_COUNT && this.config.randomContactPool.size(excludedIds) > 0) {
87
+ const random = this.config.randomContactPool.getRandom(excludedIds)
88
+ if (random) {
89
+ targetNeighbors.push(random)
90
+ }
91
+ }
92
+ return targetNeighbors.map((neighbor) => this.createRemoteHandshaker(neighbor.getPeerDescriptor()))
93
+ }
94
+
95
+ private async doParallelHandshakes(targets: RemoteHandshaker[], excludedIds: string[]): Promise<string[]> {
96
+ const results = await Promise.allSettled(
97
+ Array.from(targets.values()).map(async (target: RemoteHandshaker, i) => {
98
+ const otherPeer = i === 0 ? targets[1] : targets[0]
99
+ const otherPeerStringId = otherPeer ? keyFromPeerDescriptor(otherPeer.getPeerDescriptor()) : undefined
100
+ return this.handshakeWithTarget(target, otherPeerStringId)
101
+ })
102
+ )
103
+ results.map((res, i) => {
104
+ if (res.status !== 'fulfilled' || !res.value) {
105
+ excludedIds.push(keyFromPeerDescriptor(targets[i].getPeerDescriptor()))
106
+ }
107
+ })
108
+ return excludedIds
109
+ }
110
+
111
+ private async selectNewTargetAndHandshake(excludedIds: string[]): Promise<string[]> {
112
+ const exclude = excludedIds.concat(this.config.targetNeighbors.getStringIds())
113
+ const targetNeighbor = this.config.nearbyContactPool.getClosest(exclude) ?? this.config.randomContactPool.getRandom(exclude)
114
+ if (targetNeighbor) {
115
+ const accepted = await this.handshakeWithTarget(this.createRemoteHandshaker(targetNeighbor.getPeerDescriptor()))
116
+ if (!accepted) {
117
+ excludedIds.push(keyFromPeerDescriptor(targetNeighbor.getPeerDescriptor()))
118
+ }
119
+ }
120
+ return excludedIds
121
+ }
122
+
123
+ private async handshakeWithTarget(targetNeighbor: RemoteHandshaker, concurrentStringId?: string): Promise<boolean> {
124
+ const targetStringId = keyFromPeerDescriptor(targetNeighbor.getPeerDescriptor())
125
+ this.ongoingHandshakes.add(targetStringId)
126
+ const result = await targetNeighbor.handshake(
127
+ this.config.ownPeerDescriptor,
128
+ this.config.targetNeighbors.getStringIds(),
129
+ concurrentStringId
130
+ )
131
+ if (result.accepted) {
132
+ this.config.targetNeighbors.add(this.createRemoteNode(targetNeighbor.getPeerDescriptor()))
133
+ this.config.connectionLocker.lockConnection(targetNeighbor.getPeerDescriptor(), this.config.randomGraphId)
134
+ }
135
+ if (result.interleaveTarget) {
136
+ await this.handshakeWithInterleaving(result.interleaveTarget, targetStringId)
137
+ }
138
+ this.ongoingHandshakes.delete(targetStringId)
139
+ return result.accepted
140
+ }
141
+
142
+ private async handshakeWithInterleaving(target: PeerDescriptor, interleavingFrom: string): Promise<boolean> {
143
+ const targetNeighbor = new RemoteHandshaker(
144
+ target,
145
+ this.config.randomGraphId,
146
+ this.client
147
+ )
148
+ const targetStringId = keyFromPeerDescriptor(targetNeighbor.getPeerDescriptor())
149
+ this.ongoingHandshakes.add(targetStringId)
150
+ const result = await targetNeighbor.handshake(
151
+ this.config.ownPeerDescriptor,
152
+ this.config.targetNeighbors.getStringIds(),
153
+ undefined,
154
+ interleavingFrom
155
+ )
156
+ if (result.accepted) {
157
+ this.config.targetNeighbors.add(this.createRemoteNode(targetNeighbor.getPeerDescriptor()))
158
+ this.config.connectionLocker.lockConnection(targetNeighbor.getPeerDescriptor(), this.config.randomGraphId)
159
+ }
160
+ this.ongoingHandshakes.delete(targetStringId)
161
+ return result.accepted
162
+ }
163
+
164
+ private createRemoteHandshaker(targetPeerDescriptor: PeerDescriptor): RemoteHandshaker {
165
+ return new RemoteHandshaker(targetPeerDescriptor, this.config.randomGraphId, this.client)
166
+ }
167
+
168
+ private createRemoteNode(targetPeerDescriptor: PeerDescriptor): RemoteRandomGraphNode {
169
+ return new RemoteRandomGraphNode(
170
+ targetPeerDescriptor,
171
+ this.config.randomGraphId,
172
+ toProtoRpcClient(new NetworkRpcClient(this.config.rpcCommunicator!.getRpcClientTransport()))
173
+ )
174
+ }
175
+
176
+ public getOngoingHandshakes(): Set<string> {
177
+ return this.ongoingHandshakes
178
+ }
179
+
180
+ }
@@ -0,0 +1,99 @@
1
+ import { Empty } from '../../proto/google/protobuf/empty'
2
+ import { InterleaveNotice, StreamHandshakeRequest, StreamHandshakeResponse } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
3
+ import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
4
+ import { PeerList } from '../PeerList'
5
+ import { ConnectionLocker, keyFromPeerDescriptor, PeerDescriptor } from '@streamr/dht'
6
+ import { IHandshakeRpc } from '../../proto/packages/trackerless-network/protos/NetworkRpc.server'
7
+ import { RemoteHandshaker } from './RemoteHandshaker'
8
+ import { RemoteRandomGraphNode } from '../RemoteRandomGraphNode'
9
+
10
+ interface HandshakerServerConfig {
11
+ randomGraphId: string
12
+ ownPeerDescriptor: PeerDescriptor
13
+ targetNeighbors: PeerList
14
+ connectionLocker: ConnectionLocker
15
+ ongoingHandshakes: Set<string>
16
+ N: number
17
+ createRemoteHandshaker: (target: PeerDescriptor) => RemoteHandshaker
18
+ createRemoteNode: (peerDescriptor: PeerDescriptor) => RemoteRandomGraphNode
19
+ handshakeWithInterleaving: (target: PeerDescriptor, senderId: string) => Promise<boolean>
20
+ }
21
+
22
+ export class HandshakerServer implements IHandshakeRpc {
23
+
24
+ private readonly config: HandshakerServerConfig
25
+
26
+ constructor(config: HandshakerServerConfig) {
27
+ this.config = config
28
+ }
29
+
30
+ async handshake(request: StreamHandshakeRequest, _context: ServerCallContext): Promise<StreamHandshakeResponse> {
31
+ return this.handleRequest(request)
32
+ }
33
+
34
+ private handleRequest(request: StreamHandshakeRequest): StreamHandshakeResponse {
35
+ if (this.config.targetNeighbors!.hasPeer(request.senderDescriptor!)
36
+ || this.config.ongoingHandshakes.has(keyFromPeerDescriptor(request.senderDescriptor!))
37
+ ) {
38
+ return this.acceptHandshake(request, request.senderDescriptor!)
39
+ } else if (this.config.targetNeighbors!.size() + this.config.ongoingHandshakes.size < this.config.N) {
40
+ return this.acceptHandshake(request, request.senderDescriptor!)
41
+ } else if (this.config.targetNeighbors!.size([request.interleavingFrom!]) >= 2) {
42
+ return this.acceptHandshakeWithInterleaving(request, request.senderDescriptor!)
43
+ } else {
44
+ return this.rejectHandshake(request)
45
+ }
46
+ }
47
+
48
+ private acceptHandshake(request: StreamHandshakeRequest, requester: PeerDescriptor) {
49
+ const res: StreamHandshakeResponse = {
50
+ requestId: request.requestId,
51
+ accepted: true
52
+ }
53
+ this.config.targetNeighbors.add(this.config.createRemoteNode(requester))
54
+ this.config.connectionLocker.lockConnection(request.senderDescriptor!, this.config.randomGraphId)
55
+ return res
56
+ }
57
+
58
+ // eslint-disable-next-line class-methods-use-this
59
+ private rejectHandshake(request: StreamHandshakeRequest) {
60
+ const res: StreamHandshakeResponse = {
61
+ requestId: request.requestId,
62
+ accepted: false
63
+ }
64
+ return res
65
+ }
66
+
67
+ private acceptHandshakeWithInterleaving(request: StreamHandshakeRequest, requester: PeerDescriptor): StreamHandshakeResponse {
68
+ const exclude = request.neighbors
69
+ exclude.push(request.senderId)
70
+ exclude.push(request.interleavingFrom!)
71
+ const furthest = this.config.targetNeighbors.getFurthest(exclude)
72
+ const furthestPeerDescriptor = furthest ? furthest.getPeerDescriptor() : undefined
73
+ if (furthest) {
74
+ const remote = this.config.createRemoteHandshaker(furthest.getPeerDescriptor())
75
+ remote.interleaveNotice(this.config.ownPeerDescriptor, request.senderDescriptor!)
76
+ this.config.targetNeighbors.remove(furthest.getPeerDescriptor())
77
+ this.config.connectionLocker.unlockConnection(furthestPeerDescriptor!, this.config.randomGraphId)
78
+ }
79
+ this.config.targetNeighbors.add(this.config.createRemoteNode(requester))
80
+ this.config.connectionLocker.lockConnection(request.senderDescriptor!, this.config.randomGraphId)
81
+ return {
82
+ requestId: request.requestId,
83
+ accepted: true,
84
+ interleaveTarget: furthestPeerDescriptor
85
+ }
86
+ }
87
+
88
+ async interleaveNotice(message: InterleaveNotice, _context: ServerCallContext): Promise<Empty> {
89
+ if (message.randomGraphId === this.config.randomGraphId) {
90
+ if (this.config.targetNeighbors.hasPeerWithStringId(message.senderId)) {
91
+ const senderDescriptor = this.config.targetNeighbors.getNeighborById(message.senderId)!.getPeerDescriptor()
92
+ this.config.connectionLocker.unlockConnection(senderDescriptor, this.config.randomGraphId)
93
+ this.config.targetNeighbors.remove(senderDescriptor)
94
+ }
95
+ this.config.handshakeWithInterleaving(message.interleaveTarget!, message.senderId).catch((_e) => {})
96
+ }
97
+ return Empty
98
+ }
99
+ }
@@ -0,0 +1,61 @@
1
+ import { setAbortableTimeout } from '@streamr/utils'
2
+ import { PeerList } from '../PeerList'
3
+
4
+ interface FindNeighborsSessionConfig {
5
+ targetNeighbors: PeerList
6
+ nearbyContactPool: PeerList
7
+ doFindNeighbors: (excludedNodes: string[]) => Promise<string[]>
8
+ N: number
9
+ }
10
+
11
+ const INITIAL_TIMEOUT = 100
12
+ const INTERVAL_TIMEOUT = 250
13
+
14
+ export interface INeighborFinder {
15
+ start(excluded?: string[]): void
16
+ stop(): void
17
+ isRunning(): boolean
18
+ }
19
+
20
+ export class NeighborFinder implements INeighborFinder {
21
+ private readonly abortController: AbortController
22
+ private readonly config: FindNeighborsSessionConfig
23
+ private running = false
24
+
25
+ constructor(config: FindNeighborsSessionConfig) {
26
+ this.config = config
27
+ this.abortController = new AbortController()
28
+ }
29
+
30
+ private async findNeighbors(excluded: string[]): Promise<void> {
31
+ if (!this.running) {
32
+ return
33
+ }
34
+ const newExcludes = await this.config.doFindNeighbors(excluded)
35
+ if (this.config.targetNeighbors!.size() < this.config.N && newExcludes.length < this.config.nearbyContactPool!.size()) {
36
+ setAbortableTimeout(() => this.findNeighbors(newExcludes), INTERVAL_TIMEOUT, this.abortController.signal)
37
+ } else {
38
+ this.running = false
39
+ }
40
+ }
41
+
42
+ isRunning(): boolean {
43
+ return this.running
44
+ }
45
+
46
+ start(excluded: string[] = []): void {
47
+ if (this.running) {
48
+ return
49
+ }
50
+ this.running = true
51
+ setAbortableTimeout(() => this.findNeighbors(excluded), INITIAL_TIMEOUT, this.abortController.signal)
52
+ }
53
+
54
+ stop(): void {
55
+ if (!this.running) {
56
+ return
57
+ }
58
+ this.running = false
59
+ this.abortController.abort()
60
+ }
61
+ }
@@ -0,0 +1,67 @@
1
+ import { NeighborUpdate } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
2
+ import { keyFromPeerDescriptor, ListeningRpcCommunicator, PeerDescriptor } from '@streamr/dht'
3
+ import { ProtoRpcClient, toProtoRpcClient } from '@streamr/proto-rpc'
4
+ import { NeighborUpdateRpcClient } from '../../proto/packages/trackerless-network/protos/NetworkRpc.client'
5
+ import { Logger, scheduleAtInterval } from '@streamr/utils'
6
+ import { PeerIDKey } from '@streamr/dht/dist/src/helpers/PeerID'
7
+ import { INeighborFinder } from './NeighborFinder'
8
+ import { PeerList } from '../PeerList'
9
+ import { RemoteNeighborUpdateManager } from './RemoteNeighborUpdateManager'
10
+ import { NeighborUpdateManagerServer } from './NeighborUpdateManagerServer'
11
+
12
+ interface NeighborUpdateManagerConfig {
13
+ ownStringId: PeerIDKey
14
+ ownPeerDescriptor: PeerDescriptor
15
+ targetNeighbors: PeerList
16
+ nearbyContactPool: PeerList
17
+ neighborFinder: INeighborFinder
18
+ randomGraphId: string
19
+ rpcCommunicator: ListeningRpcCommunicator
20
+ neighborUpdateInterval: number
21
+ }
22
+
23
+ const logger = new Logger(module)
24
+
25
+ export interface INeighborUpdateManager {
26
+ start(): Promise<void>
27
+ stop(): void
28
+ }
29
+
30
+ export class NeighborUpdateManager implements INeighborUpdateManager {
31
+ private readonly abortController: AbortController
32
+ private readonly config: NeighborUpdateManagerConfig
33
+ private readonly client: ProtoRpcClient<NeighborUpdateRpcClient>
34
+ private readonly server: NeighborUpdateManagerServer
35
+ constructor(config: NeighborUpdateManagerConfig) {
36
+ this.abortController = new AbortController()
37
+ this.client = toProtoRpcClient(new NeighborUpdateRpcClient(config.rpcCommunicator.getRpcClientTransport()))
38
+ this.server = new NeighborUpdateManagerServer(config)
39
+ this.config = config
40
+ this.config.rpcCommunicator.registerRpcMethod(NeighborUpdate, NeighborUpdate, 'neighborUpdate',
41
+ (req: NeighborUpdate, context) => this.server.neighborUpdate(req, context))
42
+ }
43
+
44
+ public async start(): Promise<void> {
45
+ await scheduleAtInterval(() => this.updateNeighborInfo(), this.config.neighborUpdateInterval, false, this.abortController.signal)
46
+ }
47
+
48
+ public stop(): void {
49
+ this.abortController.abort()
50
+ }
51
+
52
+ private async updateNeighborInfo(): Promise<void> {
53
+ logger.trace(`Updating neighbor info to peers`)
54
+ const neighborDescriptors = this.config.targetNeighbors!.getPeers().map((neighbor) => neighbor.getPeerDescriptor())
55
+ await Promise.allSettled(this.config.targetNeighbors!.getPeers().map(async (neighbor) => {
56
+ const res = await this.createRemote(neighbor.getPeerDescriptor()).updateNeighbors(this.config.ownPeerDescriptor, neighborDescriptors)
57
+ if (res.removeMe) {
58
+ this.config.targetNeighbors!.remove(neighbor.getPeerDescriptor())
59
+ this.config.neighborFinder!.start([keyFromPeerDescriptor(neighbor.getPeerDescriptor())])
60
+ }
61
+ }))
62
+ }
63
+
64
+ private createRemote(targetPeerDescriptor: PeerDescriptor): RemoteNeighborUpdateManager {
65
+ return new RemoteNeighborUpdateManager(targetPeerDescriptor, this.config.randomGraphId, this.client)
66
+ }
67
+ }