@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,167 @@
1
+ /**
2
+ * Represent a pair of numbers (a,b). Ordering between two pairs is defined as
3
+ * follows. First compare first numbers. Compare second numbers if first are
4
+ * equal.
5
+ */
6
+ export class NumberPair {
7
+ private readonly a
8
+ private readonly b
9
+
10
+ constructor(a: number, b: number) {
11
+ this.a = a
12
+ this.b = b
13
+ }
14
+
15
+ greaterThanOrEqual(otherPair: NumberPair): boolean {
16
+ return this.greaterThan(otherPair) || this.equalTo(otherPair)
17
+ }
18
+
19
+ greaterThan(otherPair: NumberPair): boolean {
20
+ return this.compareTo(otherPair) === 1
21
+ }
22
+
23
+ equalTo(otherPair: NumberPair): boolean {
24
+ return this.compareTo(otherPair) === 0
25
+ }
26
+
27
+ private compareTo(otherPair: NumberPair): number {
28
+ if (this.a > otherPair.a) {
29
+ return 1
30
+ }
31
+ if (this.a < otherPair.a) {
32
+ return -1
33
+ }
34
+ if (this.b > otherPair.b) {
35
+ return 1
36
+ }
37
+ if (this.b < otherPair.b) {
38
+ return -1
39
+ }
40
+ return 0
41
+ }
42
+
43
+ toString(): string {
44
+ return `${this.a}|${this.b}`
45
+ }
46
+ }
47
+
48
+ export class InvalidNumberingError extends Error {
49
+ constructor() {
50
+ super('pre-condition: previousNumber < number')
51
+ }
52
+ }
53
+
54
+ export class GapMisMatchError extends Error {
55
+ constructor(state: string, previousNumber: NumberPair, number: NumberPair) {
56
+ super('pre-condition: gap overlap in given numbers:'
57
+ + ` previousNumber=${previousNumber}, number=${number}, state=${state}`)
58
+ }
59
+ }
60
+
61
+ /**
62
+ *
63
+ * Keeps track of a stream's message numbers and reports already seen numbers
64
+ * as duplicates.
65
+ *
66
+ * Leverages the fact that message are assigned numbers from a strictly
67
+ * increasing integer sequence for lowered space complexity. For example,
68
+ * if we know that all messages up to number N have been seen, we can only
69
+ * store the number N to provide message identity check. This is because
70
+ * anything less than N can be deemed a duplicate.
71
+ *
72
+ * Messages arriving out-of-order makes this a bit harder since gaps form.
73
+ * Most of the code in this class is built to deal with this complexity.
74
+ * Basically, we need to keep track of which intervals [N,M] could still
75
+ * contain unseen messages. We should also remove intervals after we are sure
76
+ * that they contain no unseen messages.
77
+ *
78
+ * In addition to the above, there needs to be a limit to the number of
79
+ * intervals we store, as it could well be that some messages never
80
+ * arrive. The strategy is to start removing the lowest numbered
81
+ * intervals when storage limits are hit.
82
+ *
83
+ */
84
+ export class DuplicateMessageDetector {
85
+ private readonly maxNumberOfGaps: number
86
+ private readonly gaps: Array<[NumberPair, NumberPair]>
87
+
88
+ constructor(maxNumberOfGaps = 10000) {
89
+ this.maxNumberOfGaps = maxNumberOfGaps
90
+ this.gaps = [] // ascending order of half-closed intervals (x,y] representing gaps that contain unseen message(s)
91
+ }
92
+
93
+ /**
94
+ * returns true if number has not yet been seen (i.e. is not a duplicate)
95
+ */
96
+ markAndCheck(previousNumber: NumberPair | null, number: NumberPair): boolean | never {
97
+ if (previousNumber && previousNumber.greaterThanOrEqual(number)) {
98
+ throw new InvalidNumberingError()
99
+ }
100
+
101
+ if (this.gaps.length === 0) {
102
+ this.gaps.push([number, new NumberPair(Infinity, Infinity)])
103
+ return true
104
+ }
105
+
106
+ // Handle special case where previousNumber is not provided. Only
107
+ // minimal duplicate detection is provided (comparing against latest
108
+ // known message number).
109
+ if (previousNumber === null) {
110
+ if (number.greaterThan(this.gaps[this.gaps.length - 1][0])) {
111
+ this.gaps[this.gaps.length - 1][0] = number
112
+ return true
113
+ }
114
+ return false
115
+ }
116
+
117
+ for (let i = this.gaps.length - 1; i >= 0; --i) {
118
+ const [lowerBound, upperBound] = this.gaps[i] // invariant: upperBound > lowerBound
119
+
120
+ // implies number > upperBound (would've been handled in previous iteration if gap exists)
121
+ if (previousNumber.greaterThanOrEqual(upperBound)) {
122
+ return false
123
+ }
124
+ if (previousNumber.greaterThanOrEqual(lowerBound)) {
125
+ if (number.greaterThan(upperBound)) {
126
+ throw new GapMisMatchError(this.toString(), previousNumber, number)
127
+ }
128
+ if (previousNumber.equalTo(lowerBound)) {
129
+ if (number.equalTo(upperBound)) {
130
+ this.gaps.splice(i, 1)
131
+ } else {
132
+ this.gaps[i] = [number, upperBound]
133
+ }
134
+ } else if (number.equalTo(upperBound)) {
135
+ this.gaps[i] = [lowerBound, previousNumber]
136
+ } else {
137
+ this.gaps.splice(i, 1, [lowerBound, previousNumber], [number, upperBound])
138
+ }
139
+
140
+ // invariants after:
141
+ // - gaps are in ascending order
142
+ // - the intersection between any two gaps is empty
143
+ // - there are no gaps that define the empty set
144
+ // - last gap is [n, Infinity]
145
+ // - anything not covered by a gap is considered seen
146
+
147
+ this.dropLowestGapIfOverMaxNumberOfGaps()
148
+ return true
149
+ }
150
+ if (number.greaterThan(lowerBound)) {
151
+ throw new GapMisMatchError(this.toString(), previousNumber, number)
152
+ }
153
+ }
154
+ return false
155
+ }
156
+
157
+ private dropLowestGapIfOverMaxNumberOfGaps(): void {
158
+ // invariant: this.gaps.length <= this.maxNumberOfGaps + 1
159
+ if (this.gaps.length > this.maxNumberOfGaps) {
160
+ this.gaps.shift()
161
+ }
162
+ }
163
+
164
+ toString(): string {
165
+ return this.gaps.map(([lower, upper]) => `(${lower}, ${upper}]`).join(', ')
166
+ }
167
+ }
@@ -0,0 +1,14 @@
1
+ import { DataEntry, ITransport, PeerDescriptor, PeerID, RecursiveFindResult } from '@streamr/dht'
2
+ import { Any } from '../proto/google/protobuf/any'
3
+
4
+ export interface ILayer0 extends ITransport {
5
+ getPeerDescriptor(): PeerDescriptor
6
+ getNodeId(): PeerID
7
+ getDataFromDht(key: Uint8Array): Promise<RecursiveFindResult>
8
+ findDataViaPeer(key: Uint8Array, peer: PeerDescriptor): Promise<DataEntry[]>
9
+ storeDataToDht(key: Uint8Array, data: Any): Promise<PeerDescriptor[]>
10
+ deleteDataFromDht(key: Uint8Array): Promise<void>
11
+ getKnownEntryPoints(): PeerDescriptor[]
12
+ isJoinOngoing(): boolean
13
+ stop(): Promise<void>
14
+ }
@@ -0,0 +1,17 @@
1
+ import { PeerIDKey } from '@streamr/dht'
2
+ import { ProxyDirection, StreamMessage } from '../proto/packages/trackerless-network/protos/NetworkRpc'
3
+
4
+ export interface IStreamNode {
5
+
6
+ on(event: 'message', listener: (message: StreamMessage) => void): this
7
+
8
+ once(event: 'message', listener: (message: StreamMessage) => void): this
9
+
10
+ off(event: 'message', listener: (message: StreamMessage) => void): void
11
+
12
+ broadcast(msg: StreamMessage, previousPeer?: string): void
13
+ hasProxyConnection(peerKey: PeerIDKey, direction: ProxyDirection): boolean
14
+ stop(): void
15
+ start(): Promise<void>
16
+ getTargetNeighborStringIds(): string[]
17
+ }
@@ -0,0 +1,106 @@
1
+ import { keyFromPeerDescriptor, PeerDescriptor, PeerID, peerIdFromPeerDescriptor } from '@streamr/dht'
2
+ import { sample } from 'lodash'
3
+ import { RemoteRandomGraphNode } from './RemoteRandomGraphNode'
4
+ import { EventEmitter } from 'eventemitter3'
5
+
6
+ export interface Events {
7
+ peerAdded: (id: string, remote: RemoteRandomGraphNode) => any
8
+ }
9
+
10
+ const getValuesOfIncludedKeys = (peers: Map<string, RemoteRandomGraphNode>, exclude: string[]): RemoteRandomGraphNode[] => {
11
+ return Array.from(peers.entries())
12
+ .filter(([id, _peer]) => !exclude.includes(id))
13
+ .map(([_id, peer]) => peer)
14
+ }
15
+
16
+ export class PeerList extends EventEmitter<Events> {
17
+ private readonly peers: Map<string, RemoteRandomGraphNode>
18
+ private readonly limit: number
19
+ private ownPeerID: PeerID
20
+
21
+ constructor(ownPeerId: PeerID, limit: number) {
22
+ super()
23
+ this.peers = new Map()
24
+ this.limit = limit
25
+ this.ownPeerID = ownPeerId
26
+ }
27
+
28
+ add(remote: RemoteRandomGraphNode): void {
29
+ if (!this.ownPeerID.equals(peerIdFromPeerDescriptor(remote.getPeerDescriptor())) && this.peers.size < this.limit) {
30
+ const stringId = keyFromPeerDescriptor(remote.getPeerDescriptor())
31
+ const isExistingPeer = this.peers.has(stringId)
32
+ this.peers.set(stringId, remote)
33
+
34
+ if (!isExistingPeer) {
35
+ this.emit('peerAdded', stringId, remote)
36
+ }
37
+ }
38
+ }
39
+
40
+ remove(peerDescriptor: PeerDescriptor): void {
41
+ this.peers.delete(keyFromPeerDescriptor(peerDescriptor))
42
+ }
43
+
44
+ removeById(stringId: string): void {
45
+ this.peers.delete(stringId)
46
+ }
47
+
48
+ hasPeer(peerDescriptor: PeerDescriptor): boolean {
49
+ return this.peers.has(keyFromPeerDescriptor(peerDescriptor))
50
+ }
51
+
52
+ hasPeerWithStringId(stringId: string): boolean {
53
+ return this.peers.has(stringId)
54
+ }
55
+
56
+ replaceAll(neighbors: RemoteRandomGraphNode[]): void {
57
+ this.peers.clear()
58
+ const limited = neighbors.splice(0, this.limit)
59
+ limited.forEach((remote) => {
60
+ this.add(remote)
61
+ })
62
+ }
63
+
64
+ getStringIds(): string[] {
65
+ return Array.from(this.peers.keys())
66
+ }
67
+
68
+ getNeighborById(id: string): RemoteRandomGraphNode | undefined {
69
+ return this.peers.get(id)
70
+ }
71
+
72
+ size(exclude: string[] = []): number {
73
+ return Array.from(this.peers.keys()).filter((peer) => !exclude.includes(peer)).length
74
+ }
75
+
76
+ getRandom(exclude: string[]): RemoteRandomGraphNode | undefined {
77
+ return sample(getValuesOfIncludedKeys(this.peers, exclude))
78
+ }
79
+
80
+ getClosest(exclude: string[]): RemoteRandomGraphNode | undefined {
81
+ const included = getValuesOfIncludedKeys(this.peers, exclude)
82
+ return included[0]
83
+ }
84
+
85
+ getClosestAndFurthest(exclude: string[]): RemoteRandomGraphNode[] {
86
+ const included = getValuesOfIncludedKeys(this.peers, exclude)
87
+ if (included.length === 0) {
88
+ return []
89
+ }
90
+ return included.length > 1 ? [this.getClosest(exclude)!, this.getFurthest(exclude)!] : [this.getClosest(exclude)!]
91
+ }
92
+
93
+ getFurthest(exclude: string[]): RemoteRandomGraphNode | undefined {
94
+ const included = getValuesOfIncludedKeys(this.peers, exclude)
95
+ return included[included.length - 1]
96
+ }
97
+
98
+ getPeers(): RemoteRandomGraphNode[] {
99
+ return Array.from(this.peers.values())
100
+ }
101
+
102
+ stop(): void {
103
+ this.peers.clear()
104
+ this.removeAllListeners()
105
+ }
106
+ }
@@ -0,0 +1,310 @@
1
+ import { EventEmitter } from 'eventemitter3'
2
+ import {
3
+ DhtNode,
4
+ PeerDescriptor,
5
+ DhtPeer,
6
+ ListeningRpcCommunicator,
7
+ ITransport,
8
+ ConnectionLocker,
9
+ keyFromPeerDescriptor,
10
+ PeerIDKey
11
+ } from '@streamr/dht'
12
+ import {
13
+ StreamMessage,
14
+ LeaveStreamNotice,
15
+ MessageRef,
16
+ StreamMessageType,
17
+ GroupKeyRequest,
18
+ TemporaryConnectionRequest,
19
+ TemporaryConnectionResponse,
20
+ } from '../proto/packages/trackerless-network/protos/NetworkRpc'
21
+ import { PeerList } from './PeerList'
22
+ import { NetworkRpcClient } from '../proto/packages/trackerless-network/protos/NetworkRpc.client'
23
+ import { RemoteRandomGraphNode } from './RemoteRandomGraphNode'
24
+ import { INetworkRpc } from '../proto/packages/trackerless-network/protos/NetworkRpc.server'
25
+ import { DuplicateMessageDetector } from './DuplicateMessageDetector'
26
+ import { Logger } from '@streamr/utils'
27
+ import { toProtoRpcClient } from '@streamr/proto-rpc'
28
+ import { IHandshaker } from './neighbor-discovery/Handshaker'
29
+ import { Propagation } from './propagation/Propagation'
30
+ import { INeighborFinder } from './neighbor-discovery/NeighborFinder'
31
+ import { INeighborUpdateManager } from './neighbor-discovery/NeighborUpdateManager'
32
+ import { StreamNodeServer } from './StreamNodeServer'
33
+ import { IStreamNode } from './IStreamNode'
34
+ import { ProxyStreamConnectionServer } from './proxy/ProxyStreamConnectionServer'
35
+ import { IInspector } from './inspect/Inspector'
36
+ import { TemporaryConnectionRpcServer } from './temporary-connection/TemporaryConnectionRpcServer'
37
+ import { markAndCheckDuplicate } from './utils'
38
+
39
+ export interface Events {
40
+ message: (message: StreamMessage) => void
41
+ targetNeighborConnected: (stringId: string) => void
42
+ nearbyContactPoolIdAdded: () => void
43
+ }
44
+
45
+ export interface StrictRandomGraphNodeConfig {
46
+ randomGraphId: string
47
+ layer1: DhtNode
48
+ P2PTransport: ITransport
49
+ connectionLocker: ConnectionLocker
50
+ ownPeerDescriptor: PeerDescriptor
51
+ peerViewSize: number
52
+ nearbyContactPool: PeerList
53
+ randomContactPool: PeerList
54
+ targetNeighbors: PeerList
55
+ handshaker: IHandshaker
56
+ neighborFinder: INeighborFinder
57
+ neighborUpdateManager: INeighborUpdateManager
58
+ propagation: Propagation
59
+ rpcCommunicator: ListeningRpcCommunicator
60
+ numOfTargetNeighbors: number
61
+ maxNumberOfContacts: number
62
+ minPropagationTargets: number
63
+ name: string
64
+ acceptProxyConnections: boolean
65
+ neighborUpdateInterval: number
66
+ inspector: IInspector
67
+ temporaryConnectionServer: TemporaryConnectionRpcServer
68
+ proxyConnectionServer?: ProxyStreamConnectionServer
69
+ }
70
+
71
+ const logger = new Logger(module)
72
+
73
+ export class RandomGraphNode extends EventEmitter<Events> implements IStreamNode {
74
+ private stopped = false
75
+ private started = false
76
+ private readonly duplicateDetectors: Map<string, DuplicateMessageDetector>
77
+ private config: StrictRandomGraphNodeConfig
78
+ private readonly server: INetworkRpc
79
+
80
+ constructor(config: StrictRandomGraphNodeConfig) {
81
+ super()
82
+ this.config = config
83
+ this.duplicateDetectors = new Map()
84
+ this.server = new StreamNodeServer({
85
+ ownPeerDescriptor: this.config.ownPeerDescriptor,
86
+ randomGraphId: this.config.randomGraphId,
87
+ rpcCommunicator: this.config.rpcCommunicator,
88
+ markAndCheckDuplicate: (msg: MessageRef, prev?: MessageRef) => markAndCheckDuplicate(this.duplicateDetectors, msg, prev),
89
+ broadcast: (message: StreamMessage, previousPeer?: string) => this.broadcast(message, previousPeer),
90
+ onLeaveNotice: (notice: LeaveStreamNotice) => {
91
+ const senderId = notice.senderId
92
+ const contact = this.config.nearbyContactPool.getNeighborById(senderId)
93
+ || this.config.randomContactPool.getNeighborById(senderId)
94
+ || this.config.targetNeighbors.getNeighborById(senderId)
95
+ || this.config.proxyConnectionServer?.getConnection(senderId as PeerIDKey)?.remote
96
+ // TODO: check integrity of notifier?
97
+ if (contact) {
98
+ this.config.layer1.removeContact(contact.getPeerDescriptor(), true)
99
+ this.config.targetNeighbors.remove(contact.getPeerDescriptor())
100
+ this.config.nearbyContactPool.remove(contact.getPeerDescriptor())
101
+ this.config.connectionLocker.unlockConnection(contact.getPeerDescriptor(), this.config.randomGraphId)
102
+ this.config.neighborFinder.start([senderId])
103
+ this.config.proxyConnectionServer?.removeConnection(senderId as PeerIDKey)
104
+ }
105
+ },
106
+ markForInspection: (senderId: PeerIDKey, messageRef: MessageRef) => this.config.inspector.markMessage(senderId, messageRef)
107
+ })
108
+ }
109
+
110
+ async start(): Promise<void> {
111
+ this.started = true
112
+ this.registerDefaultServerMethods()
113
+ this.config.layer1.on('newContact', (peerDescriptor, closestPeers) => this.newContact(peerDescriptor, closestPeers))
114
+ this.config.layer1.on('contactRemoved', (peerDescriptor, closestPeers) => this.removedContact(peerDescriptor, closestPeers))
115
+ this.config.layer1.on('newRandomContact', (peerDescriptor, randomPeers) => this.newRandomContact(peerDescriptor, randomPeers))
116
+ this.config.layer1.on('randomContactRemoved', (peerDescriptor, randomPeers) => this.removedRandomContact(peerDescriptor, randomPeers))
117
+ this.config.P2PTransport.on('disconnected', (peerDescriptor: PeerDescriptor) => this.onPeerDisconnected(peerDescriptor))
118
+ this.config.targetNeighbors.on('peerAdded', (id, _remote) => {
119
+ this.config.propagation.onNeighborJoined(id)
120
+ this.emit('targetNeighborConnected', id)
121
+ })
122
+ this.config.proxyConnectionServer?.on('newConnection', (id: PeerIDKey) => {
123
+ this.config.propagation.onNeighborJoined(id)
124
+ })
125
+ const candidates = this.getNewNeighborCandidates()
126
+ if (candidates.length > 0) {
127
+ this.newContact(candidates[0], candidates)
128
+ } else {
129
+ logger.debug('layer1 had no closest contacts in the beginning')
130
+ }
131
+ this.config.neighborFinder.start()
132
+ await this.config.neighborUpdateManager.start()
133
+ }
134
+
135
+ private registerDefaultServerMethods(): void {
136
+ this.config.rpcCommunicator.registerRpcNotification(StreamMessage, 'sendData',
137
+ (msg: StreamMessage, context) => this.server.sendData(msg, context))
138
+ this.config.rpcCommunicator.registerRpcNotification(LeaveStreamNotice, 'leaveStreamNotice',
139
+ (req: LeaveStreamNotice, context) => this.server.leaveStreamNotice(req, context))
140
+ this.config.rpcCommunicator.registerRpcMethod(TemporaryConnectionRequest, TemporaryConnectionResponse, 'openConnection',
141
+ (req: TemporaryConnectionRequest, context) => this.config.temporaryConnectionServer.openConnection(req, context))
142
+ }
143
+
144
+ private newContact(_newContact: PeerDescriptor, closestTen: PeerDescriptor[]): void {
145
+ logger.trace(`New nearby contact found`)
146
+ if (this.stopped) {
147
+ return
148
+ }
149
+
150
+ const oldLength = this.config.nearbyContactPool.getStringIds().length
151
+ this.config.nearbyContactPool.replaceAll(closestTen.map((descriptor) =>
152
+ new RemoteRandomGraphNode(
153
+ descriptor,
154
+ this.config.randomGraphId,
155
+ toProtoRpcClient(new NetworkRpcClient(this.config.rpcCommunicator.getRpcClientTransport()))
156
+ )
157
+ ))
158
+
159
+ if (oldLength < this.config.nearbyContactPool.getStringIds().length) {
160
+ this.emit('nearbyContactPoolIdAdded')
161
+ }
162
+
163
+ if (this.config.targetNeighbors.size() < this.config.numOfTargetNeighbors) {
164
+ this.config.neighborFinder.start()
165
+ }
166
+ }
167
+
168
+ private removedContact(_removedContact: PeerDescriptor, closestTen: PeerDescriptor[]): void {
169
+ logger.trace(`Nearby contact removed`)
170
+ if (this.stopped) {
171
+ return
172
+ }
173
+ this.config.nearbyContactPool.replaceAll(closestTen.map((descriptor) =>
174
+ new RemoteRandomGraphNode(
175
+ descriptor,
176
+ this.config.randomGraphId,
177
+ toProtoRpcClient(new NetworkRpcClient(this.config.rpcCommunicator.getRpcClientTransport()))
178
+ )
179
+ ))
180
+ }
181
+
182
+ private newRandomContact(_newDescriptor: PeerDescriptor, randomPeers: PeerDescriptor[]): void {
183
+ if (this.stopped) {
184
+ return
185
+ }
186
+ this.config.randomContactPool.replaceAll(randomPeers.map((descriptor) =>
187
+ new RemoteRandomGraphNode(
188
+ descriptor,
189
+ this.config.randomGraphId,
190
+ toProtoRpcClient(new NetworkRpcClient(this.config.rpcCommunicator.getRpcClientTransport()))
191
+ )
192
+ ))
193
+ if (this.config.targetNeighbors.size() < this.config.numOfTargetNeighbors) {
194
+ this.config.neighborFinder.start()
195
+ }
196
+ }
197
+
198
+ private removedRandomContact(_removedDescriptor: PeerDescriptor, randomPeers: PeerDescriptor[]): void {
199
+ logger.trace(`New nearby contact found`)
200
+ if (this.stopped) {
201
+ return
202
+ }
203
+ this.config.randomContactPool!.replaceAll(randomPeers.map((descriptor) =>
204
+ new RemoteRandomGraphNode(
205
+ descriptor,
206
+ this.config.randomGraphId,
207
+ toProtoRpcClient(new NetworkRpcClient(this.config.rpcCommunicator.getRpcClientTransport()))
208
+ )
209
+ ))
210
+ }
211
+
212
+ private onPeerDisconnected(peerDescriptor: PeerDescriptor): void {
213
+ if (this.config.targetNeighbors.hasPeer(peerDescriptor)) {
214
+ this.config.targetNeighbors.remove(peerDescriptor)
215
+ this.config.connectionLocker.unlockConnection(peerDescriptor, this.config.randomGraphId)
216
+ this.config.neighborFinder.start([keyFromPeerDescriptor(peerDescriptor)])
217
+ this.config.temporaryConnectionServer.removePeer(peerDescriptor)
218
+ }
219
+ }
220
+
221
+ private getNewNeighborCandidates(): PeerDescriptor[] {
222
+ return this.config.layer1.getNeighborList().getClosestContacts(this.config.peerViewSize).map((contact: DhtPeer) => {
223
+ return contact.getPeerDescriptor()
224
+ })
225
+ }
226
+
227
+ public hasProxyConnection(peerKey: PeerIDKey): boolean {
228
+ if (this.config.proxyConnectionServer) {
229
+ return this.config.proxyConnectionServer.hasConnection(peerKey)
230
+ }
231
+ return false
232
+ }
233
+
234
+ stop(): void {
235
+ if (!this.started) {
236
+ return
237
+ }
238
+ this.stopped = true
239
+ this.config.proxyConnectionServer?.stop()
240
+ this.config.targetNeighbors.getPeers().map((remote) => remote.leaveStreamNotice(this.config.ownPeerDescriptor))
241
+ this.config.rpcCommunicator.stop()
242
+ this.removeAllListeners()
243
+ this.config.layer1.off('newContact', (peerDescriptor, closestTen) => this.newContact(peerDescriptor, closestTen))
244
+ this.config.layer1.off('contactRemoved', (peerDescriptor, closestTen) => this.removedContact(peerDescriptor, closestTen))
245
+ this.config.layer1.off('newRandomContact', (peerDescriptor, randomPeers) => this.newRandomContact(peerDescriptor, randomPeers))
246
+ this.config.layer1.off('randomContactRemoved', (peerDescriptor, randomPeers) => this.removedRandomContact(peerDescriptor, randomPeers))
247
+ this.config.P2PTransport.off('disconnected', (peerDescriptor: PeerDescriptor) => this.onPeerDisconnected(peerDescriptor))
248
+ this.config.nearbyContactPool.stop()
249
+ this.config.targetNeighbors.stop()
250
+ this.config.randomContactPool.stop()
251
+ this.config.neighborFinder.stop()
252
+ this.config.neighborUpdateManager.stop()
253
+ this.config.inspector.stop()
254
+ }
255
+
256
+ broadcast(msg: StreamMessage, previousPeer?: string): void {
257
+ if (!previousPeer) {
258
+ markAndCheckDuplicate(this.duplicateDetectors, msg.messageRef!, msg.previousMessageRef)
259
+ }
260
+ this.emit('message', msg)
261
+ this.config.propagation.feedUnseenMessage(msg, this.getPropagationTargets(msg), previousPeer ?? null)
262
+ }
263
+
264
+ inspect(peerDescriptor: PeerDescriptor): Promise<boolean> {
265
+ return this.config.inspector.inspect(peerDescriptor)
266
+ }
267
+
268
+ private getPropagationTargets(msg: StreamMessage): string[] {
269
+ let propagationTargets = this.config.targetNeighbors.getStringIds()
270
+ if (this.config.proxyConnectionServer) {
271
+ const proxyTargets = (msg.messageType === StreamMessageType.GROUP_KEY_REQUEST)
272
+ ? this.config.proxyConnectionServer.getPeerKeysForUserId(GroupKeyRequest.fromBinary(msg.content).recipient)
273
+ : this.config.proxyConnectionServer.getSubscribers()
274
+ propagationTargets = propagationTargets.concat(proxyTargets)
275
+ }
276
+
277
+ propagationTargets = propagationTargets.filter((target) => !this.config.inspector.isInspected(target as PeerIDKey))
278
+ propagationTargets = propagationTargets.concat(this.config.temporaryConnectionServer.getPeers().getStringIds())
279
+ return propagationTargets
280
+ }
281
+
282
+ getOwnStringId(): PeerIDKey {
283
+ return keyFromPeerDescriptor(this.config.ownPeerDescriptor)
284
+ }
285
+
286
+ getNumberOfOutgoingHandshakes(): number {
287
+ return this.config.handshaker.getOngoingHandshakes().size
288
+ }
289
+
290
+ getTargetNeighborStringIds(): string[] {
291
+ if (!this.started && this.stopped) {
292
+ return []
293
+ }
294
+ return this.config.targetNeighbors.getStringIds()
295
+ }
296
+
297
+ getNearbyContactPoolIds(): string[] {
298
+ if (!this.started && this.stopped) {
299
+ return []
300
+ }
301
+ return this.config.nearbyContactPool.getStringIds()
302
+ }
303
+
304
+ getRandomContactPoolIds(): string[] {
305
+ if (!this.started && this.stopped) {
306
+ return []
307
+ }
308
+ return this.config.randomContactPool.getStringIds()
309
+ }
310
+ }
@@ -0,0 +1,19 @@
1
+ import { PeerDescriptor } from '@streamr/dht'
2
+ import { ProtoRpcClient } from '@streamr/proto-rpc'
3
+
4
+ export abstract class Remote<T> {
5
+ protected remotePeerDescriptor: PeerDescriptor
6
+ protected client: ProtoRpcClient<T>
7
+ protected graphId: string
8
+
9
+ constructor(peerDescriptor: PeerDescriptor, graphId: string, client: ProtoRpcClient<T>) {
10
+ this.remotePeerDescriptor = peerDescriptor
11
+ this.client = client
12
+ this.graphId = graphId
13
+ }
14
+
15
+ getPeerDescriptor(): PeerDescriptor {
16
+ return this.remotePeerDescriptor
17
+ }
18
+
19
+ }
@@ -0,0 +1,39 @@
1
+ import { INetworkRpcClient } from '../proto/packages/trackerless-network/protos/NetworkRpc.client'
2
+ import { PeerDescriptor, DhtRpcOptions, keyFromPeerDescriptor } from '@streamr/dht'
3
+ import {
4
+ StreamMessage,
5
+ LeaveStreamNotice
6
+ } from '../proto/packages/trackerless-network/protos/NetworkRpc'
7
+ import { Logger } from '@streamr/utils'
8
+ import { Remote } from './Remote'
9
+
10
+ const logger = new Logger(module)
11
+
12
+ export class RemoteRandomGraphNode extends Remote<INetworkRpcClient> {
13
+
14
+ async sendData(ownPeerDescriptor: PeerDescriptor, msg: StreamMessage): Promise<void> {
15
+ const options: DhtRpcOptions = {
16
+ sourceDescriptor: ownPeerDescriptor as PeerDescriptor,
17
+ targetDescriptor: this.remotePeerDescriptor as PeerDescriptor,
18
+ notification: true
19
+ }
20
+ this.client.sendData(msg, options).catch(() => {
21
+ logger.trace('Failed to sendData')
22
+ })
23
+ }
24
+
25
+ leaveStreamNotice(ownPeerDescriptor: PeerDescriptor): void {
26
+ const options: DhtRpcOptions = {
27
+ sourceDescriptor: ownPeerDescriptor as PeerDescriptor,
28
+ targetDescriptor: this.remotePeerDescriptor as PeerDescriptor,
29
+ notification: true
30
+ }
31
+ const notification: LeaveStreamNotice = {
32
+ senderId: keyFromPeerDescriptor(ownPeerDescriptor),
33
+ randomGraphId: this.graphId
34
+ }
35
+ this.client.leaveStreamNotice(notification, options).catch(() => {
36
+ logger.debug('Failed to send leaveStreamNotice')
37
+ })
38
+ }
39
+ }