@streamr/trackerless-network 100.2.5-beta.1 → 101.0.0-beta.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.
- package/dist/package.json +6 -6
- package/dist/src/NetworkNode.js +1 -1
- package/dist/src/NetworkNode.js.map +1 -1
- package/dist/src/NetworkStack.d.ts +5 -5
- package/dist/src/NetworkStack.js +21 -21
- package/dist/src/NetworkStack.js.map +1 -1
- package/dist/src/exports.d.ts +2 -2
- package/dist/src/exports.js +2 -2
- package/dist/src/exports.js.map +1 -1
- package/dist/src/logic/ContentDeliveryLayerNode.d.ts +5 -5
- package/dist/src/logic/ContentDeliveryLayerNode.js +85 -85
- package/dist/src/logic/ContentDeliveryLayerNode.js.map +1 -1
- package/dist/src/logic/ContentDeliveryManager.d.ts +11 -12
- package/dist/src/logic/ContentDeliveryManager.js +65 -61
- package/dist/src/logic/ContentDeliveryManager.js.map +1 -1
- package/dist/src/logic/ContentDeliveryRpcLocal.d.ts +5 -5
- package/dist/src/logic/ContentDeliveryRpcLocal.js +9 -9
- package/dist/src/logic/ContentDeliveryRpcLocal.js.map +1 -1
- package/dist/src/logic/{Layer0Node.d.ts → ControlLayerNode.d.ts} +1 -1
- package/dist/src/logic/{Layer0Node.js → ControlLayerNode.js} +1 -1
- package/dist/src/logic/ControlLayerNode.js.map +1 -0
- package/dist/src/logic/{Layer1Node.d.ts → DiscoveryLayerNode.d.ts} +8 -8
- package/dist/src/logic/{Layer1Node.js → DiscoveryLayerNode.js} +1 -1
- package/dist/src/logic/DiscoveryLayerNode.js.map +1 -0
- package/dist/src/logic/PeerDescriptorStoreManager.d.ts +28 -0
- package/dist/src/logic/PeerDescriptorStoreManager.js +79 -0
- package/dist/src/logic/PeerDescriptorStoreManager.js.map +1 -0
- package/dist/src/logic/StreamPartNetworkSplitAvoidance.d.ts +5 -5
- package/dist/src/logic/StreamPartNetworkSplitAvoidance.js +8 -8
- package/dist/src/logic/StreamPartNetworkSplitAvoidance.js.map +1 -1
- package/dist/src/logic/StreamPartReconnect.d.ts +5 -5
- package/dist/src/logic/StreamPartReconnect.js +10 -10
- package/dist/src/logic/StreamPartReconnect.js.map +1 -1
- package/dist/src/logic/createContentDeliveryLayerNode.d.ts +3 -3
- package/dist/src/logic/createContentDeliveryLayerNode.js +34 -34
- package/dist/src/logic/createContentDeliveryLayerNode.js.map +1 -1
- package/dist/src/logic/inspect/InspectSession.d.ts +3 -3
- package/dist/src/logic/inspect/InspectSession.js +5 -5
- package/dist/src/logic/inspect/InspectSession.js.map +1 -1
- package/dist/src/logic/inspect/Inspector.d.ts +2 -2
- package/dist/src/logic/inspect/Inspector.js +8 -8
- package/dist/src/logic/inspect/Inspector.js.map +1 -1
- package/dist/src/logic/neighbor-discovery/HandshakeRpcLocal.d.ts +4 -4
- package/dist/src/logic/neighbor-discovery/HandshakeRpcLocal.js +24 -24
- package/dist/src/logic/neighbor-discovery/HandshakeRpcLocal.js.map +1 -1
- package/dist/src/logic/neighbor-discovery/HandshakeRpcRemote.d.ts +1 -1
- package/dist/src/logic/neighbor-discovery/HandshakeRpcRemote.js +4 -4
- package/dist/src/logic/neighbor-discovery/HandshakeRpcRemote.js.map +1 -1
- package/dist/src/logic/neighbor-discovery/Handshaker.d.ts +3 -3
- package/dist/src/logic/neighbor-discovery/Handshaker.js +37 -37
- package/dist/src/logic/neighbor-discovery/Handshaker.js.map +1 -1
- package/dist/src/logic/neighbor-discovery/NeighborFinder.d.ts +3 -3
- package/dist/src/logic/neighbor-discovery/NeighborFinder.js +9 -9
- package/dist/src/logic/neighbor-discovery/NeighborFinder.js.map +1 -1
- package/dist/src/logic/neighbor-discovery/NeighborUpdateManager.d.ts +3 -3
- package/dist/src/logic/neighbor-discovery/NeighborUpdateManager.js +12 -12
- package/dist/src/logic/neighbor-discovery/NeighborUpdateManager.js.map +1 -1
- package/dist/src/logic/neighbor-discovery/NeighborUpdateRpcLocal.d.ts +3 -3
- package/dist/src/logic/neighbor-discovery/NeighborUpdateRpcLocal.js +14 -14
- package/dist/src/logic/neighbor-discovery/NeighborUpdateRpcLocal.js.map +1 -1
- package/dist/src/logic/proxy/ProxyClient.d.ts +3 -3
- package/dist/src/logic/proxy/ProxyClient.js +25 -25
- package/dist/src/logic/proxy/ProxyClient.js.map +1 -1
- package/dist/src/logic/proxy/ProxyConnectionRpcLocal.d.ts +3 -3
- package/dist/src/logic/proxy/ProxyConnectionRpcLocal.js +10 -10
- package/dist/src/logic/proxy/ProxyConnectionRpcLocal.js.map +1 -1
- package/dist/src/logic/temporary-connection/TemporaryConnectionRpcLocal.d.ts +3 -3
- package/dist/src/logic/temporary-connection/TemporaryConnectionRpcLocal.js +11 -11
- package/dist/src/logic/temporary-connection/TemporaryConnectionRpcLocal.js.map +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.d.ts +4 -4
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.js +8 -8
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.js.map +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +11 -3
- package/dist/src/proto/packages/dht/protos/DhtRpc.js +7 -5
- package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.server.d.ts +2 -2
- package/dist/src/proto/packages/proto-rpc/protos/ProtoRpc.js +1 -1
- package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.client.js +1 -1
- package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.d.ts +6 -23
- package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.js +5 -23
- package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.js.map +1 -1
- package/dist/test/benchmark/first-message.js +7 -7
- package/dist/test/benchmark/first-message.js.map +1 -1
- package/dist/test/utils/utils.d.ts +2 -2
- package/dist/test/utils/utils.js +3 -3
- package/dist/test/utils/utils.js.map +1 -1
- package/package.json +6 -6
- package/protos/NetworkRpc.proto +3 -9
- package/src/NetworkNode.ts +1 -1
- package/src/NetworkStack.ts +24 -24
- package/src/exports.ts +2 -2
- package/src/logic/ContentDeliveryLayerNode.ts +112 -112
- package/src/logic/ContentDeliveryManager.ts +71 -67
- package/src/logic/ContentDeliveryRpcLocal.ts +12 -12
- package/src/logic/{Layer0Node.ts → ControlLayerNode.ts} +1 -1
- package/src/logic/{Layer1Node.ts → DiscoveryLayerNode.ts} +8 -8
- package/src/logic/PeerDescriptorStoreManager.ts +97 -0
- package/src/logic/StreamPartNetworkSplitAvoidance.ts +11 -11
- package/src/logic/StreamPartReconnect.ts +12 -12
- package/src/logic/createContentDeliveryLayerNode.ts +38 -38
- package/src/logic/inspect/InspectSession.ts +6 -6
- package/src/logic/inspect/Inspector.ts +9 -9
- package/src/logic/neighbor-discovery/HandshakeRpcLocal.ts +26 -26
- package/src/logic/neighbor-discovery/HandshakeRpcRemote.ts +6 -6
- package/src/logic/neighbor-discovery/Handshaker.ts +45 -45
- package/src/logic/neighbor-discovery/NeighborFinder.ts +10 -10
- package/src/logic/neighbor-discovery/NeighborUpdateManager.ts +14 -14
- package/src/logic/neighbor-discovery/NeighborUpdateRpcLocal.ts +17 -17
- package/src/logic/proxy/ProxyClient.ts +26 -26
- package/src/logic/proxy/ProxyConnectionRpcLocal.ts +12 -12
- package/src/logic/temporary-connection/TemporaryConnectionRpcLocal.ts +13 -13
- package/src/proto/google/protobuf/any.ts +1 -1
- package/src/proto/google/protobuf/empty.ts +1 -1
- package/src/proto/google/protobuf/timestamp.ts +1 -1
- package/src/proto/packages/dht/protos/DhtRpc.client.ts +9 -9
- package/src/proto/packages/dht/protos/DhtRpc.server.ts +3 -3
- package/src/proto/packages/dht/protos/DhtRpc.ts +15 -5
- package/src/proto/packages/proto-rpc/protos/ProtoRpc.ts +1 -1
- package/src/proto/packages/trackerless-network/protos/NetworkRpc.client.ts +1 -1
- package/src/proto/packages/trackerless-network/protos/NetworkRpc.server.ts +1 -1
- package/src/proto/packages/trackerless-network/protos/NetworkRpc.ts +10 -27
- package/test/benchmark/StreamPartIdDataKeyDistribution.test.ts +1 -1
- package/test/benchmark/first-message.ts +9 -9
- package/test/end-to-end/content-delivery-layer-node-with-real-connections.test.ts +12 -12
- package/test/end-to-end/proxy-and-full-node.test.ts +4 -4
- package/test/integration/ContentDeliveryLayerNode-Layer1Node-Latencies.test.ts +19 -19
- package/test/integration/ContentDeliveryLayerNode-Layer1Node.test.ts +19 -19
- package/test/integration/ContentDeliveryManager.test.ts +11 -11
- package/test/integration/Inspect.test.ts +1 -1
- package/test/integration/Propagation.test.ts +6 -6
- package/test/integration/joining-streams-on-offline-peers.test.ts +3 -3
- package/test/integration/stream-without-default-entrypoints.test.ts +2 -2
- package/test/integration/streamEntryPointReplacing.test.ts +2 -2
- package/test/unit/ContentDeliveryLayerNode.test.ts +11 -11
- package/test/unit/ContentDeliveryManager.test.ts +2 -2
- package/test/unit/{EntrypointDiscovery.test.ts → PeerDescriptorStoreManager.test.ts} +28 -29
- package/test/unit/StreamPartIDDataKey.test.ts +1 -1
- package/test/unit/StreamPartNetworkSplitAvoidance.test.ts +8 -8
- package/test/unit/StreamPartReconnect.test.ts +9 -9
- package/test/utils/fake/FakePeerDescriptorStoreManager.ts +29 -0
- package/test/utils/mock/{MockLayer0Node.ts → MockControlLayerNode.ts} +2 -2
- package/test/utils/mock/{MockLayer1Node.ts → MockDiscoveryLayerNode.ts} +2 -2
- package/test/utils/utils.ts +5 -5
- package/dist/src/logic/EntryPointDiscovery.d.ts +0 -27
- package/dist/src/logic/EntryPointDiscovery.js +0 -80
- package/dist/src/logic/EntryPointDiscovery.js.map +0 -1
- package/dist/src/logic/Layer0Node.js.map +0 -1
- package/dist/src/logic/Layer1Node.js.map +0 -1
- package/src/logic/EntryPointDiscovery.ts +0 -100
- package/test/utils/fake/FakeEntryPointDiscovery.ts +0 -29
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
EXISTING_CONNECTION_TIMEOUT,
|
|
6
6
|
ITransport,
|
|
7
7
|
PeerDescriptor,
|
|
8
|
+
getDhtAddressFromRaw,
|
|
8
9
|
getNodeIdFromPeerDescriptor
|
|
9
10
|
} from '@streamr/dht'
|
|
10
11
|
import { StreamID, StreamPartID, StreamPartIDUtils, toStreamPartID } from '@streamr/protocol'
|
|
@@ -16,26 +17,26 @@ import {
|
|
|
16
17
|
MetricsDefinition,
|
|
17
18
|
RateMetric
|
|
18
19
|
} from '@streamr/utils'
|
|
20
|
+
import { createHash } from 'crypto'
|
|
19
21
|
import { EventEmitter } from 'eventemitter3'
|
|
20
22
|
import { sampleSize } from 'lodash'
|
|
21
23
|
import { ProxyDirection, StreamMessage, StreamPartitionInfo } from '../proto/packages/trackerless-network/protos/NetworkRpc'
|
|
22
|
-
import { ENTRYPOINT_STORE_LIMIT, EntryPointDiscovery } from './EntryPointDiscovery'
|
|
23
|
-
import { Layer0Node } from './Layer0Node'
|
|
24
|
-
import { Layer1Node } from './Layer1Node'
|
|
25
24
|
import { ContentDeliveryLayerNode } from './ContentDeliveryLayerNode'
|
|
25
|
+
import { ControlLayerNode } from './ControlLayerNode'
|
|
26
|
+
import { DiscoveryLayerNode } from './DiscoveryLayerNode'
|
|
27
|
+
import { MAX_NODE_COUNT, PeerDescriptorStoreManager } from './PeerDescriptorStoreManager'
|
|
28
|
+
import { MIN_NEIGHBOR_COUNT as NETWORK_SPLIT_AVOIDANCE_MIN_NEIGHBOR_COUNT, StreamPartNetworkSplitAvoidance } from './StreamPartNetworkSplitAvoidance'
|
|
29
|
+
import { StreamPartReconnect } from './StreamPartReconnect'
|
|
26
30
|
import { createContentDeliveryLayerNode } from './createContentDeliveryLayerNode'
|
|
27
31
|
import { ProxyClient } from './proxy/ProxyClient'
|
|
28
|
-
import { StreamPartReconnect } from './StreamPartReconnect'
|
|
29
|
-
import { MIN_NEIGHBOR_COUNT as NETWORK_SPLIT_AVOIDANCE_MIN_NEIGHBOR_COUNT, StreamPartNetworkSplitAvoidance } from './StreamPartNetworkSplitAvoidance'
|
|
30
32
|
|
|
31
33
|
export type StreamPartDelivery = {
|
|
32
34
|
broadcast: (msg: StreamMessage) => void
|
|
33
35
|
stop: () => Promise<void>
|
|
34
36
|
} & ({
|
|
35
37
|
proxied: false
|
|
36
|
-
|
|
38
|
+
discoveryLayerNode: DiscoveryLayerNode
|
|
37
39
|
node: ContentDeliveryLayerNode
|
|
38
|
-
entryPointDiscovery: EntryPointDiscovery
|
|
39
40
|
networkSplitAvoidance: StreamPartNetworkSplitAvoidance
|
|
40
41
|
} | {
|
|
41
42
|
proxied: true
|
|
@@ -53,7 +54,7 @@ interface Metrics extends MetricsDefinition {
|
|
|
53
54
|
broadcastBytesPerSecond: Metric
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
export interface
|
|
57
|
+
export interface ContentDeliveryManagerOptions {
|
|
57
58
|
metricsContext?: MetricsContext
|
|
58
59
|
streamPartitionNeighborTargetCount?: number
|
|
59
60
|
streamPartitionMinPropagationTargets?: number
|
|
@@ -61,24 +62,28 @@ export interface ContentDeliveryManagerConfig {
|
|
|
61
62
|
rpcRequestTimeout?: number
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
export const streamPartIdToDataKey = (streamPartId: StreamPartID): DhtAddress => {
|
|
66
|
+
return getDhtAddressFromRaw(new Uint8Array((createHash('sha1').update(streamPartId).digest())))
|
|
67
|
+
}
|
|
68
|
+
|
|
64
69
|
export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
65
70
|
|
|
66
71
|
private transport?: ITransport
|
|
67
72
|
private connectionLocker?: ConnectionLocker
|
|
68
|
-
private
|
|
73
|
+
private controlLayerNode?: ControlLayerNode
|
|
69
74
|
private readonly metricsContext: MetricsContext
|
|
70
75
|
private readonly metrics: Metrics
|
|
71
|
-
private readonly
|
|
76
|
+
private readonly options: ContentDeliveryManagerOptions
|
|
72
77
|
private readonly streamParts: Map<StreamPartID, StreamPartDelivery>
|
|
73
78
|
private readonly knownStreamPartEntryPoints: Map<StreamPartID, PeerDescriptor[]> = new Map()
|
|
74
79
|
private started = false
|
|
75
80
|
private destroyed = false
|
|
76
81
|
|
|
77
|
-
constructor(
|
|
82
|
+
constructor(options: ContentDeliveryManagerOptions) {
|
|
78
83
|
super()
|
|
79
|
-
this.
|
|
84
|
+
this.options = options
|
|
80
85
|
this.streamParts = new Map()
|
|
81
|
-
this.metricsContext =
|
|
86
|
+
this.metricsContext = options.metricsContext ?? new MetricsContext()
|
|
82
87
|
this.metrics = {
|
|
83
88
|
broadcastMessagesPerSecond: new RateMetric(),
|
|
84
89
|
broadcastBytesPerSecond: new RateMetric()
|
|
@@ -86,12 +91,12 @@ export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
|
86
91
|
this.metricsContext.addMetrics('node', this.metrics)
|
|
87
92
|
}
|
|
88
93
|
|
|
89
|
-
async start(
|
|
94
|
+
async start(startedAndJoinedControlLayerNode: ControlLayerNode, transport: ITransport, connectionLocker: ConnectionLocker): Promise<void> {
|
|
90
95
|
if (this.started || this.destroyed) {
|
|
91
96
|
return
|
|
92
97
|
}
|
|
93
98
|
this.started = true
|
|
94
|
-
this.
|
|
99
|
+
this.controlLayerNode = startedAndJoinedControlLayerNode
|
|
95
100
|
this.transport = transport
|
|
96
101
|
this.connectionLocker = connectionLocker
|
|
97
102
|
}
|
|
@@ -105,7 +110,7 @@ export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
|
105
110
|
await Promise.all(Array.from(this.streamParts.values()).map((streamPart) => streamPart.stop()))
|
|
106
111
|
this.streamParts.clear()
|
|
107
112
|
this.removeAllListeners()
|
|
108
|
-
this.
|
|
113
|
+
this.controlLayerNode = undefined
|
|
109
114
|
this.transport = undefined
|
|
110
115
|
this.connectionLocker = undefined
|
|
111
116
|
}
|
|
@@ -135,37 +140,36 @@ export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
|
135
140
|
return
|
|
136
141
|
}
|
|
137
142
|
logger.debug(`Join stream part ${streamPartId}`)
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
-
streamPartId,
|
|
143
|
+
const discoveryLayerNode = this.createDiscoveryLayerNode(streamPartId, this.knownStreamPartEntryPoints.get(streamPartId) ?? [])
|
|
144
|
+
const peerDescriptorStoreManager = new PeerDescriptorStoreManager({
|
|
145
|
+
key: streamPartIdToDataKey(streamPartId),
|
|
141
146
|
localPeerDescriptor: this.getPeerDescriptor(),
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
147
|
+
fetchDataFromDht: (key) => this.controlLayerNode!.fetchDataFromDht(key),
|
|
148
|
+
storeDataToDht: (key, data) => this.controlLayerNode!.storeDataToDht(key, data),
|
|
149
|
+
deleteDataFromDht: async (key, waitForCompletion) => this.controlLayerNode!.deleteDataFromDht(key, waitForCompletion)
|
|
145
150
|
})
|
|
146
151
|
const networkSplitAvoidance = new StreamPartNetworkSplitAvoidance({
|
|
147
|
-
|
|
148
|
-
discoverEntryPoints: async () =>
|
|
152
|
+
discoveryLayerNode,
|
|
153
|
+
discoverEntryPoints: async () => peerDescriptorStoreManager.fetchNodes()
|
|
149
154
|
})
|
|
150
155
|
const node = this.createContentDeliveryLayerNode(
|
|
151
156
|
streamPartId,
|
|
152
|
-
|
|
153
|
-
() =>
|
|
157
|
+
discoveryLayerNode,
|
|
158
|
+
() => peerDescriptorStoreManager.isLocalNodeStored()
|
|
154
159
|
)
|
|
155
|
-
const streamPartReconnect = new StreamPartReconnect(
|
|
160
|
+
const streamPartReconnect = new StreamPartReconnect(discoveryLayerNode, peerDescriptorStoreManager)
|
|
156
161
|
streamPart = {
|
|
157
162
|
proxied: false,
|
|
158
|
-
|
|
163
|
+
discoveryLayerNode,
|
|
159
164
|
node,
|
|
160
|
-
entryPointDiscovery,
|
|
161
165
|
networkSplitAvoidance,
|
|
162
166
|
broadcast: (msg: StreamMessage) => node.broadcast(msg),
|
|
163
167
|
stop: async () => {
|
|
164
168
|
streamPartReconnect.destroy()
|
|
165
169
|
networkSplitAvoidance.destroy()
|
|
166
|
-
await
|
|
170
|
+
await peerDescriptorStoreManager.destroy()
|
|
167
171
|
node.stop()
|
|
168
|
-
await
|
|
172
|
+
await discoveryLayerNode.stop()
|
|
169
173
|
}
|
|
170
174
|
}
|
|
171
175
|
this.streamParts.set(streamPartId, streamPart)
|
|
@@ -173,15 +177,15 @@ export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
|
173
177
|
this.emit('newMessage', message)
|
|
174
178
|
})
|
|
175
179
|
const handleEntryPointLeave = async () => {
|
|
176
|
-
if (this.destroyed ||
|
|
180
|
+
if (this.destroyed || peerDescriptorStoreManager.isLocalNodeStored() || this.knownStreamPartEntryPoints.has(streamPartId)) {
|
|
177
181
|
return
|
|
178
182
|
}
|
|
179
|
-
const entryPoints = await
|
|
180
|
-
if (entryPoints.length <
|
|
181
|
-
await
|
|
183
|
+
const entryPoints = await peerDescriptorStoreManager.fetchNodes()
|
|
184
|
+
if (entryPoints.length < MAX_NODE_COUNT) {
|
|
185
|
+
await peerDescriptorStoreManager.storeAndKeepLocalNode()
|
|
182
186
|
}
|
|
183
187
|
}
|
|
184
|
-
|
|
188
|
+
discoveryLayerNode.on('manualRejoinRequired', async () => {
|
|
185
189
|
if (!streamPartReconnect.isRunning() && !networkSplitAvoidance.isRunning()) {
|
|
186
190
|
logger.debug('Manual rejoin required for stream part', { streamPartId })
|
|
187
191
|
await streamPartReconnect.reconnect()
|
|
@@ -190,53 +194,53 @@ export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
|
190
194
|
node.on('entryPointLeaveDetected', () => handleEntryPointLeave())
|
|
191
195
|
setImmediate(async () => {
|
|
192
196
|
try {
|
|
193
|
-
await this.startLayersAndJoinDht(streamPartId,
|
|
197
|
+
await this.startLayersAndJoinDht(streamPartId, peerDescriptorStoreManager)
|
|
194
198
|
} catch (err) {
|
|
195
199
|
logger.warn(`Failed to join to stream part ${streamPartId}`, { err })
|
|
196
200
|
}
|
|
197
201
|
})
|
|
198
202
|
}
|
|
199
203
|
|
|
200
|
-
private async startLayersAndJoinDht(streamPartId: StreamPartID,
|
|
204
|
+
private async startLayersAndJoinDht(streamPartId: StreamPartID, peerDescriptorStoreManager: PeerDescriptorStoreManager): Promise<void> {
|
|
201
205
|
logger.debug(`Start layers and join DHT for stream part ${streamPartId}`)
|
|
202
206
|
const streamPart = this.streamParts.get(streamPartId)
|
|
203
207
|
if ((streamPart === undefined) || streamPart.proxied) {
|
|
204
208
|
// leaveStreamPart has been called (or leaveStreamPart called, and then setProxies called)
|
|
205
209
|
return
|
|
206
210
|
}
|
|
207
|
-
await streamPart.
|
|
211
|
+
await streamPart.discoveryLayerNode.start()
|
|
208
212
|
await streamPart.node.start()
|
|
209
213
|
const knownEntryPoints = this.knownStreamPartEntryPoints.get(streamPartId)
|
|
210
214
|
if (knownEntryPoints !== undefined) {
|
|
211
215
|
await Promise.all([
|
|
212
|
-
streamPart.
|
|
213
|
-
streamPart.
|
|
216
|
+
streamPart.discoveryLayerNode.joinDht(knownEntryPoints),
|
|
217
|
+
streamPart.discoveryLayerNode.joinRing()
|
|
214
218
|
])
|
|
215
219
|
} else {
|
|
216
|
-
const entryPoints = await
|
|
220
|
+
const entryPoints = await peerDescriptorStoreManager.fetchNodes()
|
|
217
221
|
await Promise.all([
|
|
218
|
-
streamPart.
|
|
219
|
-
streamPart.
|
|
222
|
+
streamPart.discoveryLayerNode.joinDht(sampleSize(entryPoints, NETWORK_SPLIT_AVOIDANCE_MIN_NEIGHBOR_COUNT)),
|
|
223
|
+
streamPart.discoveryLayerNode.joinRing()
|
|
220
224
|
])
|
|
221
|
-
if (entryPoints.length <
|
|
222
|
-
await
|
|
223
|
-
if (streamPart.
|
|
225
|
+
if (entryPoints.length < MAX_NODE_COUNT) {
|
|
226
|
+
await peerDescriptorStoreManager.storeAndKeepLocalNode()
|
|
227
|
+
if (streamPart.discoveryLayerNode.getNeighborCount() < NETWORK_SPLIT_AVOIDANCE_MIN_NEIGHBOR_COUNT) {
|
|
224
228
|
setImmediate(() => streamPart.networkSplitAvoidance.avoidNetworkSplit())
|
|
225
229
|
}
|
|
226
230
|
}
|
|
227
231
|
}
|
|
228
232
|
}
|
|
229
233
|
|
|
230
|
-
private
|
|
234
|
+
private createDiscoveryLayerNode(streamPartId: StreamPartID, entryPoints: PeerDescriptor[]): DiscoveryLayerNode {
|
|
231
235
|
return new DhtNode({
|
|
232
|
-
transport: this.
|
|
233
|
-
connectionsView: this.
|
|
236
|
+
transport: this.controlLayerNode!,
|
|
237
|
+
connectionsView: this.controlLayerNode!.getConnectionsView(),
|
|
234
238
|
serviceId: 'layer1::' + streamPartId,
|
|
235
|
-
peerDescriptor: this.
|
|
239
|
+
peerDescriptor: this.controlLayerNode!.getLocalPeerDescriptor(),
|
|
236
240
|
entryPoints,
|
|
237
|
-
numberOfNodesPerKBucket: 4, // TODO use
|
|
241
|
+
numberOfNodesPerKBucket: 4, // TODO use options option or named constant?
|
|
238
242
|
rpcRequestTimeout: EXISTING_CONNECTION_TIMEOUT,
|
|
239
|
-
dhtJoinTimeout: 20000, // TODO use
|
|
243
|
+
dhtJoinTimeout: 20000, // TODO use options option or named constant?
|
|
240
244
|
periodicallyPingNeighbors: true,
|
|
241
245
|
periodicallyPingRingContacts: true
|
|
242
246
|
})
|
|
@@ -244,19 +248,19 @@ export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
|
244
248
|
|
|
245
249
|
private createContentDeliveryLayerNode(
|
|
246
250
|
streamPartId: StreamPartID,
|
|
247
|
-
|
|
251
|
+
discoveryLayerNode: DiscoveryLayerNode,
|
|
248
252
|
isLocalNodeEntryPoint: () => boolean
|
|
249
253
|
) {
|
|
250
254
|
return createContentDeliveryLayerNode({
|
|
251
255
|
streamPartId,
|
|
252
256
|
transport: this.transport!,
|
|
253
|
-
|
|
257
|
+
discoveryLayerNode,
|
|
254
258
|
connectionLocker: this.connectionLocker!,
|
|
255
|
-
localPeerDescriptor: this.
|
|
256
|
-
minPropagationTargets: this.
|
|
257
|
-
neighborTargetCount: this.
|
|
258
|
-
acceptProxyConnections: this.
|
|
259
|
-
rpcRequestTimeout: this.
|
|
259
|
+
localPeerDescriptor: this.controlLayerNode!.getLocalPeerDescriptor(),
|
|
260
|
+
minPropagationTargets: this.options.streamPartitionMinPropagationTargets,
|
|
261
|
+
neighborTargetCount: this.options.streamPartitionNeighborTargetCount,
|
|
262
|
+
acceptProxyConnections: this.options.acceptProxyConnections,
|
|
263
|
+
rpcRequestTimeout: this.options.rpcRequestTimeout,
|
|
260
264
|
isLocalNodeEntryPoint
|
|
261
265
|
})
|
|
262
266
|
}
|
|
@@ -269,7 +273,7 @@ export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
|
269
273
|
connectionCount?: number
|
|
270
274
|
): Promise<void> {
|
|
271
275
|
// TODO explicit default value for "acceptProxyConnections" or make it required
|
|
272
|
-
if (this.
|
|
276
|
+
if (this.options.acceptProxyConnections) {
|
|
273
277
|
throw new Error('cannot set proxies when acceptProxyConnections=true')
|
|
274
278
|
}
|
|
275
279
|
const enable = (nodes.length > 0) && ((connectionCount === undefined) || (connectionCount > 0))
|
|
@@ -301,10 +305,10 @@ export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
|
301
305
|
private createProxyClient(streamPartId: StreamPartID): ProxyClient {
|
|
302
306
|
return new ProxyClient({
|
|
303
307
|
transport: this.transport!,
|
|
304
|
-
localPeerDescriptor: this.
|
|
308
|
+
localPeerDescriptor: this.controlLayerNode!.getLocalPeerDescriptor(),
|
|
305
309
|
streamPartId,
|
|
306
310
|
connectionLocker: this.connectionLocker!,
|
|
307
|
-
minPropagationTargets: this.
|
|
311
|
+
minPropagationTargets: this.options.streamPartitionMinPropagationTargets
|
|
308
312
|
})
|
|
309
313
|
}
|
|
310
314
|
|
|
@@ -320,10 +324,10 @@ export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
|
320
324
|
getNodeInfo(): StreamPartitionInfo[] {
|
|
321
325
|
const streamParts = Array.from(this.streamParts.entries()).filter(([_, node]) => node.proxied === false)
|
|
322
326
|
return streamParts.map(([streamPartId]) => {
|
|
323
|
-
const stream = this.streamParts.get(streamPartId)! as { node: ContentDeliveryLayerNode,
|
|
327
|
+
const stream = this.streamParts.get(streamPartId)! as { node: ContentDeliveryLayerNode, discoveryLayerNode: DiscoveryLayerNode }
|
|
324
328
|
return {
|
|
325
329
|
id: streamPartId,
|
|
326
|
-
controlLayerNeighbors: stream.
|
|
330
|
+
controlLayerNeighbors: stream.discoveryLayerNode.getNeighbors(),
|
|
327
331
|
contentDeliveryLayerNeighbors: stream.node.getNeighbors()
|
|
328
332
|
}
|
|
329
333
|
})
|
|
@@ -350,11 +354,11 @@ export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
|
350
354
|
}
|
|
351
355
|
|
|
352
356
|
getPeerDescriptor(): PeerDescriptor {
|
|
353
|
-
return this.
|
|
357
|
+
return this.controlLayerNode!.getLocalPeerDescriptor()
|
|
354
358
|
}
|
|
355
359
|
|
|
356
360
|
getNodeId(): DhtAddress {
|
|
357
|
-
return getNodeIdFromPeerDescriptor(this.
|
|
361
|
+
return getNodeIdFromPeerDescriptor(this.controlLayerNode!.getLocalPeerDescriptor())
|
|
358
362
|
}
|
|
359
363
|
|
|
360
364
|
getNeighbors(streamPartId: StreamPartID): DhtAddress[] {
|
|
@@ -10,38 +10,38 @@ import { IContentDeliveryRpc } from '../proto/packages/trackerless-network/proto
|
|
|
10
10
|
import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
|
|
11
11
|
import { StreamPartID } from '@streamr/protocol'
|
|
12
12
|
|
|
13
|
-
export interface
|
|
13
|
+
export interface ContentDeliveryRpcLocalOptions {
|
|
14
14
|
localPeerDescriptor: PeerDescriptor
|
|
15
15
|
streamPartId: StreamPartID
|
|
16
16
|
markAndCheckDuplicate: (messageId: MessageID, previousMessageRef?: MessageRef) => boolean
|
|
17
17
|
broadcast: (message: StreamMessage, previousNode?: DhtAddress) => void
|
|
18
|
-
onLeaveNotice(
|
|
19
|
-
markForInspection(
|
|
18
|
+
onLeaveNotice(remoteNodeId: DhtAddress, isLocalNodeEntryPoint: boolean): void
|
|
19
|
+
markForInspection(remoteNodeId: DhtAddress, messageId: MessageID): void
|
|
20
20
|
rpcCommunicator: ListeningRpcCommunicator
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export class ContentDeliveryRpcLocal implements IContentDeliveryRpc {
|
|
24
24
|
|
|
25
|
-
private readonly
|
|
25
|
+
private readonly options: ContentDeliveryRpcLocalOptions
|
|
26
26
|
|
|
27
|
-
constructor(
|
|
28
|
-
this.
|
|
27
|
+
constructor(options: ContentDeliveryRpcLocalOptions) {
|
|
28
|
+
this.options = options
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
async sendStreamMessage(message: StreamMessage, context: ServerCallContext): Promise<Empty> {
|
|
32
32
|
const previousNode = getNodeIdFromPeerDescriptor((context as DhtCallContext).incomingSourceDescriptor!)
|
|
33
|
-
this.
|
|
34
|
-
if (this.
|
|
35
|
-
this.
|
|
33
|
+
this.options.markForInspection(previousNode, message.messageId!)
|
|
34
|
+
if (this.options.markAndCheckDuplicate(message.messageId!, message.previousMessageRef)) {
|
|
35
|
+
this.options.broadcast(message, previousNode)
|
|
36
36
|
}
|
|
37
37
|
return Empty
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
async leaveStreamPartNotice(message: LeaveStreamPartNotice, context: ServerCallContext): Promise<Empty> {
|
|
41
|
-
if (message.streamPartId === this.
|
|
41
|
+
if (message.streamPartId === this.options.streamPartId) {
|
|
42
42
|
const sourcePeerDescriptor = (context as DhtCallContext).incomingSourceDescriptor!
|
|
43
|
-
const
|
|
44
|
-
this.
|
|
43
|
+
const remoteNodeId = getNodeIdFromPeerDescriptor(sourcePeerDescriptor)
|
|
44
|
+
this.options.onLeaveNotice(remoteNodeId, message.isEntryPoint)
|
|
45
45
|
}
|
|
46
46
|
return Empty
|
|
47
47
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ConnectionsView, DataEntry, DhtAddress, ITransport, PeerDescriptor } from '@streamr/dht'
|
|
2
2
|
import { Any } from '../proto/google/protobuf/any'
|
|
3
3
|
|
|
4
|
-
export interface
|
|
4
|
+
export interface ControlLayerNode extends ITransport {
|
|
5
5
|
joinDht(entryPointDescriptors: PeerDescriptor[]): Promise<void>
|
|
6
6
|
hasJoined(): boolean
|
|
7
7
|
getLocalPeerDescriptor(): PeerDescriptor
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DhtAddress, PeerDescriptor, RingContacts } from '@streamr/dht'
|
|
2
2
|
|
|
3
|
-
export interface
|
|
3
|
+
export interface DiscoveryLayerNodeEvents {
|
|
4
4
|
manualRejoinRequired: () => void
|
|
5
5
|
nearbyContactAdded: (peerDescriptor: PeerDescriptor) => void
|
|
6
6
|
nearbyContactRemoved: (peerDescriptor: PeerDescriptor) => void
|
|
@@ -10,13 +10,13 @@ export interface Layer1NodeEvents {
|
|
|
10
10
|
ringContactRemoved: (peerDescriptor: PeerDescriptor) => void
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export interface
|
|
14
|
-
on<T extends keyof
|
|
15
|
-
once<T extends keyof
|
|
16
|
-
off<T extends keyof
|
|
17
|
-
on<T extends keyof
|
|
18
|
-
once<T extends keyof
|
|
19
|
-
off<T extends keyof
|
|
13
|
+
export interface DiscoveryLayerNode {
|
|
14
|
+
on<T extends keyof DiscoveryLayerNodeEvents>(eventName: T, listener: (peerDescriptor: PeerDescriptor) => void): void
|
|
15
|
+
once<T extends keyof DiscoveryLayerNodeEvents>(eventName: T, listener: (peerDescriptor: PeerDescriptor) => void): void
|
|
16
|
+
off<T extends keyof DiscoveryLayerNodeEvents>(eventName: T, listener: (peerDescriptor: PeerDescriptor) => void): void
|
|
17
|
+
on<T extends keyof DiscoveryLayerNodeEvents>(eventName: T, listener: () => void): void
|
|
18
|
+
once<T extends keyof DiscoveryLayerNodeEvents>(eventName: T, listener: () => void): void
|
|
19
|
+
off<T extends keyof DiscoveryLayerNodeEvents>(eventName: T, listener: () => void): void
|
|
20
20
|
removeContact: (nodeId: DhtAddress) => void
|
|
21
21
|
getClosestContacts: (maxCount?: number) => PeerDescriptor[]
|
|
22
22
|
getRandomContacts: (maxCount?: number) => PeerDescriptor[]
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DataEntry,
|
|
3
|
+
DhtAddress,
|
|
4
|
+
PeerDescriptor,
|
|
5
|
+
areEqualPeerDescriptors
|
|
6
|
+
} from '@streamr/dht'
|
|
7
|
+
import { Logger, scheduleAtInterval } from '@streamr/utils'
|
|
8
|
+
import { Any } from '../proto/google/protobuf/any'
|
|
9
|
+
|
|
10
|
+
const parsePeerDescriptor = (dataEntries: DataEntry[]): PeerDescriptor[] => {
|
|
11
|
+
return dataEntries.filter((entry) => !entry.deleted).map((entry) => Any.unpack(entry.data!, PeerDescriptor))
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const logger = new Logger(module)
|
|
15
|
+
|
|
16
|
+
export const MAX_NODE_COUNT = 8
|
|
17
|
+
|
|
18
|
+
interface PeerDescriptorStoreManagerOptions {
|
|
19
|
+
key: DhtAddress
|
|
20
|
+
localPeerDescriptor: PeerDescriptor
|
|
21
|
+
storeInterval?: number
|
|
22
|
+
fetchDataFromDht: (key: DhtAddress) => Promise<DataEntry[]>
|
|
23
|
+
storeDataToDht: (key: DhtAddress, data: Any) => Promise<PeerDescriptor[]>
|
|
24
|
+
deleteDataFromDht: (key: DhtAddress, waitForCompletion: boolean) => Promise<void>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* For each key there is usually 0-MAX_NODE_COUNT PeerDescriptors stored in the DHT. If there are fewer node,
|
|
29
|
+
* the peer descriptor of the local node is stored to the DHT.
|
|
30
|
+
*/
|
|
31
|
+
export class PeerDescriptorStoreManager {
|
|
32
|
+
|
|
33
|
+
private readonly abortController: AbortController
|
|
34
|
+
private readonly options: PeerDescriptorStoreManagerOptions
|
|
35
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
36
|
+
private isLocalNodeStored_ = false
|
|
37
|
+
|
|
38
|
+
constructor(options: PeerDescriptorStoreManagerOptions) {
|
|
39
|
+
this.options = options
|
|
40
|
+
this.abortController = new AbortController()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async fetchNodes(): Promise<PeerDescriptor[]> {
|
|
44
|
+
logger.trace('Fetch data', { key: this.options.key })
|
|
45
|
+
try {
|
|
46
|
+
const result = await this.options.fetchDataFromDht(this.options.key)
|
|
47
|
+
return parsePeerDescriptor(result)
|
|
48
|
+
} catch (err) {
|
|
49
|
+
return []
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async storeAndKeepLocalNode(): Promise<void> {
|
|
54
|
+
if (this.abortController.signal.aborted) {
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
58
|
+
this.isLocalNodeStored_ = true
|
|
59
|
+
await this.storeLocalNode()
|
|
60
|
+
await this.keepLocalNode()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private async storeLocalNode(): Promise<void> {
|
|
64
|
+
const localPeerDescriptor = this.options.localPeerDescriptor
|
|
65
|
+
const dataToStore = Any.pack(localPeerDescriptor, PeerDescriptor)
|
|
66
|
+
try {
|
|
67
|
+
await this.options.storeDataToDht(this.options.key, dataToStore)
|
|
68
|
+
} catch (err) {
|
|
69
|
+
logger.warn('Failed to store local node', { key: this.options.key })
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private async keepLocalNode(): Promise<void> {
|
|
74
|
+
await scheduleAtInterval(async () => {
|
|
75
|
+
logger.trace('Attempting to keep local node', { key: this.options.key })
|
|
76
|
+
try {
|
|
77
|
+
const discovered = await this.fetchNodes()
|
|
78
|
+
if (discovered.length < MAX_NODE_COUNT
|
|
79
|
+
|| discovered.some((peerDescriptor) => areEqualPeerDescriptors(peerDescriptor, this.options.localPeerDescriptor))) {
|
|
80
|
+
await this.storeLocalNode()
|
|
81
|
+
}
|
|
82
|
+
} catch (err) {
|
|
83
|
+
logger.debug('Failed to keep local node', { key: this.options.key })
|
|
84
|
+
}
|
|
85
|
+
}, this.options.storeInterval ?? 60000, false, this.abortController.signal)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public isLocalNodeStored(): boolean {
|
|
89
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
90
|
+
return this.isLocalNodeStored_
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async destroy(): Promise<void> {
|
|
94
|
+
this.abortController.abort()
|
|
95
|
+
await this.options.deleteDataFromDht(this.options.key, false)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { areEqualPeerDescriptors, DhtAddress, getNodeIdFromPeerDescriptor, PeerDescriptor } from '@streamr/dht'
|
|
2
2
|
import { Logger, wait } from '@streamr/utils'
|
|
3
|
-
import {
|
|
3
|
+
import { DiscoveryLayerNode } from './DiscoveryLayerNode'
|
|
4
4
|
|
|
5
5
|
/*
|
|
6
6
|
* Tries to find new neighbors if we currently have less than MIN_NEIGHBOR_COUNT neigbors. It does so by
|
|
@@ -40,8 +40,8 @@ const exponentialRunOff = async (
|
|
|
40
40
|
|
|
41
41
|
export const MIN_NEIGHBOR_COUNT = 4
|
|
42
42
|
|
|
43
|
-
export interface
|
|
44
|
-
|
|
43
|
+
export interface StreamPartNetworkSplitAvoidanceOptions {
|
|
44
|
+
discoveryLayerNode: DiscoveryLayerNode
|
|
45
45
|
discoverEntryPoints: (excludedNodes?: Set<DhtAddress>) => Promise<PeerDescriptor[]>
|
|
46
46
|
exponentialRunOfBaseDelay?: number
|
|
47
47
|
}
|
|
@@ -49,31 +49,31 @@ export interface StreamPartNetworkSplitAvoidanceConfig {
|
|
|
49
49
|
export class StreamPartNetworkSplitAvoidance {
|
|
50
50
|
|
|
51
51
|
private readonly abortController: AbortController
|
|
52
|
-
private readonly
|
|
52
|
+
private readonly options: StreamPartNetworkSplitAvoidanceOptions
|
|
53
53
|
private readonly excludedNodes: Set<DhtAddress> = new Set()
|
|
54
54
|
private running = false
|
|
55
55
|
|
|
56
|
-
constructor(
|
|
57
|
-
this.
|
|
56
|
+
constructor(options: StreamPartNetworkSplitAvoidanceOptions) {
|
|
57
|
+
this.options = options
|
|
58
58
|
this.abortController = new AbortController()
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
public async avoidNetworkSplit(): Promise<void> {
|
|
62
62
|
this.running = true
|
|
63
63
|
await exponentialRunOff(async () => {
|
|
64
|
-
const discoveredEntrypoints = await this.
|
|
64
|
+
const discoveredEntrypoints = await this.options.discoverEntryPoints()
|
|
65
65
|
const filteredEntryPoints = discoveredEntrypoints.filter((peer) => !this.excludedNodes.has(getNodeIdFromPeerDescriptor(peer)))
|
|
66
|
-
await this.
|
|
67
|
-
if (this.
|
|
66
|
+
await this.options.discoveryLayerNode.joinDht(filteredEntryPoints, false, false)
|
|
67
|
+
if (this.options.discoveryLayerNode.getNeighborCount() < MIN_NEIGHBOR_COUNT) {
|
|
68
68
|
// Filter out nodes that are not neighbors as those nodes are assumed to be offline
|
|
69
69
|
const newExcludes = filteredEntryPoints
|
|
70
|
-
.filter((peer) => !this.
|
|
70
|
+
.filter((peer) => !this.options.discoveryLayerNode.getNeighbors()
|
|
71
71
|
.some((neighbor) => areEqualPeerDescriptors(neighbor, peer)))
|
|
72
72
|
.map((peer) => getNodeIdFromPeerDescriptor(peer))
|
|
73
73
|
newExcludes.forEach((node) => this.excludedNodes.add(node))
|
|
74
74
|
throw new Error(`Network split is still possible`)
|
|
75
75
|
}
|
|
76
|
-
}, 'avoid network split', this.abortController.signal, this.
|
|
76
|
+
}, 'avoid network split', this.abortController.signal, this.options.exponentialRunOfBaseDelay)
|
|
77
77
|
this.running = false
|
|
78
78
|
this.excludedNodes.clear()
|
|
79
79
|
logger.trace(`Network split avoided`)
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { scheduleAtInterval } from '@streamr/utils'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { PeerDescriptorStoreManager } from './PeerDescriptorStoreManager'
|
|
3
|
+
import { DiscoveryLayerNode } from './DiscoveryLayerNode'
|
|
4
4
|
|
|
5
5
|
const DEFAULT_RECONNECT_INTERVAL = 30 * 1000
|
|
6
6
|
export class StreamPartReconnect {
|
|
7
7
|
private abortController?: AbortController
|
|
8
|
-
private readonly
|
|
9
|
-
private readonly
|
|
8
|
+
private readonly discoveryLayerNode: DiscoveryLayerNode
|
|
9
|
+
private readonly peerDescriptorStoreManager: PeerDescriptorStoreManager
|
|
10
10
|
|
|
11
|
-
constructor(
|
|
12
|
-
this.
|
|
13
|
-
this.
|
|
11
|
+
constructor(discoveryLayerNode: DiscoveryLayerNode, peerDescriptorStoreManager: PeerDescriptorStoreManager) {
|
|
12
|
+
this.discoveryLayerNode = discoveryLayerNode
|
|
13
|
+
this.peerDescriptorStoreManager = peerDescriptorStoreManager
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
async reconnect(timeout = DEFAULT_RECONNECT_INTERVAL): Promise<void> {
|
|
17
17
|
this.abortController = new AbortController()
|
|
18
18
|
await scheduleAtInterval(async () => {
|
|
19
|
-
const entryPoints = await this.
|
|
20
|
-
await this.
|
|
21
|
-
if (this.
|
|
22
|
-
await this.
|
|
19
|
+
const entryPoints = await this.peerDescriptorStoreManager.fetchNodes()
|
|
20
|
+
await this.discoveryLayerNode.joinDht(entryPoints)
|
|
21
|
+
if (this.peerDescriptorStoreManager.isLocalNodeStored()) {
|
|
22
|
+
await this.peerDescriptorStoreManager.storeAndKeepLocalNode()
|
|
23
23
|
}
|
|
24
|
-
if (this.
|
|
24
|
+
if (this.discoveryLayerNode.getNeighborCount() > 0) {
|
|
25
25
|
this.abortController!.abort()
|
|
26
26
|
}
|
|
27
27
|
}, timeout, true, this.abortController.signal)
|