@streamr/trackerless-network 100.2.4-beta.0 → 100.2.4
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 -7
- package/dist/src/NetworkStack.js +1 -1
- package/dist/src/NetworkStack.js.map +1 -1
- package/dist/src/logic/ContentDeliveryLayerNode.js +9 -8
- package/dist/src/logic/ContentDeliveryLayerNode.js.map +1 -1
- package/dist/src/logic/ContentDeliveryManager.js +13 -1
- package/dist/src/logic/ContentDeliveryManager.js.map +1 -1
- package/dist/src/logic/EntryPointDiscovery.d.ts +3 -1
- package/dist/src/logic/EntryPointDiscovery.js +5 -0
- package/dist/src/logic/EntryPointDiscovery.js.map +1 -1
- package/dist/src/logic/Layer0Node.d.ts +2 -2
- package/dist/src/logic/Layer1Node.d.ts +7 -3
- package/dist/src/logic/StreamPartReconnect.d.ts +11 -0
- package/dist/src/logic/StreamPartReconnect.js +35 -0
- package/dist/src/logic/StreamPartReconnect.js.map +1 -0
- package/dist/test/benchmark/first-message.js +1 -1
- package/dist/test/benchmark/first-message.js.map +1 -1
- package/dist/test/utils/utils.js +2 -0
- package/dist/test/utils/utils.js.map +1 -1
- package/package.json +6 -7
- package/src/NetworkStack.ts +1 -1
- package/src/logic/ContentDeliveryLayerNode.ts +11 -9
- package/src/logic/ContentDeliveryManager.ts +13 -1
- package/src/logic/EntryPointDiscovery.ts +7 -1
- package/src/logic/Layer0Node.ts +2 -2
- package/src/logic/Layer1Node.ts +7 -3
- package/src/logic/StreamPartReconnect.ts +37 -0
- package/test/benchmark/first-message.ts +1 -1
- package/test/integration/ContentDeliveryLayerNode-Layer1Node-Latencies.test.ts +2 -0
- package/test/integration/ContentDeliveryLayerNode-Layer1Node.test.ts +2 -0
- package/test/integration/ContentDeliveryManager.test.ts +2 -0
- package/test/integration/Inspect.test.ts +2 -1
- package/test/integration/NetworkNode.test.ts +4 -2
- package/test/integration/NodeInfoRpc.test.ts +2 -0
- package/test/integration/joining-streams-on-offline-peers.test.ts +3 -0
- package/test/integration/stream-without-default-entrypoints.test.ts +2 -0
- package/test/integration/streamEntryPointReplacing.test.ts +2 -0
- package/test/unit/ContentDeliveryLayerNode.test.ts +5 -5
- package/test/unit/ContentDeliveryManager.test.ts +1 -1
- package/test/unit/ContentDeliveryRpcLocal.test.ts +1 -1
- package/test/unit/Inspector.test.ts +1 -1
- package/test/unit/NeighborUpdateRpcLocal.test.ts +1 -1
- package/test/unit/NodeList.test.ts +1 -1
- package/test/unit/StreamPartReconnect.test.ts +30 -0
- package/test/unit/TemporaryConnectionRpcLocal.test.ts +1 -1
- package/test/utils/fake/FakeEntryPointDiscovery.ts +32 -0
- package/test/utils/mock/MockConnectionsView.ts +18 -0
- package/test/utils/mock/MockLayer0Node.ts +5 -14
- package/test/utils/mock/MockLayer1Node.ts +2 -2
- package/test/utils/mock/{Transport.ts → MockTransport.ts} +2 -16
- package/test/utils/utils.ts +2 -0
|
@@ -65,6 +65,8 @@ export interface StrictContentDeliveryLayerNodeConfig {
|
|
|
65
65
|
rpcRequestTimeout?: number
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
const RANDOM_NODE_VIEW_SIZE = 20
|
|
69
|
+
|
|
68
70
|
const logger = new Logger(module)
|
|
69
71
|
|
|
70
72
|
export class ContentDeliveryLayerNode extends EventEmitter<Events> {
|
|
@@ -117,26 +119,26 @@ export class ContentDeliveryLayerNode extends EventEmitter<Events> {
|
|
|
117
119
|
this.registerDefaultServerMethods()
|
|
118
120
|
addManagedEventListener<any, any>(
|
|
119
121
|
this.config.layer1Node as any,
|
|
120
|
-
'
|
|
121
|
-
() => this.onNearbyContactAdded(
|
|
122
|
+
'nearbyContactAdded',
|
|
123
|
+
() => this.onNearbyContactAdded(),
|
|
122
124
|
this.abortController.signal
|
|
123
125
|
)
|
|
124
126
|
addManagedEventListener<any, any>(
|
|
125
127
|
this.config.layer1Node as any,
|
|
126
|
-
'
|
|
128
|
+
'nearbyContactRemoved',
|
|
127
129
|
() => this.onNearbyContactRemoved(),
|
|
128
130
|
this.abortController.signal
|
|
129
131
|
)
|
|
130
132
|
addManagedEventListener<any, any>(
|
|
131
133
|
this.config.layer1Node as any,
|
|
132
134
|
'randomContactAdded',
|
|
133
|
-
(
|
|
135
|
+
() => this.onRandomContactAdded(),
|
|
134
136
|
this.abortController.signal
|
|
135
137
|
)
|
|
136
138
|
addManagedEventListener<any, any>(
|
|
137
139
|
this.config.layer1Node as any,
|
|
138
140
|
'randomContactRemoved',
|
|
139
|
-
(
|
|
141
|
+
() => this.onRandomContactRemoved(),
|
|
140
142
|
this.abortController.signal
|
|
141
143
|
)
|
|
142
144
|
addManagedEventListener<any, any>(
|
|
@@ -230,12 +232,12 @@ export class ContentDeliveryLayerNode extends EventEmitter<Events> {
|
|
|
230
232
|
))
|
|
231
233
|
}
|
|
232
234
|
|
|
233
|
-
|
|
234
|
-
private onNearbyContactAdded(closestContacts: PeerDescriptor[]): void {
|
|
235
|
+
private onNearbyContactAdded(): void {
|
|
235
236
|
logger.trace(`New nearby contact found`)
|
|
236
237
|
if (this.isStopped()) {
|
|
237
238
|
return
|
|
238
239
|
}
|
|
240
|
+
const closestContacts = this.config.layer1Node.getClosestContacts()
|
|
239
241
|
this.updateNearbyNodeView(closestContacts)
|
|
240
242
|
if (this.config.neighbors.size() < this.config.neighborTargetCount) {
|
|
241
243
|
this.config.neighborFinder.start()
|
|
@@ -281,7 +283,7 @@ export class ContentDeliveryLayerNode extends EventEmitter<Events> {
|
|
|
281
283
|
if (this.isStopped()) {
|
|
282
284
|
return
|
|
283
285
|
}
|
|
284
|
-
const randomContacts = this.config.layer1Node.getRandomContacts()
|
|
286
|
+
const randomContacts = this.config.layer1Node.getRandomContacts(RANDOM_NODE_VIEW_SIZE)
|
|
285
287
|
this.config.randomNodeView.replaceAll(randomContacts.map((descriptor) =>
|
|
286
288
|
new ContentDeliveryRpcRemote(
|
|
287
289
|
this.config.localPeerDescriptor,
|
|
@@ -301,7 +303,7 @@ export class ContentDeliveryLayerNode extends EventEmitter<Events> {
|
|
|
301
303
|
if (this.isStopped()) {
|
|
302
304
|
return
|
|
303
305
|
}
|
|
304
|
-
const randomContacts = this.config.layer1Node.getRandomContacts()
|
|
306
|
+
const randomContacts = this.config.layer1Node.getRandomContacts(RANDOM_NODE_VIEW_SIZE)
|
|
305
307
|
this.config.randomNodeView.replaceAll(randomContacts.map((descriptor) =>
|
|
306
308
|
new ContentDeliveryRpcRemote(
|
|
307
309
|
this.config.localPeerDescriptor,
|
|
@@ -25,6 +25,7 @@ import { Layer1Node } from './Layer1Node'
|
|
|
25
25
|
import { ContentDeliveryLayerNode } from './ContentDeliveryLayerNode'
|
|
26
26
|
import { createContentDeliveryLayerNode } from './createContentDeliveryLayerNode'
|
|
27
27
|
import { ProxyClient } from './proxy/ProxyClient'
|
|
28
|
+
import { StreamPartReconnect } from './StreamPartReconnect'
|
|
28
29
|
|
|
29
30
|
export type StreamPartDelivery = {
|
|
30
31
|
broadcast: (msg: StreamMessage) => void
|
|
@@ -146,6 +147,7 @@ export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
|
146
147
|
layer1Node,
|
|
147
148
|
() => entryPointDiscovery.isLocalNodeEntryPoint()
|
|
148
149
|
)
|
|
150
|
+
const streamPartReconnect = new StreamPartReconnect(layer1Node, entryPointDiscovery)
|
|
149
151
|
streamPart = {
|
|
150
152
|
proxied: false,
|
|
151
153
|
layer1Node,
|
|
@@ -153,6 +155,7 @@ export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
|
153
155
|
entryPointDiscovery,
|
|
154
156
|
broadcast: (msg: StreamMessage) => node.broadcast(msg),
|
|
155
157
|
stop: async () => {
|
|
158
|
+
streamPartReconnect.destroy()
|
|
156
159
|
await entryPointDiscovery.destroy()
|
|
157
160
|
node.stop()
|
|
158
161
|
await layer1Node.stop()
|
|
@@ -169,6 +172,12 @@ export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
|
169
172
|
const entryPoints = await entryPointDiscovery.discoverEntryPointsFromDht(0)
|
|
170
173
|
await entryPointDiscovery.storeSelfAsEntryPointIfNecessary(entryPoints.discoveredEntryPoints.length)
|
|
171
174
|
}
|
|
175
|
+
layer1Node.on('manualRejoinRequired', async () => {
|
|
176
|
+
if (!streamPartReconnect.isRunning() && !entryPointDiscovery.isNetworkSplitAvoidanceRunning()) {
|
|
177
|
+
logger.debug('Manual rejoin required for stream part', { streamPartId })
|
|
178
|
+
await streamPartReconnect.reconnect()
|
|
179
|
+
}
|
|
180
|
+
})
|
|
172
181
|
node.on('entryPointLeaveDetected', () => handleEntryPointLeave())
|
|
173
182
|
setImmediate(async () => {
|
|
174
183
|
try {
|
|
@@ -205,12 +214,15 @@ export class ContentDeliveryManager extends EventEmitter<Events> {
|
|
|
205
214
|
private createLayer1Node(streamPartId: StreamPartID, entryPoints: PeerDescriptor[]): Layer1Node {
|
|
206
215
|
return new DhtNode({
|
|
207
216
|
transport: this.layer0Node!,
|
|
217
|
+
connectionsView: this.layer0Node!.getConnectionsView(),
|
|
208
218
|
serviceId: 'layer1::' + streamPartId,
|
|
209
219
|
peerDescriptor: this.layer0Node!.getLocalPeerDescriptor(),
|
|
210
220
|
entryPoints,
|
|
211
221
|
numberOfNodesPerKBucket: 4, // TODO use config option or named constant?
|
|
212
222
|
rpcRequestTimeout: EXISTING_CONNECTION_TIMEOUT,
|
|
213
|
-
dhtJoinTimeout: 20000 // TODO use config option or named constant?
|
|
223
|
+
dhtJoinTimeout: 20000, // TODO use config option or named constant?
|
|
224
|
+
periodicallyPingNeighbors: true,
|
|
225
|
+
periodicallyPingRingContacts: true
|
|
214
226
|
})
|
|
215
227
|
}
|
|
216
228
|
|
|
@@ -20,7 +20,7 @@ const parseEntryPointData = (dataEntries: DataEntry[]): PeerDescriptor[] => {
|
|
|
20
20
|
return dataEntries.filter((entry) => !entry.deleted).map((entry) => Any.unpack(entry.data!, PeerDescriptor))
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
interface FindEntryPointsResult {
|
|
23
|
+
export interface FindEntryPointsResult {
|
|
24
24
|
entryPointsFromDht: boolean
|
|
25
25
|
discoveredEntryPoints: PeerDescriptor[]
|
|
26
26
|
}
|
|
@@ -72,6 +72,7 @@ export class EntryPointDiscovery {
|
|
|
72
72
|
private readonly storeInterval: number
|
|
73
73
|
private readonly networkSplitAvoidedNodes: Set<DhtAddress> = new Set()
|
|
74
74
|
private isLocalNodeStoredAsEntryPoint = false
|
|
75
|
+
private networkSplitAvoidanceIsRunning = false
|
|
75
76
|
constructor(config: EntryPointDiscoveryConfig) {
|
|
76
77
|
this.config = config
|
|
77
78
|
this.abortController = new AbortController()
|
|
@@ -160,6 +161,7 @@ export class EntryPointDiscovery {
|
|
|
160
161
|
}
|
|
161
162
|
|
|
162
163
|
private async avoidNetworkSplit(): Promise<void> {
|
|
164
|
+
this.networkSplitAvoidanceIsRunning = true
|
|
163
165
|
await exponentialRunOff(async () => {
|
|
164
166
|
const rediscoveredEntrypoints = await this.discoverEntryPoints()
|
|
165
167
|
await this.config.layer1Node.joinDht(rediscoveredEntrypoints, false, false)
|
|
@@ -181,6 +183,10 @@ export class EntryPointDiscovery {
|
|
|
181
183
|
return this.isLocalNodeStoredAsEntryPoint
|
|
182
184
|
}
|
|
183
185
|
|
|
186
|
+
public isNetworkSplitAvoidanceRunning(): boolean {
|
|
187
|
+
return this.networkSplitAvoidanceIsRunning
|
|
188
|
+
}
|
|
189
|
+
|
|
184
190
|
async destroy(): Promise<void> {
|
|
185
191
|
this.abortController.abort()
|
|
186
192
|
await this.config.deleteEntryPointData(streamPartIdToDataKey(this.config.streamPartId))
|
package/src/logic/Layer0Node.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DataEntry, DhtAddress, ITransport, PeerDescriptor } from '@streamr/dht'
|
|
1
|
+
import { ConnectionsView, DataEntry, DhtAddress, ITransport, PeerDescriptor } from '@streamr/dht'
|
|
2
2
|
import { Any } from '../proto/google/protobuf/any'
|
|
3
3
|
|
|
4
4
|
export interface Layer0Node extends ITransport {
|
|
@@ -11,7 +11,7 @@ export interface Layer0Node extends ITransport {
|
|
|
11
11
|
waitForNetworkConnectivity(): Promise<void>
|
|
12
12
|
getTransport(): ITransport
|
|
13
13
|
getNeighbors(): PeerDescriptor[]
|
|
14
|
-
|
|
14
|
+
getConnectionsView(): ConnectionsView
|
|
15
15
|
start(): Promise<void>
|
|
16
16
|
stop(): Promise<void>
|
|
17
17
|
}
|
package/src/logic/Layer1Node.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { DhtAddress, PeerDescriptor, RingContacts } from '@streamr/dht'
|
|
2
2
|
|
|
3
3
|
export interface Layer1NodeEvents {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
manualRejoinRequired: () => void
|
|
5
|
+
nearbyContactAdded: (peerDescriptor: PeerDescriptor) => void
|
|
6
|
+
nearbyContactRemoved: (peerDescriptor: PeerDescriptor) => void
|
|
6
7
|
randomContactAdded: (peerDescriptor: PeerDescriptor) => void
|
|
7
8
|
randomContactRemoved: (peerDescriptor: PeerDescriptor) => void
|
|
8
9
|
ringContactAdded: (peerDescriptor: PeerDescriptor) => void
|
|
@@ -13,9 +14,12 @@ export interface Layer1Node {
|
|
|
13
14
|
on<T extends keyof Layer1NodeEvents>(eventName: T, listener: (peerDescriptor: PeerDescriptor) => void): void
|
|
14
15
|
once<T extends keyof Layer1NodeEvents>(eventName: T, listener: (peerDescriptor: PeerDescriptor) => void): void
|
|
15
16
|
off<T extends keyof Layer1NodeEvents>(eventName: T, listener: (peerDescriptor: PeerDescriptor) => void): void
|
|
17
|
+
on<T extends keyof Layer1NodeEvents>(eventName: T, listener: () => void): void
|
|
18
|
+
once<T extends keyof Layer1NodeEvents>(eventName: T, listener: () => void): void
|
|
19
|
+
off<T extends keyof Layer1NodeEvents>(eventName: T, listener: () => void): void
|
|
16
20
|
removeContact: (nodeId: DhtAddress) => void
|
|
17
21
|
getClosestContacts: (maxCount?: number) => PeerDescriptor[]
|
|
18
|
-
getRandomContacts: () => PeerDescriptor[]
|
|
22
|
+
getRandomContacts: (maxCount?: number) => PeerDescriptor[]
|
|
19
23
|
getRingContacts: () => RingContacts
|
|
20
24
|
getNeighbors: () => PeerDescriptor[]
|
|
21
25
|
getNeighborCount(): number
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { scheduleAtInterval } from '@streamr/utils'
|
|
2
|
+
import { EntryPointDiscovery } from './EntryPointDiscovery'
|
|
3
|
+
import { Layer1Node } from './Layer1Node'
|
|
4
|
+
|
|
5
|
+
const DEFAULT_RECONNECT_INTERVAL = 30 * 1000
|
|
6
|
+
export class StreamPartReconnect {
|
|
7
|
+
private abortController?: AbortController
|
|
8
|
+
private readonly layer1Node: Layer1Node
|
|
9
|
+
private readonly entryPointDiscovery: EntryPointDiscovery
|
|
10
|
+
|
|
11
|
+
constructor(layer1Node: Layer1Node, entryPointDiscovery: EntryPointDiscovery) {
|
|
12
|
+
this.layer1Node = layer1Node
|
|
13
|
+
this.entryPointDiscovery = entryPointDiscovery
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async reconnect(timeout = DEFAULT_RECONNECT_INTERVAL): Promise<void> {
|
|
17
|
+
this.abortController = new AbortController()
|
|
18
|
+
await scheduleAtInterval(async () => {
|
|
19
|
+
const entryPoints = await this.entryPointDiscovery.discoverEntryPointsFromDht(0)
|
|
20
|
+
await this.layer1Node.joinDht(entryPoints.discoveredEntryPoints)
|
|
21
|
+
if (this.entryPointDiscovery.isLocalNodeEntryPoint()) {
|
|
22
|
+
await this.entryPointDiscovery.storeSelfAsEntryPointIfNecessary(entryPoints.discoveredEntryPoints.length)
|
|
23
|
+
}
|
|
24
|
+
if (this.layer1Node.getNeighborCount() > 0) {
|
|
25
|
+
this.abortController!.abort()
|
|
26
|
+
}
|
|
27
|
+
}, timeout, true, this.abortController.signal)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
isRunning(): boolean {
|
|
31
|
+
return this.abortController ? !this.abortController.signal.aborted : false
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
destroy(): void {
|
|
35
|
+
this.abortController?.abort()
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -159,7 +159,7 @@ run().then(() => {
|
|
|
159
159
|
console.log(foundData)
|
|
160
160
|
const layer0Node = currentNode.stack.getLayer0Node() as DhtNode
|
|
161
161
|
console.log(layer0Node.getNeighbors().length)
|
|
162
|
-
console.log(layer0Node.getConnectionCount())
|
|
162
|
+
console.log(layer0Node.getConnectionsView().getConnectionCount())
|
|
163
163
|
const streamPartDelivery = contentDeliveryManager
|
|
164
164
|
.getStreamPartDelivery(streamParts[0])! as { layer1Node: Layer1Node, node: ContentDeliveryLayerNode }
|
|
165
165
|
console.log(streamPartDelivery.layer1Node.getNeighbors())
|
|
@@ -29,11 +29,13 @@ describe('ContentDeliveryLayerNode-DhtNode-Latencies', () => {
|
|
|
29
29
|
|
|
30
30
|
entryPointLayer1Node = new DhtNode({
|
|
31
31
|
transport: entrypointCm,
|
|
32
|
+
connectionsView: entrypointCm,
|
|
32
33
|
peerDescriptor: entrypointDescriptor,
|
|
33
34
|
serviceId: streamPartId
|
|
34
35
|
})
|
|
35
36
|
otherLayer1Nodes = range(otherNodeCount).map((i) => new DhtNode({
|
|
36
37
|
transport: cms[i],
|
|
38
|
+
connectionsView: cms[i],
|
|
37
39
|
peerDescriptor: peerDescriptors[i],
|
|
38
40
|
serviceId: streamPartId
|
|
39
41
|
}))
|
|
@@ -44,12 +44,14 @@ describe('ContentDeliveryLayerNode-DhtNode', () => {
|
|
|
44
44
|
|
|
45
45
|
entryPointLayer1Node = new DhtNode({
|
|
46
46
|
transport: entrypointCm,
|
|
47
|
+
connectionsView: entrypointCm,
|
|
47
48
|
peerDescriptor: entrypointDescriptor,
|
|
48
49
|
serviceId: streamPartId
|
|
49
50
|
})
|
|
50
51
|
|
|
51
52
|
otherLayer1Nodes = range(otherNodeCount).map((i) => new DhtNode({
|
|
52
53
|
transport: cms[i],
|
|
54
|
+
connectionsView: cms[i],
|
|
53
55
|
peerDescriptor: peerDescriptors[i],
|
|
54
56
|
serviceId: streamPartId
|
|
55
57
|
}))
|
|
@@ -44,11 +44,13 @@ describe('ContentDeliveryManager', () => {
|
|
|
44
44
|
await transport2.start()
|
|
45
45
|
layer0Node1 = new DhtNode({
|
|
46
46
|
transport: transport1,
|
|
47
|
+
connectionsView: transport1,
|
|
47
48
|
peerDescriptor: peerDescriptor1,
|
|
48
49
|
entryPoints: [peerDescriptor1]
|
|
49
50
|
})
|
|
50
51
|
layer0Node2 = new DhtNode({
|
|
51
52
|
transport: transport2,
|
|
53
|
+
connectionsView: transport2,
|
|
52
54
|
peerDescriptor: peerDescriptor2,
|
|
53
55
|
entryPoints: [peerDescriptor1]
|
|
54
56
|
})
|
|
@@ -37,14 +37,16 @@ describe('NetworkNode', () => {
|
|
|
37
37
|
layer0: {
|
|
38
38
|
entryPoints: [pd1],
|
|
39
39
|
peerDescriptor: pd1,
|
|
40
|
-
transport: transport1
|
|
40
|
+
transport: transport1,
|
|
41
|
+
connectionsView: transport1
|
|
41
42
|
}
|
|
42
43
|
})
|
|
43
44
|
node2 = createNetworkNode({
|
|
44
45
|
layer0: {
|
|
45
46
|
entryPoints: [pd1],
|
|
46
47
|
peerDescriptor: pd2,
|
|
47
|
-
transport: transport2
|
|
48
|
+
transport: transport2,
|
|
49
|
+
connectionsView: transport2
|
|
48
50
|
}
|
|
49
51
|
})
|
|
50
52
|
|
|
@@ -40,6 +40,7 @@ describe('NetworkStack NodeInfoRpc', () => {
|
|
|
40
40
|
requesteStack = new NetworkStack({
|
|
41
41
|
layer0: {
|
|
42
42
|
transport: requesteeTransport1,
|
|
43
|
+
connectionsView: requesteeTransport1,
|
|
43
44
|
peerDescriptor: requesteePeerDescriptor,
|
|
44
45
|
entryPoints: [requesteePeerDescriptor]
|
|
45
46
|
}
|
|
@@ -47,6 +48,7 @@ describe('NetworkStack NodeInfoRpc', () => {
|
|
|
47
48
|
otherStack = new NetworkStack({
|
|
48
49
|
layer0: {
|
|
49
50
|
transport: otherTransport,
|
|
51
|
+
connectionsView: otherTransport,
|
|
50
52
|
peerDescriptor: otherPeerDescriptor,
|
|
51
53
|
entryPoints: [requesteePeerDescriptor]
|
|
52
54
|
}
|
|
@@ -28,6 +28,7 @@ describe('Joining stream parts on offline nodes', () => {
|
|
|
28
28
|
entryPoint = new NetworkStack({
|
|
29
29
|
layer0: {
|
|
30
30
|
transport: entryPointTransport,
|
|
31
|
+
connectionsView: entryPointTransport,
|
|
31
32
|
peerDescriptor: entryPointPeerDescriptor,
|
|
32
33
|
entryPoints: [entryPointPeerDescriptor]
|
|
33
34
|
}
|
|
@@ -36,6 +37,7 @@ describe('Joining stream parts on offline nodes', () => {
|
|
|
36
37
|
node1 = new NetworkStack({
|
|
37
38
|
layer0: {
|
|
38
39
|
transport: node1Transport,
|
|
40
|
+
connectionsView: node1Transport,
|
|
39
41
|
peerDescriptor: node1PeerDescriptor,
|
|
40
42
|
entryPoints: [entryPointPeerDescriptor]
|
|
41
43
|
}
|
|
@@ -44,6 +46,7 @@ describe('Joining stream parts on offline nodes', () => {
|
|
|
44
46
|
node2 = new NetworkStack({
|
|
45
47
|
layer0: {
|
|
46
48
|
transport: node2Transport,
|
|
49
|
+
connectionsView: node2Transport,
|
|
47
50
|
peerDescriptor: node2PeerDescriptor,
|
|
48
51
|
entryPoints: [entryPointPeerDescriptor]
|
|
49
52
|
}
|
|
@@ -53,6 +53,7 @@ describe('stream without default entrypoints', () => {
|
|
|
53
53
|
entrypoint = createNetworkNode({
|
|
54
54
|
layer0: {
|
|
55
55
|
transport: entryPointTransport,
|
|
56
|
+
connectionsView: entryPointTransport,
|
|
56
57
|
peerDescriptor: entryPointPeerDescriptor,
|
|
57
58
|
entryPoints: [entryPointPeerDescriptor]
|
|
58
59
|
}
|
|
@@ -66,6 +67,7 @@ describe('stream without default entrypoints', () => {
|
|
|
66
67
|
layer0: {
|
|
67
68
|
peerDescriptor,
|
|
68
69
|
transport,
|
|
70
|
+
connectionsView: transport,
|
|
69
71
|
entryPoints: [entryPointPeerDescriptor]
|
|
70
72
|
}
|
|
71
73
|
})
|
|
@@ -27,6 +27,7 @@ describe('Stream Entry Points are replaced when known entry points leave streams
|
|
|
27
27
|
const node = new NetworkStack({
|
|
28
28
|
layer0: {
|
|
29
29
|
transport,
|
|
30
|
+
connectionsView: transport,
|
|
30
31
|
peerDescriptor,
|
|
31
32
|
entryPoints: [entryPointPeerDescriptor]
|
|
32
33
|
}
|
|
@@ -41,6 +42,7 @@ describe('Stream Entry Points are replaced when known entry points leave streams
|
|
|
41
42
|
layer0EntryPoint = new NetworkStack({
|
|
42
43
|
layer0: {
|
|
43
44
|
transport: entryPointTransport,
|
|
45
|
+
connectionsView: entryPointTransport,
|
|
44
46
|
peerDescriptor: entryPointPeerDescriptor,
|
|
45
47
|
entryPoints: [entryPointPeerDescriptor]
|
|
46
48
|
}
|
|
@@ -6,7 +6,7 @@ import { MockHandshaker } from '../utils/mock/MockHandshaker'
|
|
|
6
6
|
import { MockLayer1Node } from '../utils/mock/MockLayer1Node'
|
|
7
7
|
import { MockNeighborFinder } from '../utils/mock/MockNeighborFinder'
|
|
8
8
|
import { MockNeighborUpdateManager } from '../utils/mock/MockNeighborUpdateManager'
|
|
9
|
-
import { MockTransport } from '../utils/mock/
|
|
9
|
+
import { MockTransport } from '../utils/mock/MockTransport'
|
|
10
10
|
import { createMockPeerDescriptor, createMockContentDeliveryRpcRemote, mockConnectionLocker } from '../utils/utils'
|
|
11
11
|
import { StreamPartIDUtils } from '@streamr/protocol'
|
|
12
12
|
import { getNodeIdFromPeerDescriptor } from '@streamr/dht'
|
|
@@ -65,11 +65,11 @@ describe('ContentDeliveryLayerNode', () => {
|
|
|
65
65
|
expect(ids[0]).toEqual(getNodeIdFromPeerDescriptor(mockRemote.getPeerDescriptor()))
|
|
66
66
|
})
|
|
67
67
|
|
|
68
|
-
it('Adds Closest Nodes from layer1
|
|
68
|
+
it('Adds Closest Nodes from layer1 nearbyContactAdded event to nearbyNodeView', async () => {
|
|
69
69
|
const peerDescriptor1 = createMockPeerDescriptor()
|
|
70
70
|
const peerDescriptor2 = createMockPeerDescriptor()
|
|
71
71
|
layer1Node.setClosestContacts([peerDescriptor1, peerDescriptor2])
|
|
72
|
-
layer1Node.emit('
|
|
72
|
+
layer1Node.emit('nearbyContactAdded', peerDescriptor1)
|
|
73
73
|
await waitForCondition(() => nearbyNodeView.size() === 2)
|
|
74
74
|
expect(nearbyNodeView.get(getNodeIdFromPeerDescriptor(peerDescriptor1))).toBeTruthy()
|
|
75
75
|
expect(nearbyNodeView.get(getNodeIdFromPeerDescriptor(peerDescriptor2))).toBeTruthy()
|
|
@@ -85,12 +85,12 @@ describe('ContentDeliveryLayerNode', () => {
|
|
|
85
85
|
expect(randomNodeView.get(getNodeIdFromPeerDescriptor(peerDescriptor2))).toBeTruthy()
|
|
86
86
|
})
|
|
87
87
|
|
|
88
|
-
it('Adds Nodes from layer1
|
|
88
|
+
it('Adds Nodes from layer1 neighbors to nearbyNodeView if its size is below nodeViewSize', async () => {
|
|
89
89
|
const peerDescriptor1 = createMockPeerDescriptor()
|
|
90
90
|
const peerDescriptor2 = createMockPeerDescriptor()
|
|
91
91
|
layer1Node.addNewRandomPeerToKBucket()
|
|
92
92
|
layer1Node.setClosestContacts([peerDescriptor1, peerDescriptor2])
|
|
93
|
-
layer1Node.emit('
|
|
93
|
+
layer1Node.emit('nearbyContactAdded', peerDescriptor1)
|
|
94
94
|
await waitForCondition(() => {
|
|
95
95
|
return nearbyNodeView.size() === 3
|
|
96
96
|
}, 20000)
|
|
@@ -4,7 +4,7 @@ import { randomEthereumAddress } from '@streamr/test-utils'
|
|
|
4
4
|
import { waitForCondition } from '@streamr/utils'
|
|
5
5
|
import { ContentDeliveryManager } from '../../src/logic/ContentDeliveryManager'
|
|
6
6
|
import { MockLayer0Node } from '../utils/mock/MockLayer0Node'
|
|
7
|
-
import { MockTransport } from '../utils/mock/
|
|
7
|
+
import { MockTransport } from '../utils/mock/MockTransport'
|
|
8
8
|
import { createMockPeerDescriptor, createStreamMessage, mockConnectionLocker } from '../utils/utils'
|
|
9
9
|
import { ProxyDirection } from '../../src/proto/packages/trackerless-network/protos/NetworkRpc'
|
|
10
10
|
|
|
@@ -3,7 +3,7 @@ import { StreamPartIDUtils } from '@streamr/protocol'
|
|
|
3
3
|
import { randomEthereumAddress } from '@streamr/test-utils'
|
|
4
4
|
import { ContentDeliveryRpcLocal } from '../../src/logic/ContentDeliveryRpcLocal'
|
|
5
5
|
import { LeaveStreamPartNotice } from '../../src/proto/packages/trackerless-network/protos/NetworkRpc'
|
|
6
|
-
import { MockTransport } from '../utils/mock/
|
|
6
|
+
import { MockTransport } from '../utils/mock/MockTransport'
|
|
7
7
|
import { createMockPeerDescriptor, createStreamMessage } from '../utils/utils'
|
|
8
8
|
|
|
9
9
|
describe('ContentDeliveryRpcLocal', () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ListeningRpcCommunicator, createRandomDhtAddress, getNodeIdFromPeerDescriptor } from '@streamr/dht'
|
|
2
2
|
import { utf8ToBinary } from '@streamr/utils'
|
|
3
3
|
import { Inspector } from '../../src/logic/inspect/Inspector'
|
|
4
|
-
import { MockTransport } from '../utils/mock/
|
|
4
|
+
import { MockTransport } from '../utils/mock/MockTransport'
|
|
5
5
|
import { createMockPeerDescriptor, mockConnectionLocker } from '../utils/utils'
|
|
6
6
|
import { StreamPartIDUtils } from '@streamr/protocol'
|
|
7
7
|
|
|
@@ -4,7 +4,7 @@ import { NeighborUpdateRpcLocal } from '../../src/logic/neighbor-discovery/Neigh
|
|
|
4
4
|
import { createMockPeerDescriptor } from '../utils/utils'
|
|
5
5
|
import { NodeList } from '../../src/logic/NodeList'
|
|
6
6
|
import { StreamPartIDUtils } from '@streamr/protocol'
|
|
7
|
-
import { MockTransport } from '../utils/mock/
|
|
7
|
+
import { MockTransport } from '../utils/mock/MockTransport'
|
|
8
8
|
import { ContentDeliveryRpcClient } from '../../src/proto/packages/trackerless-network/protos/NetworkRpc.client'
|
|
9
9
|
import { ContentDeliveryRpcRemote } from '../../src/logic/ContentDeliveryRpcRemote'
|
|
10
10
|
import { range } from 'lodash'
|
|
@@ -13,7 +13,7 @@ import { NodeList } from '../../src/logic/NodeList'
|
|
|
13
13
|
import { formStreamPartContentDeliveryServiceId } from '../../src/logic/formStreamPartDeliveryServiceId'
|
|
14
14
|
import { ContentDeliveryRpcClient } from '../../src/proto/packages/trackerless-network/protos/NetworkRpc.client'
|
|
15
15
|
import { createMockPeerDescriptor } from '../utils/utils'
|
|
16
|
-
import { MockTransport } from '../utils/mock/
|
|
16
|
+
import { MockTransport } from '../utils/mock/MockTransport'
|
|
17
17
|
|
|
18
18
|
const streamPartId = StreamPartIDUtils.parse('stream#0')
|
|
19
19
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { EntryPointDiscovery } from '../../src/logic/EntryPointDiscovery'
|
|
2
|
+
import { StreamPartReconnect } from '../../src/logic/StreamPartReconnect'
|
|
3
|
+
import { MockLayer1Node } from '../utils/mock/MockLayer1Node'
|
|
4
|
+
import { createFakeEntryPointDiscovery } from '../utils/fake/FakeEntryPointDiscovery'
|
|
5
|
+
import { waitForCondition } from '@streamr/utils'
|
|
6
|
+
|
|
7
|
+
describe('StreamPartReconnect', () => {
|
|
8
|
+
|
|
9
|
+
let entryPointDiscovery: EntryPointDiscovery
|
|
10
|
+
let layer1Node: MockLayer1Node
|
|
11
|
+
let streamPartReconnect: StreamPartReconnect
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
entryPointDiscovery = createFakeEntryPointDiscovery()
|
|
15
|
+
layer1Node = new MockLayer1Node()
|
|
16
|
+
streamPartReconnect = new StreamPartReconnect(layer1Node, entryPointDiscovery)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
streamPartReconnect.destroy()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('Happy path', async () => {
|
|
24
|
+
await streamPartReconnect.reconnect(1000)
|
|
25
|
+
expect(streamPartReconnect.isRunning()).toEqual(true)
|
|
26
|
+
layer1Node.addNewRandomPeerToKBucket()
|
|
27
|
+
await waitForCondition(() => streamPartReconnect.isRunning() === false)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StreamPartIDUtils } from '@streamr/protocol'
|
|
2
2
|
import { TemporaryConnectionRpcLocal } from '../../src/logic/temporary-connection/TemporaryConnectionRpcLocal'
|
|
3
|
-
import { MockTransport } from '../utils/mock/
|
|
3
|
+
import { MockTransport } from '../utils/mock/MockTransport'
|
|
4
4
|
import { createMockPeerDescriptor } from '../utils/utils'
|
|
5
5
|
import { ListeningRpcCommunicator, getDhtAddressFromRaw } from '@streamr/dht'
|
|
6
6
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { PeerDescriptor } from '@streamr/dht'
|
|
2
|
+
import { EntryPointDiscovery, FindEntryPointsResult } from '../../../src/logic/EntryPointDiscovery'
|
|
3
|
+
|
|
4
|
+
export const createFakeEntryPointDiscovery = (): EntryPointDiscovery => {
|
|
5
|
+
return new FakeEntryPointDiscovery() as unknown as EntryPointDiscovery
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
class FakeEntryPointDiscovery {
|
|
9
|
+
|
|
10
|
+
private entryPoints: PeerDescriptor[] = []
|
|
11
|
+
|
|
12
|
+
setEntryPoints(nodes: PeerDescriptor[]): void {
|
|
13
|
+
this.entryPoints = nodes
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async discoverEntryPointsFromDht(): Promise<FindEntryPointsResult> {
|
|
17
|
+
return {
|
|
18
|
+
entryPointsFromDht: true,
|
|
19
|
+
discoveredEntryPoints: this.entryPoints
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// eslint-disable-next-line class-methods-use-this
|
|
24
|
+
async storeSelfAsEntryPointIfNecessary(): Promise<void> {
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// eslint-disable-next-line class-methods-use-this
|
|
28
|
+
isLocalNodeEntryPoint(): boolean {
|
|
29
|
+
return true
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PeerDescriptor } from '@streamr/dht'
|
|
2
|
+
|
|
3
|
+
export class MockConnectionsView {
|
|
4
|
+
// eslint-disable-next-line class-methods-use-this
|
|
5
|
+
getConnections(): PeerDescriptor[] {
|
|
6
|
+
return []
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// eslint-disable-next-line class-methods-use-this
|
|
10
|
+
getConnectionCount(): number {
|
|
11
|
+
return 0
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// eslint-disable-next-line class-methods-use-this
|
|
15
|
+
hasConnection(): boolean {
|
|
16
|
+
return false
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { PeerDescriptor, DataEntry, ITransport } from '@streamr/dht'
|
|
1
|
+
import { PeerDescriptor, DataEntry, ITransport, TransportEvents, ConnectionsView } from '@streamr/dht'
|
|
2
2
|
import { Layer0Node } from '../../../src/logic/Layer0Node'
|
|
3
3
|
import { EventEmitter } from 'eventemitter3'
|
|
4
|
+
import { MockConnectionsView } from './MockConnectionsView'
|
|
4
5
|
|
|
5
|
-
export class MockLayer0Node extends EventEmitter implements Layer0Node {
|
|
6
|
+
export class MockLayer0Node extends EventEmitter<TransportEvents> implements Layer0Node {
|
|
6
7
|
|
|
7
8
|
private readonly peerDescriptor: PeerDescriptor
|
|
8
9
|
|
|
@@ -44,18 +45,8 @@ export class MockLayer0Node extends EventEmitter implements Layer0Node {
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
// eslint-disable-next-line class-methods-use-this
|
|
47
|
-
|
|
48
|
-
return
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// eslint-disable-next-line class-methods-use-this
|
|
52
|
-
getConnectionCount(): number {
|
|
53
|
-
return 0
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// eslint-disable-next-line class-methods-use-this
|
|
57
|
-
hasConnection(): boolean {
|
|
58
|
-
return false
|
|
48
|
+
getConnectionsView(): ConnectionsView {
|
|
49
|
+
return new MockConnectionsView()
|
|
59
50
|
}
|
|
60
51
|
|
|
61
52
|
// eslint-disable-next-line class-methods-use-this
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { PeerDescriptor, RingContacts } from '@streamr/dht'
|
|
2
2
|
import { EventEmitter } from 'eventemitter3'
|
|
3
|
-
import { Layer1Node } from '../../../src/logic/Layer1Node'
|
|
3
|
+
import { Layer1Node, Layer1NodeEvents } from '../../../src/logic/Layer1Node'
|
|
4
4
|
import { createMockPeerDescriptor } from '../utils'
|
|
5
5
|
|
|
6
|
-
export class MockLayer1Node extends EventEmitter implements Layer1Node {
|
|
6
|
+
export class MockLayer1Node extends EventEmitter<Layer1NodeEvents> implements Layer1Node {
|
|
7
7
|
|
|
8
8
|
private readonly kbucketPeers: PeerDescriptor[] = []
|
|
9
9
|
private closestContacts: PeerDescriptor[] = []
|