@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,61 @@
1
+ import { keyFromPeerDescriptor, ListeningRpcCommunicator } from '@streamr/dht'
2
+ import { NeighborUpdate } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
3
+ import { INeighborUpdateRpc } from '../../proto/packages/trackerless-network/protos/NetworkRpc.server'
4
+ import { PeerList } from '../PeerList'
5
+ import { INeighborFinder } from './NeighborFinder'
6
+ import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
7
+ import { toProtoRpcClient } from '@streamr/proto-rpc'
8
+ import { NetworkRpcClient } from '../../proto/packages/trackerless-network/protos/NetworkRpc.client'
9
+ import { RemoteRandomGraphNode } from '../RemoteRandomGraphNode'
10
+
11
+ interface NeighborUpdateManagerConfig {
12
+ ownStringId: string
13
+ randomGraphId: string
14
+ targetNeighbors: PeerList
15
+ nearbyContactPool: PeerList
16
+ neighborFinder: INeighborFinder
17
+ rpcCommunicator: ListeningRpcCommunicator
18
+ }
19
+
20
+ export class NeighborUpdateManagerServer implements INeighborUpdateRpc {
21
+
22
+ private readonly config: NeighborUpdateManagerConfig
23
+
24
+ constructor(config: NeighborUpdateManagerConfig) {
25
+ this.config = config
26
+ }
27
+
28
+ // INetworkRpc server method
29
+ async neighborUpdate(message: NeighborUpdate, _context: ServerCallContext): Promise<NeighborUpdate> {
30
+ if (this.config.targetNeighbors!.hasPeerWithStringId(message.senderId)) {
31
+ const newPeers = message.neighborDescriptors
32
+ .filter((peerDescriptor) => {
33
+ const stringId = keyFromPeerDescriptor(peerDescriptor)
34
+ return stringId !== this.config.ownStringId && !this.config.targetNeighbors.getStringIds().includes(stringId)
35
+ })
36
+ newPeers.forEach((peer) => this.config.nearbyContactPool.add(
37
+ new RemoteRandomGraphNode(
38
+ peer,
39
+ this.config.randomGraphId,
40
+ toProtoRpcClient(new NetworkRpcClient(this.config.rpcCommunicator!.getRpcClientTransport()))
41
+ ))
42
+ )
43
+ this.config.neighborFinder!.start()
44
+ const response: NeighborUpdate = {
45
+ senderId: this.config.ownStringId,
46
+ randomGraphId: this.config.randomGraphId,
47
+ neighborDescriptors: this.config.targetNeighbors.getPeers().map((neighbor) => neighbor.getPeerDescriptor()),
48
+ removeMe: false
49
+ }
50
+ return response
51
+ } else {
52
+ const response: NeighborUpdate = {
53
+ senderId: this.config.ownStringId,
54
+ randomGraphId: this.config.randomGraphId,
55
+ neighborDescriptors: this.config.targetNeighbors.getPeers().map((neighbor) => neighbor.getPeerDescriptor()),
56
+ removeMe: true
57
+ }
58
+ return response
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,64 @@
1
+ import { Remote } from '../Remote'
2
+ import { DhtRpcOptions, keyFromPeerDescriptor, PeerDescriptor, UUID } from '@streamr/dht'
3
+ import { InterleaveNotice, StreamHandshakeRequest } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
4
+ import { Logger } from '@streamr/utils'
5
+ import { IHandshakeRpcClient } from '../../proto/packages/trackerless-network/protos/NetworkRpc.client'
6
+
7
+ const logger = new Logger(module)
8
+
9
+ interface HandshakeResponse {
10
+ accepted: boolean
11
+ interleaveTarget?: PeerDescriptor
12
+ }
13
+
14
+ export class RemoteHandshaker extends Remote<IHandshakeRpcClient> {
15
+
16
+ async handshake(
17
+ ownPeerDescriptor: PeerDescriptor,
18
+ neighbors: string[],
19
+ concurrentHandshakeTargetId?: string,
20
+ interleavingFrom?: string
21
+ ): Promise<HandshakeResponse> {
22
+ const request: StreamHandshakeRequest = {
23
+ randomGraphId: this.graphId,
24
+ requestId: new UUID().toString(),
25
+ senderId: keyFromPeerDescriptor(ownPeerDescriptor),
26
+ neighbors,
27
+ concurrentHandshakeTargetId,
28
+ interleavingFrom,
29
+ senderDescriptor: ownPeerDescriptor
30
+ }
31
+ const options: DhtRpcOptions = {
32
+ sourceDescriptor: ownPeerDescriptor as PeerDescriptor,
33
+ targetDescriptor: this.remotePeerDescriptor as PeerDescriptor
34
+ }
35
+ try {
36
+ const response = await this.client.handshake(request, options)
37
+ return {
38
+ accepted: response.accepted,
39
+ interleaveTarget: response.interleaveTarget
40
+ }
41
+ } catch (err: any) {
42
+ logger.debug(`handshake to ${keyFromPeerDescriptor(this.getPeerDescriptor())} failed: ${err}`)
43
+ return {
44
+ accepted: false
45
+ }
46
+ }
47
+ }
48
+
49
+ interleaveNotice(ownPeerDescriptor: PeerDescriptor, originatorDescriptor: PeerDescriptor): void {
50
+ const options: DhtRpcOptions = {
51
+ sourceDescriptor: ownPeerDescriptor as PeerDescriptor,
52
+ targetDescriptor: this.remotePeerDescriptor as PeerDescriptor,
53
+ notification: true
54
+ }
55
+ const notification: InterleaveNotice = {
56
+ randomGraphId: this.graphId,
57
+ interleaveTarget: originatorDescriptor,
58
+ senderId: keyFromPeerDescriptor(ownPeerDescriptor)
59
+ }
60
+ this.client.interleaveNotice(notification, options).catch(() => {
61
+ logger.debug('Failed to send interleaveNotice')
62
+ })
63
+ }
64
+ }
@@ -0,0 +1,41 @@
1
+ import { DhtRpcOptions, keyFromPeerDescriptor, PeerDescriptor } from '@streamr/dht'
2
+ import { Logger } from '@streamr/utils'
3
+ import { NeighborUpdate } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
4
+ import { Remote } from '../Remote'
5
+ import { INeighborUpdateRpcClient } from '../../proto/packages/trackerless-network/protos/NetworkRpc.client'
6
+
7
+ const logger = new Logger(module)
8
+
9
+ interface UpdateNeighborsResponse {
10
+ peers: PeerDescriptor[]
11
+ removeMe: boolean
12
+ }
13
+
14
+ export class RemoteNeighborUpdateManager extends Remote<INeighborUpdateRpcClient> {
15
+
16
+ async updateNeighbors(ownPeerDescriptor: PeerDescriptor, neighbors: PeerDescriptor[]): Promise<UpdateNeighborsResponse> {
17
+ const options: DhtRpcOptions = {
18
+ sourceDescriptor: ownPeerDescriptor as PeerDescriptor,
19
+ targetDescriptor: this.remotePeerDescriptor as PeerDescriptor,
20
+ }
21
+ const request: NeighborUpdate = {
22
+ senderId: keyFromPeerDescriptor(ownPeerDescriptor),
23
+ randomGraphId: this.graphId,
24
+ neighborDescriptors: neighbors,
25
+ removeMe: false
26
+ }
27
+ try {
28
+ const response = await this.client.neighborUpdate(request, options)
29
+ return {
30
+ peers: response.neighborDescriptors!,
31
+ removeMe: response.removeMe
32
+ }
33
+ } catch (err: any) {
34
+ logger.debug(`updateNeighbors to ${keyFromPeerDescriptor(this.getPeerDescriptor())} failed: ${err}`)
35
+ return {
36
+ peers: [],
37
+ removeMe: true
38
+ }
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,108 @@
1
+ import { Node, create } from 'yallist'
2
+
3
+ interface Item<K, V> {
4
+ value: V
5
+ dropQueueNode: Node<K>
6
+ expiresAt: number
7
+ }
8
+
9
+ export interface FifoMapWithTtlOptions<K> {
10
+ ttlInMs: number
11
+ maxSize: number
12
+ onItemDropped?: (key: K) => void
13
+ timeProvider?: () => number
14
+ debugMode?: boolean
15
+ }
16
+
17
+ /**
18
+ * A "Map" implementation with a maximum size and TTL expiration on entries.
19
+ *
20
+ * When full, room is made for new entries by dropping existing by FIFO method.
21
+ *
22
+ * Entries have a TTL after which they are considered stale. Stale items are
23
+ * not returned when querying.
24
+ *
25
+ */
26
+ export class FifoMapWithTTL<K, V> {
27
+ // class invariant: the keys present in `items` and `dropQueue` are the same set.
28
+ private readonly items = new Map<K, Item<K, V>>()
29
+ private readonly dropQueue = create<K>() // queue is used to determine deletion order when full
30
+ private readonly ttlInMs: number
31
+ private readonly maxSize: number
32
+ private readonly onItemDropped: (key: K) => void
33
+ private readonly timeProvider: () => number
34
+
35
+ constructor({
36
+ ttlInMs,
37
+ maxSize,
38
+ onItemDropped = () => {},
39
+ timeProvider = Date.now
40
+ }: FifoMapWithTtlOptions<K>) {
41
+ if (ttlInMs < 0) {
42
+ throw new Error(`ttlInMs (${ttlInMs}) cannot be < 0`)
43
+ }
44
+ if (maxSize < 0) {
45
+ throw new Error(`maxSize (${maxSize}) cannot be < 0`)
46
+ }
47
+ this.ttlInMs = ttlInMs
48
+ this.maxSize = maxSize
49
+ this.onItemDropped = onItemDropped
50
+ this.timeProvider = timeProvider
51
+ }
52
+
53
+ set(key: K, value: V): void {
54
+ if (this.maxSize === 0) {
55
+ return
56
+ }
57
+ if (this.items.size > this.maxSize) {
58
+ throw new Error('assertion error: maximum size exceeded')
59
+ }
60
+
61
+ // delete an existing entry if exists
62
+ this.delete(key)
63
+
64
+ // make room for new entry
65
+ if (this.items.size === this.maxSize) {
66
+ const keyToDel = this.dropQueue.shift()
67
+ if (keyToDel === undefined) {
68
+ throw new Error('assertion error: queue empty but still have items')
69
+ }
70
+ this.items.delete(keyToDel)
71
+ this.onItemDropped(keyToDel)
72
+ }
73
+
74
+ // add entry
75
+ const dropQueueNode = new Node<K>(key)
76
+ this.dropQueue.pushNode(dropQueueNode)
77
+ this.items.set(key, {
78
+ value,
79
+ dropQueueNode,
80
+ expiresAt: this.timeProvider() + this.ttlInMs
81
+ })
82
+ }
83
+
84
+ delete(key: K): void {
85
+ const item = this.items.get(key)
86
+ if (item !== undefined) {
87
+ this.items.delete(key)
88
+ this.dropQueue.removeNode(item.dropQueueNode)
89
+ this.onItemDropped(key)
90
+ }
91
+ }
92
+
93
+ get(key: K): V | undefined {
94
+ const item = this.items.get(key)
95
+ if (item === undefined) {
96
+ return undefined
97
+ }
98
+ if (item.expiresAt <= this.timeProvider()) {
99
+ this.delete(key)
100
+ return undefined
101
+ }
102
+ return item.value
103
+ }
104
+
105
+ values(): Item<K, V>[] {
106
+ return [...this.items.values()]
107
+ }
108
+ }
@@ -0,0 +1,83 @@
1
+ import { StreamMessage } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
2
+ import { PropagationTask, PropagationTaskStore } from './PropagationTaskStore'
3
+
4
+ type SendToNeighborFn = (neighborId: string, msg: StreamMessage) => Promise<void>
5
+
6
+ interface ConstructorOptions {
7
+ sendToNeighbor: SendToNeighborFn
8
+ minPropagationTargets: number
9
+ ttl?: number
10
+ maxMessages?: number
11
+ }
12
+
13
+ const DEFAULT_MAX_MESSAGES = 150
14
+ const DEFAULT_TTL = 30 * 1000
15
+
16
+ /**
17
+ * Message propagation logic of a node. Given a message, this class will actively attempt to propagate it to
18
+ * `minPropagationTargets` neighbors until success or TTL expiration.
19
+ *
20
+ * Setting `minPropagationTargets = 0` effectively disables any propagation reattempts. A message will then
21
+ * only be propagated exactly once, to neighbors that are present at that moment, in a fire-and-forget manner.
22
+ */
23
+
24
+ export class Propagation {
25
+ private readonly sendToNeighbor: SendToNeighborFn
26
+ private readonly minPropagationTargets: number
27
+ private readonly activeTaskStore: PropagationTaskStore
28
+
29
+ constructor({
30
+ sendToNeighbor,
31
+ minPropagationTargets,
32
+ ttl = DEFAULT_TTL,
33
+ maxMessages = DEFAULT_MAX_MESSAGES
34
+ }: ConstructorOptions) {
35
+ this.sendToNeighbor = sendToNeighbor
36
+ this.minPropagationTargets = minPropagationTargets
37
+ this.activeTaskStore = new PropagationTaskStore(ttl, maxMessages)
38
+ }
39
+
40
+ /**
41
+ * Node should invoke this when it learns about a new message
42
+ */
43
+ feedUnseenMessage(message: StreamMessage, targets: string[], source: string | null): void {
44
+ const task = {
45
+ message,
46
+ source,
47
+ handledNeighbors: new Set<string>()
48
+ }
49
+ this.activeTaskStore.add(task)
50
+ for (const target of targets) {
51
+ this.sendAndAwaitThenMark(task, target)
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Node should invoke this when it learns about a new node stream assignment
57
+ */
58
+ onNeighborJoined(neighborId: string): void {
59
+ const tasksOfStream = this.activeTaskStore.get()
60
+ for (const task of tasksOfStream) {
61
+ this.sendAndAwaitThenMark(task, neighborId)
62
+ }
63
+ }
64
+
65
+ private sendAndAwaitThenMark({ message, source, handledNeighbors }: PropagationTask, neighborId: string): void {
66
+ if (!handledNeighbors.has(neighborId) && neighborId !== source) {
67
+ (async () => {
68
+ try {
69
+ await this.sendToNeighbor(neighborId, message)
70
+ } catch {
71
+ return
72
+ }
73
+ // Side-note: due to asynchronicity, the task being modified at this point could already be stale and
74
+ // deleted from `activeTaskStore`. However, as modifying it or re-deleting it is pretty much
75
+ // inconsequential at this point, leaving the logic as is.
76
+ handledNeighbors.add(neighborId)
77
+ if (handledNeighbors.size >= this.minPropagationTargets) {
78
+ this.activeTaskStore.delete(message.messageRef!)
79
+ }
80
+ })()
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,40 @@
1
+ import { MessageRef, StreamMessage } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
2
+ import { FifoMapWithTTL } from './FifoMapWithTTL'
3
+
4
+ export interface PropagationTask {
5
+ message: StreamMessage
6
+ source: string | null
7
+ handledNeighbors: Set<string>
8
+ }
9
+
10
+ /**
11
+ * Keeps track of propagation tasks for the needs of message propagation logic.
12
+ *
13
+ * Properties:
14
+ * - Allows fetching propagation tasks by StreamPartID
15
+ * - Upper bound on number of tasks stored, replacement policy if FIFO
16
+ * - Items have a TTL, after which they are considered stale and not returned when querying
17
+ **/
18
+ export class PropagationTaskStore {
19
+ private readonly tasks: FifoMapWithTTL<MessageRef, PropagationTask>
20
+
21
+ constructor(ttlInMs: number, maxTasks: number) {
22
+ this.tasks = new FifoMapWithTTL<MessageRef, PropagationTask>({
23
+ ttlInMs,
24
+ maxSize: maxTasks
25
+ })
26
+ }
27
+
28
+ get(): PropagationTask[] {
29
+ return this.tasks.values().map((task) => task.value)
30
+ }
31
+
32
+ add(task: PropagationTask): void {
33
+ const messageId = task.message.messageRef!
34
+ this.tasks.set(messageId, task)
35
+ }
36
+
37
+ delete(messageId: MessageRef): void {
38
+ this.tasks.delete(messageId) // causes `onKeyDropped` to be invoked
39
+ }
40
+ }
@@ -0,0 +1,16 @@
1
+ import { ContentMessage } from '../../../proto/packages/trackerless-network/protos/NetworkRpc'
2
+
3
+ // eslint-disable-next-line @typescript-eslint/no-extraneous-class
4
+ export class ContentMessageTranslator {
5
+
6
+ static toProtobuf(msg: string): ContentMessage {
7
+ const translatedMessage: ContentMessage = {
8
+ body: msg
9
+ }
10
+ return translatedMessage
11
+ }
12
+
13
+ static toClientProtocol(msg: ContentMessage): string {
14
+ return msg.body
15
+ }
16
+ }
@@ -0,0 +1,28 @@
1
+ import { GroupKeyRequest as OldGroupKeyRequest } from '@streamr/protocol'
2
+ import { GroupKeyRequest } from '../../../proto/packages/trackerless-network/protos/NetworkRpc'
3
+ import { EthereumAddress } from '@streamr/utils'
4
+
5
+ // eslint-disable-next-line @typescript-eslint/no-extraneous-class
6
+ export class GroupKeyRequestTranslator {
7
+
8
+ static toProtobuf(msg: OldGroupKeyRequest): GroupKeyRequest {
9
+ const translated: GroupKeyRequest = {
10
+ recipient: msg.recipient,
11
+ requestId: msg.requestId,
12
+ rsaPublicKey: msg.rsaPublicKey,
13
+ groupKeyIds: msg.groupKeyIds
14
+ }
15
+ return translated
16
+ }
17
+
18
+ static toClientProtocol(msg: GroupKeyRequest): OldGroupKeyRequest {
19
+ const translated = new OldGroupKeyRequest({
20
+ recipient: msg.recipient as EthereumAddress,
21
+ requestId: msg.requestId,
22
+ rsaPublicKey: msg.rsaPublicKey,
23
+ groupKeyIds: msg.groupKeyIds
24
+ })
25
+ return translated
26
+ }
27
+
28
+ }
@@ -0,0 +1,38 @@
1
+ import { GroupKeyResponse as OldGroupKeyResponse, EncryptedGroupKey as OldEncryptedGroupKey } from '@streamr/protocol'
2
+ import { EncryptedGroupKey, GroupKeyResponse } from '../../../proto/packages/trackerless-network/protos/NetworkRpc'
3
+ import { EthereumAddress } from '@streamr/utils'
4
+
5
+ // eslint-disable-next-line @typescript-eslint/no-extraneous-class
6
+ export class GroupKeyResponseTranslator {
7
+
8
+ static toProtobuf(msg: OldGroupKeyResponse): GroupKeyResponse {
9
+
10
+ const encryptedGroupKeys = msg.encryptedGroupKeys.map((groupKey) => {
11
+ const encryptedGroupKey: EncryptedGroupKey = {
12
+ encryptedGroupKeyHex: groupKey.encryptedGroupKeyHex,
13
+ groupKeyId: groupKey.groupKeyId,
14
+ serialized: groupKey.serialized ?? undefined
15
+ }
16
+ return encryptedGroupKey
17
+ })
18
+ const translated: GroupKeyResponse = {
19
+ recipient: msg.recipient as string,
20
+ requestId: msg.requestId,
21
+ encryptedGroupKeys
22
+ }
23
+ return translated
24
+ }
25
+
26
+ static toClientProtocol(msg: GroupKeyResponse): OldGroupKeyResponse {
27
+ const encryptedGroupKeys = msg.encryptedGroupKeys.map((groupKey: EncryptedGroupKey) => new OldEncryptedGroupKey(
28
+ groupKey.groupKeyId,
29
+ groupKey.encryptedGroupKeyHex,
30
+ groupKey.serialized
31
+ ))
32
+ return new OldGroupKeyResponse({
33
+ requestId: msg.requestId,
34
+ recipient: msg.recipient as EthereumAddress,
35
+ encryptedGroupKeys
36
+ })
37
+ }
38
+ }
@@ -0,0 +1,142 @@
1
+ import {
2
+ MessageID,
3
+ StreamMessage as OldStreamMessage,
4
+ StreamMessageType as OldStreamMessageType,
5
+ MessageRef as OldMessageRef,
6
+ EncryptedGroupKey as OldEncryptedGroupKey,
7
+ GroupKeyRequest as OldGroupKeyRequest,
8
+ GroupKeyResponse as OldGroupKeyResponse,
9
+ StreamID,
10
+ } from '@streamr/protocol'
11
+ import {
12
+ ContentMessage,
13
+ EncryptedGroupKey,
14
+ GroupKeyRequest,
15
+ GroupKeyResponse,
16
+ MessageRef,
17
+ StreamMessage,
18
+ StreamMessageType
19
+ } from '../../../proto/packages/trackerless-network/protos/NetworkRpc'
20
+ import { ContentMessageTranslator } from './ContentMessageTranslator'
21
+ import { EthereumAddress } from '@streamr/utils'
22
+ import { GroupKeyRequestTranslator } from './GroupKeyRequestTranslator'
23
+ import { GroupKeyResponseTranslator } from './GroupKeyResponseTranslator'
24
+
25
+ // eslint-disable-next-line @typescript-eslint/no-extraneous-class
26
+ export class StreamMessageTranslator {
27
+
28
+ static toProtobuf(msg: OldStreamMessage): StreamMessage {
29
+ let content: Uint8Array
30
+ let contentType: StreamMessageType
31
+ if (msg.messageType === OldStreamMessageType.MESSAGE) {
32
+ content = ContentMessage.toBinary(ContentMessageTranslator.toProtobuf(msg.serializedContent))
33
+ contentType = StreamMessageType.MESSAGE
34
+ } else if (msg.messageType === OldStreamMessageType.GROUP_KEY_REQUEST) {
35
+ content = GroupKeyRequest.toBinary(
36
+ GroupKeyRequestTranslator.toProtobuf(
37
+ OldGroupKeyRequest.deserialize(
38
+ msg.serializedContent,
39
+ OldStreamMessageType.GROUP_KEY_REQUEST) as OldGroupKeyRequest
40
+ )
41
+ )
42
+ contentType = StreamMessageType.GROUP_KEY_REQUEST
43
+ } else if (msg.messageType === OldStreamMessageType.GROUP_KEY_RESPONSE) {
44
+ content = GroupKeyResponse.toBinary(
45
+ GroupKeyResponseTranslator.toProtobuf(
46
+ OldGroupKeyResponse.deserialize(
47
+ msg.serializedContent,
48
+ OldStreamMessageType.GROUP_KEY_RESPONSE) as OldGroupKeyResponse
49
+ )
50
+ )
51
+ contentType = StreamMessageType.GROUP_KEY_RESPONSE
52
+ } else {
53
+ throw new Error('invalid message type')
54
+ }
55
+ const messageRef: MessageRef = {
56
+ timestamp: msg.getTimestamp(),
57
+ sequenceNumber: msg.getSequenceNumber(),
58
+ streamId: msg.getStreamId() as string,
59
+ streamPartition: msg.getStreamPartition(),
60
+ publisherId: msg.getPublisherId(),
61
+ messageChainId: msg.getMsgChainId()
62
+ }
63
+ let previousMessageRef: MessageRef | undefined = undefined
64
+ if (msg.getPreviousMessageRef()) {
65
+ previousMessageRef = {
66
+ timestamp: msg.getPreviousMessageRef()!.timestamp,
67
+ sequenceNumber: msg.getPreviousMessageRef()!.sequenceNumber,
68
+ streamId: msg.getStreamId() as string,
69
+ streamPartition: msg.getStreamPartition(),
70
+ publisherId: msg.getPublisherId(),
71
+ messageChainId: msg.getMsgChainId()
72
+ }
73
+ }
74
+ let newGroupKey: EncryptedGroupKey | undefined = undefined
75
+ if (msg.getNewGroupKey()) {
76
+ newGroupKey = {
77
+ encryptedGroupKeyHex: msg.getNewGroupKey()!.encryptedGroupKeyHex,
78
+ groupKeyId: msg.getNewGroupKey()!.groupKeyId,
79
+ serialized: msg.getNewGroupKey()!.serialized ?? undefined
80
+ }
81
+ }
82
+ const translated: StreamMessage = {
83
+ content: content,
84
+ encryptionType: msg.encryptionType,
85
+ messageRef: messageRef,
86
+ previousMessageRef,
87
+ messageType: contentType,
88
+ signature: msg.signature,
89
+ groupKeyId: msg.groupKeyId ?? undefined,
90
+ newGroupKey,
91
+ }
92
+ return translated
93
+ }
94
+
95
+ static toClientProtocol<T>(msg: StreamMessage): OldStreamMessage<T> {
96
+ let content: string
97
+ let contentType: OldStreamMessageType
98
+ if (msg.messageType === StreamMessageType.MESSAGE) {
99
+ contentType = OldStreamMessageType.MESSAGE
100
+ content = ContentMessageTranslator.toClientProtocol(ContentMessage.fromBinary(msg.content))
101
+ } else if (msg.messageType === StreamMessageType.GROUP_KEY_REQUEST) {
102
+ contentType = OldStreamMessageType.GROUP_KEY_REQUEST
103
+ content = GroupKeyRequestTranslator.toClientProtocol(GroupKeyRequest.fromBinary(msg.content)).serialize()
104
+ } else if (msg.messageType === StreamMessageType.GROUP_KEY_RESPONSE) {
105
+ contentType = OldStreamMessageType.GROUP_KEY_RESPONSE
106
+ content = GroupKeyResponseTranslator.toClientProtocol(GroupKeyResponse.fromBinary(msg.content)).serialize()
107
+ } else {
108
+ throw new Error('invalid message type')
109
+ }
110
+ const messageId = new MessageID(
111
+ msg.messageRef!.streamId as StreamID,
112
+ msg.messageRef!.streamPartition,
113
+ Number(msg.messageRef!.timestamp),
114
+ msg.messageRef!.sequenceNumber,
115
+ msg.messageRef!.publisherId as EthereumAddress,
116
+ msg.messageRef!.messageChainId
117
+ )
118
+ let prevMsgRef: OldMessageRef | undefined = undefined
119
+ if (msg.previousMessageRef) {
120
+ prevMsgRef = new OldMessageRef(Number(msg.previousMessageRef!.timestamp), msg.previousMessageRef!.sequenceNumber)
121
+ }
122
+ let newGroupKey: OldEncryptedGroupKey | undefined = undefined
123
+ if (msg.newGroupKey) {
124
+ newGroupKey = new OldEncryptedGroupKey(
125
+ msg.newGroupKey!.groupKeyId,
126
+ msg.newGroupKey!.encryptedGroupKeyHex,
127
+ msg.newGroupKey!.serialized
128
+ )
129
+ }
130
+ const translated = new OldStreamMessage<T>({
131
+ signature: msg.signature,
132
+ newGroupKey,
133
+ groupKeyId: msg.groupKeyId,
134
+ content,
135
+ messageType: contentType,
136
+ encryptionType: msg.encryptionType,
137
+ messageId,
138
+ prevMsgRef
139
+ })
140
+ return translated
141
+ }
142
+ }