@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.
Files changed (51) hide show
  1. package/dist/package.json +6 -7
  2. package/dist/src/NetworkStack.js +1 -1
  3. package/dist/src/NetworkStack.js.map +1 -1
  4. package/dist/src/logic/ContentDeliveryLayerNode.js +9 -8
  5. package/dist/src/logic/ContentDeliveryLayerNode.js.map +1 -1
  6. package/dist/src/logic/ContentDeliveryManager.js +13 -1
  7. package/dist/src/logic/ContentDeliveryManager.js.map +1 -1
  8. package/dist/src/logic/EntryPointDiscovery.d.ts +3 -1
  9. package/dist/src/logic/EntryPointDiscovery.js +5 -0
  10. package/dist/src/logic/EntryPointDiscovery.js.map +1 -1
  11. package/dist/src/logic/Layer0Node.d.ts +2 -2
  12. package/dist/src/logic/Layer1Node.d.ts +7 -3
  13. package/dist/src/logic/StreamPartReconnect.d.ts +11 -0
  14. package/dist/src/logic/StreamPartReconnect.js +35 -0
  15. package/dist/src/logic/StreamPartReconnect.js.map +1 -0
  16. package/dist/test/benchmark/first-message.js +1 -1
  17. package/dist/test/benchmark/first-message.js.map +1 -1
  18. package/dist/test/utils/utils.js +2 -0
  19. package/dist/test/utils/utils.js.map +1 -1
  20. package/package.json +6 -7
  21. package/src/NetworkStack.ts +1 -1
  22. package/src/logic/ContentDeliveryLayerNode.ts +11 -9
  23. package/src/logic/ContentDeliveryManager.ts +13 -1
  24. package/src/logic/EntryPointDiscovery.ts +7 -1
  25. package/src/logic/Layer0Node.ts +2 -2
  26. package/src/logic/Layer1Node.ts +7 -3
  27. package/src/logic/StreamPartReconnect.ts +37 -0
  28. package/test/benchmark/first-message.ts +1 -1
  29. package/test/integration/ContentDeliveryLayerNode-Layer1Node-Latencies.test.ts +2 -0
  30. package/test/integration/ContentDeliveryLayerNode-Layer1Node.test.ts +2 -0
  31. package/test/integration/ContentDeliveryManager.test.ts +2 -0
  32. package/test/integration/Inspect.test.ts +2 -1
  33. package/test/integration/NetworkNode.test.ts +4 -2
  34. package/test/integration/NodeInfoRpc.test.ts +2 -0
  35. package/test/integration/joining-streams-on-offline-peers.test.ts +3 -0
  36. package/test/integration/stream-without-default-entrypoints.test.ts +2 -0
  37. package/test/integration/streamEntryPointReplacing.test.ts +2 -0
  38. package/test/unit/ContentDeliveryLayerNode.test.ts +5 -5
  39. package/test/unit/ContentDeliveryManager.test.ts +1 -1
  40. package/test/unit/ContentDeliveryRpcLocal.test.ts +1 -1
  41. package/test/unit/Inspector.test.ts +1 -1
  42. package/test/unit/NeighborUpdateRpcLocal.test.ts +1 -1
  43. package/test/unit/NodeList.test.ts +1 -1
  44. package/test/unit/StreamPartReconnect.test.ts +30 -0
  45. package/test/unit/TemporaryConnectionRpcLocal.test.ts +1 -1
  46. package/test/utils/fake/FakeEntryPointDiscovery.ts +32 -0
  47. package/test/utils/mock/MockConnectionsView.ts +18 -0
  48. package/test/utils/mock/MockLayer0Node.ts +5 -14
  49. package/test/utils/mock/MockLayer1Node.ts +2 -2
  50. package/test/utils/mock/{Transport.ts → MockTransport.ts} +2 -16
  51. 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
- 'closestContactAdded',
121
- () => this.onNearbyContactAdded(this.config.layer1Node.getClosestContacts()),
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
- 'closestContactRemoved',
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
- (_peerDescriptor: PeerDescriptor) => this.onRandomContactAdded(),
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
- (_peerDescriptor: PeerDescriptor) => this.onRandomContactRemoved(),
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
- // TODO refactor so that we don't need to give the parameter? (i.e. would be similar to onNearbyContactRemoved and other event handlers)
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))
@@ -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
- getConnections(): PeerDescriptor[]
14
+ getConnectionsView(): ConnectionsView
15
15
  start(): Promise<void>
16
16
  stop(): Promise<void>
17
17
  }
@@ -1,8 +1,9 @@
1
1
  import { DhtAddress, PeerDescriptor, RingContacts } from '@streamr/dht'
2
2
 
3
3
  export interface Layer1NodeEvents {
4
- closestContactAdded: (peerDescriptor: PeerDescriptor) => void
5
- closestContactRemoved: (peerDescriptor: PeerDescriptor) => void
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
  })
@@ -30,7 +30,8 @@ describe('inspect', () => {
30
30
  layer0: {
31
31
  entryPoints: [publisherDescriptor],
32
32
  peerDescriptor,
33
- transport
33
+ transport,
34
+ connectionsView: transport
34
35
  }
35
36
  })
36
37
  await node.start()
@@ -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/Transport'
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 contactAdded event to nearbyNodeView', async () => {
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('closestContactAdded', peerDescriptor1)
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 KBucket to nearbyNodeView if its size is below nodeViewSize', async () => {
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('closestContactAdded', peerDescriptor1)
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/Transport'
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/Transport'
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/Transport'
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/Transport'
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/Transport'
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/Transport'
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
- getConnections(): PeerDescriptor[] {
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[] = []