@streamr/trackerless-network 102.0.0-beta.1 → 102.0.0-beta.3

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 (103) hide show
  1. package/dist/package.json +5 -5
  2. package/package.json +5 -5
  3. package/src/NetworkNode.ts +0 -142
  4. package/src/NetworkStack.ts +0 -197
  5. package/src/exports.ts +0 -18
  6. package/src/logic/ContentDeliveryLayerNode.ts +0 -424
  7. package/src/logic/ContentDeliveryManager.ts +0 -401
  8. package/src/logic/ContentDeliveryRpcLocal.ts +0 -48
  9. package/src/logic/ContentDeliveryRpcRemote.ts +0 -44
  10. package/src/logic/ControlLayerNode.ts +0 -17
  11. package/src/logic/DiscoveryLayerNode.ts +0 -30
  12. package/src/logic/DuplicateMessageDetector.ts +0 -167
  13. package/src/logic/ExternalNetworkRpc.ts +0 -42
  14. package/src/logic/NodeList.ts +0 -114
  15. package/src/logic/PeerDescriptorStoreManager.ts +0 -96
  16. package/src/logic/StreamPartNetworkSplitAvoidance.ts +0 -90
  17. package/src/logic/StreamPartReconnect.ts +0 -38
  18. package/src/logic/createContentDeliveryLayerNode.ts +0 -130
  19. package/src/logic/formStreamPartDeliveryServiceId.ts +0 -7
  20. package/src/logic/inspect/InspectSession.ts +0 -55
  21. package/src/logic/inspect/Inspector.ts +0 -100
  22. package/src/logic/neighbor-discovery/HandshakeRpcLocal.ts +0 -138
  23. package/src/logic/neighbor-discovery/HandshakeRpcRemote.ts +0 -66
  24. package/src/logic/neighbor-discovery/Handshaker.ts +0 -215
  25. package/src/logic/neighbor-discovery/NeighborFinder.ts +0 -77
  26. package/src/logic/neighbor-discovery/NeighborUpdateManager.ts +0 -69
  27. package/src/logic/neighbor-discovery/NeighborUpdateRpcLocal.ts +0 -75
  28. package/src/logic/neighbor-discovery/NeighborUpdateRpcRemote.ts +0 -35
  29. package/src/logic/node-info/NodeInfoClient.ts +0 -23
  30. package/src/logic/node-info/NodeInfoRpcLocal.ts +0 -28
  31. package/src/logic/node-info/NodeInfoRpcRemote.ts +0 -11
  32. package/src/logic/propagation/FifoMapWithTTL.ts +0 -116
  33. package/src/logic/propagation/Propagation.ts +0 -84
  34. package/src/logic/propagation/PropagationTaskStore.ts +0 -41
  35. package/src/logic/proxy/ProxyClient.ts +0 -286
  36. package/src/logic/proxy/ProxyConnectionRpcLocal.ts +0 -106
  37. package/src/logic/proxy/ProxyConnectionRpcRemote.ts +0 -26
  38. package/src/logic/temporary-connection/TemporaryConnectionRpcLocal.ts +0 -73
  39. package/src/logic/temporary-connection/TemporaryConnectionRpcRemote.ts +0 -29
  40. package/src/logic/utils.ts +0 -18
  41. package/src/types.ts +0 -13
  42. package/test/benchmark/StreamPartIdDataKeyDistribution.test.ts +0 -60
  43. package/test/benchmark/first-message.ts +0 -171
  44. package/test/end-to-end/content-delivery-layer-node-with-real-connections.test.ts +0 -165
  45. package/test/end-to-end/external-network-rpc.test.ts +0 -67
  46. package/test/end-to-end/inspect.test.ts +0 -124
  47. package/test/end-to-end/proxy-and-full-node.test.ts +0 -143
  48. package/test/end-to-end/proxy-connections.test.ts +0 -226
  49. package/test/end-to-end/proxy-key-exchange.test.ts +0 -126
  50. package/test/end-to-end/webrtc-full-node-network.test.ts +0 -83
  51. package/test/end-to-end/websocket-full-node-network.test.ts +0 -82
  52. package/test/integration/ContentDeliveryLayerNode-Layer1Node-Latencies.test.ts +0 -139
  53. package/test/integration/ContentDeliveryLayerNode-Layer1Node.test.ts +0 -162
  54. package/test/integration/ContentDeliveryManager.test.ts +0 -160
  55. package/test/integration/ContentDeliveryRpcRemote.test.ts +0 -100
  56. package/test/integration/HandshakeRpcRemote.test.ts +0 -79
  57. package/test/integration/Handshakes.test.ts +0 -141
  58. package/test/integration/Inspect.test.ts +0 -89
  59. package/test/integration/NeighborUpdateRpcRemote.test.ts +0 -82
  60. package/test/integration/NetworkNode.test.ts +0 -115
  61. package/test/integration/NetworkRpc.test.ts +0 -52
  62. package/test/integration/NetworkStack.test.ts +0 -72
  63. package/test/integration/NodeInfoRpc.test.ts +0 -109
  64. package/test/integration/Propagation.test.ts +0 -76
  65. package/test/integration/joining-streams-on-offline-peers.test.ts +0 -82
  66. package/test/integration/stream-without-default-entrypoints.test.ts +0 -128
  67. package/test/integration/streamEntryPointReplacing.test.ts +0 -97
  68. package/test/types/global.d.ts +0 -1
  69. package/test/unit/ContentDeliveryLayerNode.test.ts +0 -112
  70. package/test/unit/ContentDeliveryManager.test.ts +0 -96
  71. package/test/unit/ContentDeliveryRpcLocal.test.ts +0 -60
  72. package/test/unit/DuplicateMessageDetector.test.ts +0 -192
  73. package/test/unit/ExternalNetworkRpc.test.ts +0 -48
  74. package/test/unit/FifoMapWithTtl.test.ts +0 -253
  75. package/test/unit/HandshakeRpcLocal.test.ts +0 -155
  76. package/test/unit/Handshaker.test.ts +0 -69
  77. package/test/unit/InspectSession.test.ts +0 -83
  78. package/test/unit/Inspector.test.ts +0 -51
  79. package/test/unit/NeighborFinder.test.ts +0 -51
  80. package/test/unit/NeighborUpdateRpcLocal.test.ts +0 -139
  81. package/test/unit/NetworkNode.test.ts +0 -42
  82. package/test/unit/NodeList.test.ts +0 -164
  83. package/test/unit/NumberPair.test.ts +0 -22
  84. package/test/unit/PeerDescriptorStoreManager.test.ts +0 -103
  85. package/test/unit/Propagation.test.ts +0 -151
  86. package/test/unit/ProxyConnectionRpcRemote.test.ts +0 -39
  87. package/test/unit/StreamPartIDDataKey.test.ts +0 -12
  88. package/test/unit/StreamPartNetworkSplitAvoidance.test.ts +0 -31
  89. package/test/unit/StreamPartReconnect.test.ts +0 -30
  90. package/test/unit/TemporaryConnectionRpcLocal.test.ts +0 -38
  91. package/test/utils/fake/FakePeerDescriptorStoreManager.ts +0 -29
  92. package/test/utils/mock/MockConnectionsView.ts +0 -18
  93. package/test/utils/mock/MockControlLayerNode.ts +0 -78
  94. package/test/utils/mock/MockDiscoveryLayerNode.ts +0 -60
  95. package/test/utils/mock/MockHandshaker.ts +0 -17
  96. package/test/utils/mock/MockNeighborFinder.ts +0 -20
  97. package/test/utils/mock/MockNeighborUpdateManager.ts +0 -21
  98. package/test/utils/mock/MockTransport.ts +0 -30
  99. package/test/utils/utils.ts +0 -144
  100. package/tsconfig.browser.json +0 -13
  101. package/tsconfig.jest.json +0 -17
  102. package/tsconfig.json +0 -3
  103. package/tsconfig.node.json +0 -17
@@ -1,69 +0,0 @@
1
- import { DhtAddress, ListeningRpcCommunicator, PeerDescriptor, toNodeId } from '@streamr/dht'
2
- import { Logger, StreamPartID, scheduleAtInterval } from '@streamr/utils'
3
- import { NeighborUpdate } from '../../../generated/packages/trackerless-network/protos/NetworkRpc'
4
- import { NeighborUpdateRpcClient } from '../../../generated/packages/trackerless-network/protos/NetworkRpc.client'
5
- import { NodeList } from '../NodeList'
6
- import { NeighborFinder } from './NeighborFinder'
7
- import { NeighborUpdateRpcLocal } from './NeighborUpdateRpcLocal'
8
- import { NeighborUpdateRpcRemote } from './NeighborUpdateRpcRemote'
9
-
10
- interface NeighborUpdateManagerOptions {
11
- localPeerDescriptor: PeerDescriptor
12
- neighbors: NodeList
13
- nearbyNodeView: NodeList
14
- neighborFinder: NeighborFinder
15
- streamPartId: StreamPartID
16
- rpcCommunicator: ListeningRpcCommunicator
17
- neighborUpdateInterval: number
18
- neighborTargetCount: number
19
- ongoingHandshakes: Set<DhtAddress>
20
- }
21
-
22
- const logger = new Logger(module)
23
-
24
- export class NeighborUpdateManager {
25
-
26
- private readonly abortController: AbortController
27
- private readonly options: NeighborUpdateManagerOptions
28
- private readonly rpcLocal: NeighborUpdateRpcLocal
29
-
30
- constructor(options: NeighborUpdateManagerOptions) {
31
- this.abortController = new AbortController()
32
- this.rpcLocal = new NeighborUpdateRpcLocal(options)
33
- this.options = options
34
- this.options.rpcCommunicator.registerRpcMethod(NeighborUpdate, NeighborUpdate, 'neighborUpdate',
35
- (req: NeighborUpdate, context) => this.rpcLocal.neighborUpdate(req, context))
36
- }
37
-
38
- async start(): Promise<void> {
39
- await scheduleAtInterval(() => this.updateNeighborInfo(), this.options.neighborUpdateInterval, false, this.abortController.signal)
40
- }
41
-
42
- stop(): void {
43
- this.abortController.abort()
44
- }
45
-
46
- private async updateNeighborInfo(): Promise<void> {
47
- logger.trace(`Updating neighbor info to nodes`)
48
- const neighborDescriptors = this.options.neighbors.getAll().map((neighbor) => neighbor.getPeerDescriptor())
49
- const startTime = Date.now()
50
- await Promise.allSettled(this.options.neighbors.getAll().map(async (neighbor) => {
51
- const res = await this.createRemote(neighbor.getPeerDescriptor()).updateNeighbors(this.options.streamPartId, neighborDescriptors)
52
- const nodeId = toNodeId(neighbor.getPeerDescriptor())
53
- this.options.neighbors.get(nodeId)!.setRtt(Date.now() - startTime)
54
- if (res.removeMe) {
55
- this.options.neighbors.remove(nodeId)
56
- this.options.neighborFinder.start([nodeId])
57
- }
58
- }))
59
- }
60
-
61
- private createRemote(targetPeerDescriptor: PeerDescriptor): NeighborUpdateRpcRemote {
62
- return new NeighborUpdateRpcRemote(
63
- this.options.localPeerDescriptor,
64
- targetPeerDescriptor,
65
- this.options.rpcCommunicator,
66
- NeighborUpdateRpcClient
67
- )
68
- }
69
- }
@@ -1,75 +0,0 @@
1
- import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
2
- import { DhtAddress, DhtCallContext, ListeningRpcCommunicator, PeerDescriptor, toNodeId } from '@streamr/dht'
3
- import { StreamPartID } from '@streamr/utils'
4
- import { NeighborUpdate } from '../../../generated/packages/trackerless-network/protos/NetworkRpc'
5
- import { ContentDeliveryRpcClient } from '../../../generated/packages/trackerless-network/protos/NetworkRpc.client'
6
- import { INeighborUpdateRpc } from '../../../generated/packages/trackerless-network/protos/NetworkRpc.server'
7
- import { ContentDeliveryRpcRemote } from '../ContentDeliveryRpcRemote'
8
- import { NodeList } from '../NodeList'
9
- import { NeighborFinder } from './NeighborFinder'
10
-
11
- interface NeighborUpdateRpcLocalOptions {
12
- localPeerDescriptor: PeerDescriptor
13
- streamPartId: StreamPartID
14
- neighbors: NodeList
15
- nearbyNodeView: NodeList
16
- neighborFinder: NeighborFinder
17
- rpcCommunicator: ListeningRpcCommunicator
18
- neighborTargetCount: number
19
- ongoingHandshakes: Set<DhtAddress>
20
- }
21
-
22
- export class NeighborUpdateRpcLocal implements INeighborUpdateRpc {
23
-
24
- private readonly options: NeighborUpdateRpcLocalOptions
25
-
26
- constructor(options: NeighborUpdateRpcLocalOptions) {
27
- this.options = options
28
- }
29
-
30
- private updateContacts(neighborDescriptors: PeerDescriptor[]): void {
31
- const ownNodeId = toNodeId(this.options.localPeerDescriptor)
32
- const newPeerDescriptors = neighborDescriptors.filter((peerDescriptor) => {
33
- const nodeId = toNodeId(peerDescriptor)
34
- return nodeId !== ownNodeId && !this.options.neighbors.getIds().includes(nodeId)
35
- })
36
- newPeerDescriptors.forEach((peerDescriptor) => this.options.nearbyNodeView.add(
37
- new ContentDeliveryRpcRemote(
38
- this.options.localPeerDescriptor,
39
- peerDescriptor,
40
- this.options.rpcCommunicator,
41
- ContentDeliveryRpcClient
42
- ))
43
- )
44
- }
45
-
46
- private createResponse(removeMe: boolean): NeighborUpdate {
47
- return {
48
- streamPartId: this.options.streamPartId,
49
- neighborDescriptors: this.options.neighbors.getAll().map((neighbor) => neighbor.getPeerDescriptor()),
50
- removeMe
51
- }
52
- }
53
-
54
- // INeighborUpdateRpc server method
55
- async neighborUpdate(message: NeighborUpdate, context: ServerCallContext): Promise<NeighborUpdate> {
56
- const senderPeerDescriptor = (context as DhtCallContext).incomingSourceDescriptor!
57
- const remoteNodeId = toNodeId(senderPeerDescriptor)
58
- this.updateContacts(message.neighborDescriptors)
59
- if (!this.options.neighbors.has(remoteNodeId) && !this.options.ongoingHandshakes.has(remoteNodeId)) {
60
- return this.createResponse(true)
61
- } else {
62
- const isOverNeighborCount = this.options.neighbors.size() > this.options.neighborTargetCount
63
- // Motivation: We don't know the remote's neighborTargetCount setting here. We only ask to cut connections
64
- // if the remote has a "sufficient" number of neighbors, where "sufficient" means our neighborTargetCount
65
- // setting.
66
- && message.neighborDescriptors.length > this.options.neighborTargetCount
67
- if (!isOverNeighborCount) {
68
- this.options.neighborFinder.start()
69
- } else {
70
- this.options.neighbors.remove(remoteNodeId)
71
- }
72
- return this.createResponse(isOverNeighborCount)
73
- }
74
- }
75
- }
@@ -1,35 +0,0 @@
1
- import { PeerDescriptor, RpcRemote, toNodeId } from '@streamr/dht'
2
- import { Logger, StreamPartID } from '@streamr/utils'
3
- import { NeighborUpdate } from '../../../generated/packages/trackerless-network/protos/NetworkRpc'
4
- import { NeighborUpdateRpcClient } from '../../../generated/packages/trackerless-network/protos/NetworkRpc.client'
5
-
6
- const logger = new Logger(module)
7
-
8
- interface UpdateNeighborsResponse {
9
- peerDescriptors: PeerDescriptor[]
10
- removeMe: boolean
11
- }
12
-
13
- export class NeighborUpdateRpcRemote extends RpcRemote<NeighborUpdateRpcClient> {
14
-
15
- async updateNeighbors(streamPartId: StreamPartID, neighbors: PeerDescriptor[]): Promise<UpdateNeighborsResponse> {
16
- const request: NeighborUpdate = {
17
- streamPartId,
18
- neighborDescriptors: neighbors,
19
- removeMe: false
20
- }
21
- try {
22
- const response = await this.getClient().neighborUpdate(request, this.formDhtRpcOptions())
23
- return {
24
- peerDescriptors: response.neighborDescriptors,
25
- removeMe: response.removeMe
26
- }
27
- } catch (err: any) {
28
- logger.debug(`updateNeighbors to ${toNodeId(this.getPeerDescriptor())} failed`, { err })
29
- return {
30
- peerDescriptors: [],
31
- removeMe: true
32
- }
33
- }
34
- }
35
- }
@@ -1,23 +0,0 @@
1
- import { DhtCallContext, PeerDescriptor } from '@streamr/dht'
2
- import { RpcCommunicator } from '@streamr/proto-rpc'
3
- import { NodeInfo } from '../../types'
4
- import { NodeInfoRpcClient } from '../../../generated/packages/trackerless-network/protos/NetworkRpc.client'
5
- import { NodeInfoRpcRemote } from './NodeInfoRpcRemote'
6
-
7
- export class NodeInfoClient {
8
- private readonly ownPeerDescriptor: PeerDescriptor
9
- private readonly rpcCommunicator: RpcCommunicator<DhtCallContext>
10
-
11
- constructor(ownPeerDescriptor: PeerDescriptor, rpcCommunicator: RpcCommunicator<DhtCallContext>) {
12
- this.ownPeerDescriptor = ownPeerDescriptor
13
- this.rpcCommunicator = rpcCommunicator
14
- }
15
-
16
- async getInfo(node: PeerDescriptor): Promise<NodeInfo> {
17
- const remote = new NodeInfoRpcRemote(this.ownPeerDescriptor, node, this.rpcCommunicator, NodeInfoRpcClient)
18
- // TODO remove casting when we validate NodeInfoResponse messages and therefore can annotate
19
- // each of the field as required in the decorated type
20
- return remote.getInfo() as unknown as NodeInfo
21
- }
22
-
23
- }
@@ -1,28 +0,0 @@
1
- import { NodeInfoRequest, NodeInfoResponse } from '../../../generated/packages/trackerless-network/protos/NetworkRpc'
2
- import { INodeInfoRpc } from '../../../generated/packages/trackerless-network/protos/NetworkRpc.server'
3
- import { NetworkStack } from '../../NetworkStack'
4
- import { ListeningRpcCommunicator } from '@streamr/dht'
5
-
6
- export const NODE_INFO_RPC_SERVICE_ID = 'system/node-info-rpc'
7
-
8
- export class NodeInfoRpcLocal implements INodeInfoRpc {
9
-
10
- private readonly stack: NetworkStack
11
- private readonly rpcCommunicator: ListeningRpcCommunicator
12
-
13
- constructor(stack: NetworkStack, rpcCommunicator: ListeningRpcCommunicator) {
14
- this.stack = stack
15
- this.rpcCommunicator = rpcCommunicator
16
- this.registerDefaultServerMethods()
17
- }
18
-
19
- private registerDefaultServerMethods(): void {
20
- this.rpcCommunicator.registerRpcMethod(NodeInfoRequest, NodeInfoResponse, 'getInfo',
21
- () => this.getInfo())
22
- }
23
-
24
- async getInfo(): Promise<NodeInfoResponse> {
25
- return this.stack.createNodeInfo()
26
- }
27
-
28
- }
@@ -1,11 +0,0 @@
1
- import { NodeInfoResponse } from '../../../generated/packages/trackerless-network/protos/NetworkRpc'
2
- import { NodeInfoRpcClient } from '../../../generated/packages/trackerless-network/protos/NetworkRpc.client'
3
- import { RpcRemote } from '@streamr/dht'
4
-
5
- export class NodeInfoRpcRemote extends RpcRemote<NodeInfoRpcClient> {
6
-
7
- async getInfo(): Promise<NodeInfoResponse> {
8
- return this.getClient().getInfo({}, this.formDhtRpcOptions())
9
- }
10
-
11
- }
@@ -1,116 +0,0 @@
1
- import { Node, Yallist } 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 = Yallist.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(): V[] {
106
- const keys = [...this.items.keys()]
107
- const values = []
108
- for (const key of keys) {
109
- const value = this.get(key)
110
- if (value !== undefined) {
111
- values.push(value)
112
- }
113
- }
114
- return values
115
- }
116
- }
@@ -1,84 +0,0 @@
1
- import { DhtAddress } from '@streamr/dht'
2
- import { StreamMessage } from '../../../generated/packages/trackerless-network/protos/NetworkRpc'
3
- import { PropagationTask, PropagationTaskStore } from './PropagationTaskStore'
4
-
5
- type SendToNeighborFn = (neighborId: DhtAddress, msg: StreamMessage) => Promise<void>
6
-
7
- interface ConstructorOptions {
8
- sendToNeighbor: SendToNeighborFn
9
- minPropagationTargets: number
10
- ttl?: number
11
- maxMessages?: number
12
- }
13
-
14
- const DEFAULT_MAX_MESSAGES = 150
15
- const DEFAULT_TTL = 10 * 1000
16
-
17
- /**
18
- * Message propagation logic of a node. Given a message, this class will actively attempt to propagate it to
19
- * `minPropagationTargets` neighbors until success or TTL expiration.
20
- *
21
- * Setting `minPropagationTargets = 0` effectively disables any propagation reattempts. A message will then
22
- * only be propagated exactly once, to neighbors that are present at that moment, in a fire-and-forget manner.
23
- */
24
-
25
- export class Propagation {
26
- private readonly sendToNeighbor: SendToNeighborFn
27
- private readonly minPropagationTargets: number
28
- private readonly activeTaskStore: PropagationTaskStore
29
-
30
- constructor({
31
- sendToNeighbor,
32
- minPropagationTargets,
33
- ttl = DEFAULT_TTL,
34
- maxMessages = DEFAULT_MAX_MESSAGES
35
- }: ConstructorOptions) {
36
- this.sendToNeighbor = sendToNeighbor
37
- this.minPropagationTargets = minPropagationTargets
38
- this.activeTaskStore = new PropagationTaskStore(ttl, maxMessages)
39
- }
40
-
41
- /**
42
- * Node should invoke this when it learns about a new message
43
- */
44
- feedUnseenMessage(message: StreamMessage, targets: DhtAddress[], source: DhtAddress | null): void {
45
- const task = {
46
- message,
47
- source,
48
- handledNeighbors: new Set<DhtAddress>()
49
- }
50
- this.activeTaskStore.add(task)
51
- for (const target of targets) {
52
- this.sendAndAwaitThenMark(task, target)
53
- }
54
- }
55
-
56
- /**
57
- * Node should invoke this when it learns about a new node stream assignment
58
- */
59
- onNeighborJoined(neighborId: DhtAddress): void {
60
- const tasks = this.activeTaskStore.get()
61
- for (const task of tasks) {
62
- this.sendAndAwaitThenMark(task, neighborId)
63
- }
64
- }
65
-
66
- private sendAndAwaitThenMark({ message, source, handledNeighbors }: PropagationTask, neighborId: DhtAddress): void {
67
- if (!handledNeighbors.has(neighborId) && neighborId !== source) {
68
- (async () => {
69
- try {
70
- await this.sendToNeighbor(neighborId, message)
71
- } catch {
72
- return
73
- }
74
- // Side-note: due to asynchronicity, the task being modified at this point could already be stale and
75
- // deleted from `activeTaskStore`. However, as modifying it or re-deleting it is pretty much
76
- // inconsequential at this point, leaving the logic as is.
77
- handledNeighbors.add(neighborId)
78
- if (handledNeighbors.size >= this.minPropagationTargets) {
79
- this.activeTaskStore.delete(message.messageId!)
80
- }
81
- })()
82
- }
83
- }
84
- }
@@ -1,41 +0,0 @@
1
- import { DhtAddress } from '@streamr/dht'
2
- import { MessageRef, StreamMessage } from '../../../generated/packages/trackerless-network/protos/NetworkRpc'
3
- import { FifoMapWithTTL } from './FifoMapWithTTL'
4
-
5
- export interface PropagationTask {
6
- message: StreamMessage
7
- source: string | null
8
- handledNeighbors: Set<DhtAddress>
9
- }
10
-
11
- /**
12
- * Keeps track of propagation tasks for the needs of message propagation logic.
13
- *
14
- * Properties:
15
- * - Allows fetching propagation tasks by StreamPartID
16
- * - Upper bound on number of tasks stored, replacement policy if FIFO
17
- * - Items have a TTL, after which they are considered stale and not returned when querying
18
- **/
19
- export class PropagationTaskStore {
20
- private readonly tasks: FifoMapWithTTL<MessageRef, PropagationTask>
21
-
22
- constructor(ttlInMs: number, maxTasks: number) {
23
- this.tasks = new FifoMapWithTTL<MessageRef, PropagationTask>({
24
- ttlInMs,
25
- maxSize: maxTasks
26
- })
27
- }
28
-
29
- get(): PropagationTask[] {
30
- return this.tasks.values()
31
- }
32
-
33
- add(task: PropagationTask): void {
34
- const messageId = task.message.messageId!
35
- this.tasks.set(messageId, task)
36
- }
37
-
38
- delete(messageId: MessageRef): void {
39
- this.tasks.delete(messageId) // causes `onKeyDropped` to be invoked
40
- }
41
- }