@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,255 @@
1
+ import {
2
+ ITransport,
3
+ ListeningRpcCommunicator,
4
+ PeerDescriptor,
5
+ PeerIDKey,
6
+ keyFromPeerDescriptor,
7
+ peerIdFromPeerDescriptor
8
+ } from '@streamr/dht'
9
+ import { LeaveStreamNotice, MessageRef, ProxyDirection, StreamMessage } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
10
+ import { IStreamNode } from '../IStreamNode'
11
+ import { EventEmitter } from 'eventemitter3'
12
+ import { ConnectionLocker } from '@streamr/dht/src/exports'
13
+ import { StreamNodeServer } from '../StreamNodeServer'
14
+ import { Logger, wait } from '@streamr/utils'
15
+ import { DuplicateMessageDetector } from '../DuplicateMessageDetector'
16
+ import { PeerList } from '../PeerList'
17
+ import { Propagation } from '../propagation/Propagation'
18
+ import { sampleSize } from 'lodash'
19
+ import { RemoteProxyServer } from './RemoteProxyServer'
20
+ import { NetworkRpcClient, ProxyConnectionRpcClient } from '../../proto/packages/trackerless-network/protos/NetworkRpc.client'
21
+ import { toProtoRpcClient } from '@streamr/proto-rpc'
22
+ import { RemoteRandomGraphNode } from '../RemoteRandomGraphNode'
23
+ import { markAndCheckDuplicate } from '../utils'
24
+
25
+ export const retry = async <T>(task: () => Promise<T>, description: string, abortSignal: AbortSignal, delay = 10000): Promise<T> => {
26
+ // eslint-disable-next-line no-constant-condition
27
+ while (true) {
28
+ try {
29
+ const result = await task()
30
+ return result
31
+ } catch (e: any) {
32
+ logger.warn(`Failed ${description} (retrying after delay)`, {
33
+ delayInMs: delay
34
+ })
35
+ }
36
+ await wait(delay, abortSignal)
37
+ }
38
+ }
39
+
40
+ interface ProxyStreamConnectionClientConfig {
41
+ P2PTransport: ITransport
42
+ ownPeerDescriptor: PeerDescriptor
43
+ streamPartId: string
44
+ connectionLocker: ConnectionLocker
45
+ userId: string
46
+ nodeName?: string
47
+ }
48
+
49
+ interface ProxyDefinition {
50
+ peers: Map<PeerIDKey, PeerDescriptor>
51
+ connectionCount: number
52
+ direction: ProxyDirection
53
+ userId: string
54
+ }
55
+
56
+ const logger = new Logger(module)
57
+
58
+ export class ProxyStreamConnectionClient extends EventEmitter implements IStreamNode {
59
+
60
+ private readonly rpcCommunicator: ListeningRpcCommunicator
61
+ private readonly server: StreamNodeServer
62
+ private readonly config: ProxyStreamConnectionClientConfig
63
+ private readonly duplicateDetectors: Map<string, DuplicateMessageDetector> = new Map()
64
+ private definition?: ProxyDefinition
65
+ private readonly connections: Map<PeerIDKey, ProxyDirection> = new Map()
66
+ private readonly propagation: Propagation
67
+ private readonly targetNeighbors: PeerList
68
+ private readonly abortController: AbortController
69
+
70
+ constructor(config: ProxyStreamConnectionClientConfig) {
71
+ super()
72
+ this.config = config
73
+ this.rpcCommunicator = new ListeningRpcCommunicator(`layer2-${config.streamPartId}`, config.P2PTransport)
74
+ this.targetNeighbors = new PeerList(peerIdFromPeerDescriptor(this.config.ownPeerDescriptor), 1000)
75
+ this.server = new StreamNodeServer({
76
+ ownPeerDescriptor: this.config.ownPeerDescriptor,
77
+ randomGraphId: this.config.streamPartId,
78
+ markAndCheckDuplicate: (msg: MessageRef, prev?: MessageRef) => markAndCheckDuplicate(this.duplicateDetectors, msg, prev),
79
+ broadcast: (message: StreamMessage, previousPeer?: string) => this.broadcast(message, previousPeer),
80
+ onLeaveNotice: (notice: LeaveStreamNotice) => {
81
+ const senderId = notice.senderId
82
+ const contact = this.targetNeighbors.getNeighborById(senderId)
83
+ if (contact) {
84
+ setImmediate(() => this.onPeerDisconnected(contact.getPeerDescriptor()))
85
+ }
86
+ },
87
+ rpcCommunicator: this.rpcCommunicator,
88
+ markForInspection: (_senderId: PeerIDKey, _messageRef: MessageRef) => {}
89
+ })
90
+ this.propagation = new Propagation({
91
+ minPropagationTargets: 2,
92
+ sendToNeighbor: async (neighborId: string, msg: StreamMessage): Promise<void> => {
93
+ const remote = this.targetNeighbors.getNeighborById(neighborId)
94
+ if (remote) {
95
+ await remote.sendData(config.ownPeerDescriptor, msg)
96
+ } else {
97
+ throw new Error('Propagation target not found')
98
+ }
99
+ }
100
+ })
101
+ this.abortController = new AbortController()
102
+ }
103
+
104
+ private registerDefaultServerMethods(): void {
105
+ this.rpcCommunicator.registerRpcNotification(StreamMessage, 'sendData',
106
+ (msg: StreamMessage, context) => this.server.sendData(msg, context))
107
+ this.rpcCommunicator.registerRpcNotification(LeaveStreamNotice, 'leaveStreamNotice',
108
+ (req: LeaveStreamNotice, context) => this.server.leaveStreamNotice(req, context))
109
+ }
110
+
111
+ async setProxies(
112
+ streamPartId: string,
113
+ peerDescriptors: PeerDescriptor[],
114
+ direction: ProxyDirection,
115
+ userId: string,
116
+ connectionCount?: number
117
+ ): Promise<void> {
118
+ logger.trace('Setting proxies', { streamPartId, peerDescriptors, direction, userId, connectionCount })
119
+ if (connectionCount !== undefined && connectionCount > peerDescriptors.length) {
120
+ throw Error('Cannot set connectionCount above the size of the configured array of nodes')
121
+ }
122
+ const peers = new Map()
123
+ peerDescriptors.forEach((peerDescriptor) => {
124
+ peers.set(keyFromPeerDescriptor(peerDescriptor), peerDescriptor)
125
+ })
126
+ this.definition = {
127
+ peers,
128
+ userId,
129
+ direction,
130
+ connectionCount: connectionCount ?? peerDescriptors.length
131
+ }
132
+ await this.updateConnections()
133
+ }
134
+
135
+ private async updateConnections(): Promise<void> {
136
+ await Promise.all(this.getInvalidConnections().map(async (id) => {
137
+ await this.closeConnection(id)
138
+ }))
139
+ const connectionCountDiff = this.definition!.connectionCount - this.connections.size
140
+ if (connectionCountDiff > 0) {
141
+ await this.openRandomConnections(connectionCountDiff)
142
+ } else if (connectionCountDiff < 0) {
143
+ await this.closeRandomConnections(-connectionCountDiff)
144
+ }
145
+ }
146
+
147
+ private getInvalidConnections(): PeerIDKey[] {
148
+ return Array.from(this.connections.keys()).filter((id) => {
149
+ return !this.definition!.peers.has(id)
150
+ || this.definition!.direction !== this.connections.get(id)
151
+ })
152
+ }
153
+
154
+ private async openRandomConnections(connectionCount: number): Promise<void> {
155
+ const proxiesToAttempt = sampleSize(Array.from(this.definition!.peers.keys()).filter((id) =>
156
+ !this.connections.has(id)
157
+ ), connectionCount)
158
+ await Promise.all(proxiesToAttempt.map((id) =>
159
+ this.attemptConnection(id, this.definition!.direction, this.definition!.userId)
160
+ ))
161
+ }
162
+
163
+ private async attemptConnection(peer: PeerIDKey, direction: ProxyDirection, userId: string): Promise<void> {
164
+ const peerDescriptor = this.definition!.peers.get(peer)!
165
+ const client = toProtoRpcClient(new ProxyConnectionRpcClient(this.rpcCommunicator.getRpcClientTransport()))
166
+ const proxyPeer = new RemoteProxyServer(peerDescriptor, this.config.streamPartId, client)
167
+ const accepted = await proxyPeer.requestConnection(this.config.ownPeerDescriptor, direction, userId)
168
+ if (accepted) {
169
+ this.config.connectionLocker.lockConnection(peerDescriptor, 'proxy-stream-connection-client')
170
+ this.connections.set(peer, direction)
171
+ const remote = new RemoteRandomGraphNode(
172
+ peerDescriptor,
173
+ this.config.streamPartId,
174
+ toProtoRpcClient(new NetworkRpcClient(this.rpcCommunicator.getRpcClientTransport()))
175
+ )
176
+ this.targetNeighbors.add(remote)
177
+ this.propagation.onNeighborJoined(peer)
178
+ logger.info('Open proxy connection', {
179
+ peer
180
+ })
181
+ }
182
+ }
183
+
184
+ private async closeRandomConnections(connectionCount: number): Promise<void> {
185
+ const proxiesToDisconnect = sampleSize(Array.from(this.connections.keys()), connectionCount)
186
+ await Promise.allSettled(proxiesToDisconnect.map((node) => this.closeConnection(node)))
187
+ }
188
+
189
+ private async closeConnection(peerKey: PeerIDKey): Promise<void> {
190
+ if (this.connections.has(peerKey)) {
191
+ logger.info('Close proxy connection', {
192
+ peerKey
193
+ })
194
+ const server = this.targetNeighbors.getNeighborById(peerKey)
195
+ server?.leaveStreamNotice(this.config.ownPeerDescriptor)
196
+ this.removeConnection(peerKey)
197
+ }
198
+ }
199
+
200
+ private removeConnection(peerKey: PeerIDKey): void {
201
+ this.connections.delete(peerKey)
202
+ this.targetNeighbors.removeById(peerKey)
203
+ }
204
+
205
+ broadcast(msg: StreamMessage, previousPeer?: string): void {
206
+ if (!previousPeer) {
207
+ markAndCheckDuplicate(this.duplicateDetectors, msg.messageRef!, msg.previousMessageRef)
208
+ }
209
+ this.emit('message', msg)
210
+ this.propagation.feedUnseenMessage(msg, this.targetNeighbors.getStringIds(), previousPeer ?? null)
211
+ }
212
+
213
+ getTargetNeighborStringIds(): string[] {
214
+ return this.targetNeighbors.getStringIds()
215
+ }
216
+
217
+ hasProxyConnection(peerKey: PeerIDKey, direction: ProxyDirection): boolean {
218
+ return this.connections.has(peerKey) && this.connections.get(peerKey) === direction
219
+ }
220
+
221
+ getDirection(): ProxyDirection {
222
+ return this.definition!.direction
223
+ }
224
+
225
+ async onPeerDisconnected(peerDescriptor: PeerDescriptor): Promise<void> {
226
+ const peerKey = keyFromPeerDescriptor(peerDescriptor)
227
+ if (this.connections.has(peerKey)) {
228
+ this.config.connectionLocker.unlockConnection(peerDescriptor, 'proxy-stream-connection-client')
229
+ this.removeConnection(peerKey)
230
+ await retry(() => this.updateConnections(), 'updating proxy connections', this.abortController.signal)
231
+ }
232
+ }
233
+
234
+ async start(): Promise<void> {
235
+ this.registerDefaultServerMethods()
236
+ this.config.P2PTransport.on('disconnected', (peerDescriptor: PeerDescriptor) =>
237
+ this.onPeerDisconnected(peerDescriptor)
238
+ )
239
+ }
240
+
241
+ stop(): void {
242
+ this.targetNeighbors.getPeers().map((remote) => {
243
+ this.config.connectionLocker.unlockConnection(remote.getPeerDescriptor(), 'proxy-stream-connection-client')
244
+ remote.leaveStreamNotice(this.config.ownPeerDescriptor)
245
+ })
246
+ this.targetNeighbors.stop()
247
+ this.rpcCommunicator.stop()
248
+ this.connections.clear()
249
+ this.abortController.abort()
250
+ this.config.P2PTransport.off('disconnected', (peerDescriptor: PeerDescriptor) =>
251
+ this.onPeerDisconnected(peerDescriptor)
252
+ )
253
+ }
254
+
255
+ }
@@ -0,0 +1,97 @@
1
+ import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
2
+ import { ProxyConnectionRequest, ProxyConnectionResponse, ProxyDirection } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
3
+ import { IProxyConnectionRpc } from '../../proto/packages/trackerless-network/protos/NetworkRpc.server'
4
+ import { RemoteRandomGraphNode } from '../RemoteRandomGraphNode'
5
+ import { ListeningRpcCommunicator, PeerDescriptor, PeerIDKey } from '@streamr/dht'
6
+ import { toProtoRpcClient } from '@streamr/proto-rpc'
7
+ import { NetworkRpcClient } from '../../proto/packages/trackerless-network/protos/NetworkRpc.client'
8
+ import { EventEmitter } from 'eventemitter3'
9
+ import { Logger } from '@streamr/utils'
10
+
11
+ const logger = new Logger(module)
12
+
13
+ interface ProxyConnection {
14
+ direction: ProxyDirection // Direction is from the client's point of view
15
+ userId: string
16
+ remote: RemoteRandomGraphNode
17
+ }
18
+
19
+ interface ProxyStreamConnectionServerConfig {
20
+ ownPeerDescriptor: PeerDescriptor
21
+ streamPartId: string
22
+ rpcCommunicator: ListeningRpcCommunicator
23
+ }
24
+
25
+ export interface Events {
26
+ newConnection: (peerKey: PeerIDKey) => void
27
+ }
28
+
29
+ export class ProxyStreamConnectionServer extends EventEmitter<Events> implements IProxyConnectionRpc {
30
+
31
+ private readonly config: ProxyStreamConnectionServerConfig
32
+ private readonly connections: Map<PeerIDKey, ProxyConnection> = new Map()
33
+
34
+ constructor(config: ProxyStreamConnectionServerConfig) {
35
+ super()
36
+ this.config = config
37
+ this.config.rpcCommunicator.registerRpcMethod(ProxyConnectionRequest, ProxyConnectionResponse, 'requestConnection',
38
+ (msg: ProxyConnectionRequest, context) => this.requestConnection(msg, context))
39
+ }
40
+
41
+ getConnection(peerKey: PeerIDKey): ProxyConnection | undefined {
42
+ return this.connections.get(peerKey)
43
+ }
44
+
45
+ hasConnection(peerKey: PeerIDKey): boolean {
46
+ return this.connections.has(peerKey)
47
+ }
48
+
49
+ removeConnection(peerKey: PeerIDKey): void {
50
+ this.connections.delete(peerKey)
51
+ }
52
+
53
+ stop(): void {
54
+ this.connections.forEach((connection) => connection.remote.leaveStreamNotice(this.config.ownPeerDescriptor))
55
+ this.connections.clear()
56
+ this.removeAllListeners()
57
+ }
58
+
59
+ getConnectedPeerIds(): PeerIDKey[] {
60
+ return Array.from(this.connections.keys())
61
+ }
62
+
63
+ getConnections(): ProxyConnection[] {
64
+ return Array.from(this.connections.values())
65
+ }
66
+
67
+ getSubscribers(): PeerIDKey[] {
68
+ return Array.from(this.connections.keys()).filter((key) => this.connections.get(key)!.direction === ProxyDirection.SUBSCRIBE)
69
+ }
70
+
71
+ public getPeerKeysForUserId(userId: string): PeerIDKey[] {
72
+ return Array.from(this.connections.keys()).filter((nodeId) => this.connections.get(nodeId)!.userId === userId)
73
+ }
74
+
75
+ // IProxyConnectionRpc server method
76
+ async requestConnection(request: ProxyConnectionRequest, _context: ServerCallContext): Promise<ProxyConnectionResponse> {
77
+ this.connections.set(request.senderId as PeerIDKey, {
78
+ direction: request.direction,
79
+ userId: request.userId,
80
+ remote: new RemoteRandomGraphNode(
81
+ request.senderDescriptor!,
82
+ this.config.streamPartId,
83
+ toProtoRpcClient(new NetworkRpcClient(this.config.rpcCommunicator.getRpcClientTransport()))
84
+ )
85
+ })
86
+ const response: ProxyConnectionResponse = {
87
+ accepted: true,
88
+ streamId: request.streamId,
89
+ streamPartition: request.streamPartition,
90
+ direction: request.direction,
91
+ senderId: request.senderId
92
+ }
93
+ logger.trace(`Accepted connection request from ${request.senderId} to ${request.streamId}/${request.streamPartition}`)
94
+ this.emit('newConnection', request.senderId as PeerIDKey)
95
+ return response
96
+ }
97
+ }
@@ -0,0 +1,36 @@
1
+ import { DhtRpcOptions, keyFromPeerDescriptor } from '@streamr/dht'
2
+ import { PeerDescriptor } from '../../proto/packages/dht/protos/DhtRpc'
3
+ import { IProxyConnectionRpcClient } from '../../proto/packages/trackerless-network/protos/NetworkRpc.client'
4
+ import { Remote } from '../Remote'
5
+ import { StreamPartIDUtils, toStreamID } from '@streamr/protocol'
6
+ import { ProxyDirection, ProxyConnectionRequest } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
7
+ import { Logger } from '@streamr/utils'
8
+
9
+ const logger = new Logger(module)
10
+
11
+ export class RemoteProxyServer extends Remote<IProxyConnectionRpcClient> {
12
+
13
+ async requestConnection(ownPeerDescriptor: PeerDescriptor, direction: ProxyDirection, userId: string): Promise<boolean> {
14
+ const streamPartId = StreamPartIDUtils.parse(this.graphId)
15
+ const options: DhtRpcOptions = {
16
+ sourceDescriptor: ownPeerDescriptor as PeerDescriptor,
17
+ targetDescriptor: this.remotePeerDescriptor as PeerDescriptor,
18
+ timeout: 5000
19
+ }
20
+ const request: ProxyConnectionRequest = {
21
+ senderId: keyFromPeerDescriptor(ownPeerDescriptor),
22
+ senderDescriptor: ownPeerDescriptor,
23
+ streamId: toStreamID(streamPartId),
24
+ streamPartition: StreamPartIDUtils.getStreamPartition(streamPartId),
25
+ direction,
26
+ userId
27
+ }
28
+ try {
29
+ const res = await this.client.requestConnection(request, options)
30
+ return res.accepted
31
+ } catch (err) {
32
+ logger.warn(`ProxyConnectionRequest failed with error: ${err}`)
33
+ return false
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,27 @@
1
+ import { DhtRpcOptions, PeerDescriptor, keyFromPeerDescriptor } from '@streamr/dht'
2
+ import { ITemporaryConnectionRpcClient } from '../../proto/packages/trackerless-network/protos/NetworkRpc.client'
3
+ import { Remote } from '../Remote'
4
+ import { TemporaryConnectionRequest } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
5
+ import { Logger } from '@streamr/utils'
6
+
7
+ const logger = new Logger(module)
8
+
9
+ export class RemoteTemporaryConnectionRpcServer extends Remote<ITemporaryConnectionRpcClient> {
10
+
11
+ async openConnection(ownPeerDescriptor: PeerDescriptor): Promise<boolean> {
12
+ const options: DhtRpcOptions = {
13
+ sourceDescriptor: ownPeerDescriptor,
14
+ targetDescriptor: this.remotePeerDescriptor,
15
+ }
16
+ const request: TemporaryConnectionRequest = {
17
+ senderId: keyFromPeerDescriptor(ownPeerDescriptor)
18
+ }
19
+ try {
20
+ const response = await this.client.openConnection(request, options)
21
+ return response.accepted
22
+ } catch (err: any) {
23
+ logger.debug(`temporaryConnection to ${keyFromPeerDescriptor(this.getPeerDescriptor())} failed: ${err}`)
24
+ return false
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,50 @@
1
+ import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
2
+ import { TemporaryConnectionRequest, TemporaryConnectionResponse } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
3
+ import { ITemporaryConnectionRpc } from '../../proto/packages/trackerless-network/protos/NetworkRpc.server'
4
+ import { DhtCallContext, ListeningRpcCommunicator, PeerID } from '@streamr/dht'
5
+ import { NetworkRpcClient } from '../../proto/packages/trackerless-network/protos/NetworkRpc.client'
6
+ import { PeerList } from '../PeerList'
7
+ import { toProtoRpcClient } from '@streamr/proto-rpc'
8
+ import { RemoteRandomGraphNode } from '../RemoteRandomGraphNode'
9
+ import { PeerDescriptor } from '../../proto/packages/dht/protos/DhtRpc'
10
+
11
+ interface TemporaryConnectionRpcServerConfig {
12
+ randomGraphId: string
13
+ rpcCommunicator: ListeningRpcCommunicator
14
+ ownPeerId: PeerID
15
+ }
16
+
17
+ export class TemporaryConnectionRpcServer implements ITemporaryConnectionRpc {
18
+
19
+ private readonly config: TemporaryConnectionRpcServerConfig
20
+ private readonly temporaryPeers: PeerList
21
+
22
+ constructor(config: TemporaryConnectionRpcServerConfig) {
23
+ this.config = config
24
+ this.temporaryPeers = new PeerList(config.ownPeerId, 10)
25
+ }
26
+
27
+ getPeers(): PeerList {
28
+ return this.temporaryPeers
29
+ }
30
+
31
+ removePeer(peer: PeerDescriptor): void {
32
+ this.temporaryPeers.remove(peer)
33
+ }
34
+
35
+ async openConnection(
36
+ _request: TemporaryConnectionRequest,
37
+ context: ServerCallContext
38
+ ): Promise<TemporaryConnectionResponse> {
39
+ const sender = (context as DhtCallContext).incomingSourceDescriptor!
40
+ const remote = new RemoteRandomGraphNode(
41
+ sender,
42
+ this.config.randomGraphId,
43
+ toProtoRpcClient(new NetworkRpcClient(this.config.rpcCommunicator.getRpcClientTransport()))
44
+ )
45
+ this.temporaryPeers.add(remote)
46
+ return {
47
+ accepted: true
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,17 @@
1
+ import { DuplicateMessageDetector, NumberPair } from './DuplicateMessageDetector'
2
+ import { MessageRef } from '../proto/packages/trackerless-network/protos/NetworkRpc'
3
+
4
+ export const markAndCheckDuplicate = (
5
+ duplicateDetectors: Map<string, DuplicateMessageDetector>,
6
+ currentMessageRef: MessageRef,
7
+ previousMessageRef?: MessageRef
8
+ ): boolean => {
9
+ const detectorKey = `${currentMessageRef.publisherId}-${currentMessageRef.messageChainId}`
10
+ const previousNumberPair = previousMessageRef ?
11
+ new NumberPair(Number(previousMessageRef!.timestamp), previousMessageRef!.sequenceNumber) : null
12
+ const currentNumberPair = new NumberPair(Number(currentMessageRef.timestamp), currentMessageRef.sequenceNumber)
13
+ if (!duplicateDetectors.has(detectorKey)) {
14
+ duplicateDetectors.set(detectorKey, new DuplicateMessageDetector())
15
+ }
16
+ return duplicateDetectors.get(detectorKey)!.markAndCheck(previousNumberPair, currentNumberPair)
17
+ }