@streamr/dht 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 (151) hide show
  1. package/dist/package.json +8 -9
  2. package/dist/src/connection/ConnectionManager.d.ts +2 -1
  3. package/dist/src/connection/ConnectionManager.js +2 -10
  4. package/dist/src/connection/ConnectionManager.js.map +1 -1
  5. package/dist/src/connection/ConnectionsView.d.ts +7 -0
  6. package/dist/src/connection/ConnectionsView.js +3 -0
  7. package/dist/src/connection/ConnectionsView.js.map +1 -0
  8. package/dist/src/connection/ConnectorFacade.d.ts +2 -1
  9. package/dist/src/connection/ConnectorFacade.js +5 -4
  10. package/dist/src/connection/ConnectorFacade.js.map +1 -1
  11. package/dist/src/connection/connectivityRequestHandler.d.ts +2 -1
  12. package/dist/src/connection/connectivityRequestHandler.js +12 -5
  13. package/dist/src/connection/connectivityRequestHandler.js.map +1 -1
  14. package/dist/src/connection/{ManagedWebrtcConnection.d.ts → webrtc/ManagedWebrtcConnection.d.ts} +3 -3
  15. package/dist/src/connection/{ManagedWebrtcConnection.js → webrtc/ManagedWebrtcConnection.js} +2 -2
  16. package/dist/src/connection/webrtc/ManagedWebrtcConnection.js.map +1 -0
  17. package/dist/src/connection/webrtc/NodeWebrtcConnection.js +3 -26
  18. package/dist/src/connection/webrtc/NodeWebrtcConnection.js.map +1 -1
  19. package/dist/src/connection/webrtc/WebrtcConnector.js +1 -1
  20. package/dist/src/connection/webrtc/WebrtcConnector.js.map +1 -1
  21. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.d.ts +1 -1
  22. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js +1 -1
  23. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js.map +1 -1
  24. package/dist/src/connection/websocket/WebsocketConnector.d.ts +2 -0
  25. package/dist/src/connection/websocket/WebsocketConnector.js +21 -13
  26. package/dist/src/connection/websocket/WebsocketConnector.js.map +1 -1
  27. package/dist/src/connection/websocket/WebsocketServerConnection.d.ts +2 -1
  28. package/dist/src/connection/websocket/WebsocketServerConnection.js +4 -0
  29. package/dist/src/connection/websocket/WebsocketServerConnection.js.map +1 -1
  30. package/dist/src/dht/DhtNode.d.ts +14 -11
  31. package/dist/src/dht/DhtNode.js +74 -61
  32. package/dist/src/dht/DhtNode.js.map +1 -1
  33. package/dist/src/dht/DhtNodeRpcLocal.d.ts +3 -3
  34. package/dist/src/dht/DhtNodeRpcLocal.js +5 -2
  35. package/dist/src/dht/DhtNodeRpcLocal.js.map +1 -1
  36. package/dist/src/dht/PeerManager.d.ts +14 -14
  37. package/dist/src/dht/PeerManager.js +51 -42
  38. package/dist/src/dht/PeerManager.js.map +1 -1
  39. package/dist/src/dht/contact/ContactList.d.ts +1 -2
  40. package/dist/src/dht/contact/ContactList.js +1 -3
  41. package/dist/src/dht/contact/ContactList.js.map +1 -1
  42. package/dist/src/dht/contact/RandomContactList.d.ts +1 -1
  43. package/dist/src/dht/contact/RandomContactList.js +7 -4
  44. package/dist/src/dht/contact/RandomContactList.js.map +1 -1
  45. package/dist/src/dht/contact/getClosestNodes.d.ts +6 -0
  46. package/dist/src/dht/contact/{getClosestContacts.js → getClosestNodes.js} +7 -6
  47. package/dist/src/dht/contact/getClosestNodes.js.map +1 -0
  48. package/dist/src/dht/discovery/DiscoverySession.d.ts +4 -0
  49. package/dist/src/dht/discovery/DiscoverySession.js +27 -21
  50. package/dist/src/dht/discovery/DiscoverySession.js.map +1 -1
  51. package/dist/src/dht/discovery/PeerDiscovery.d.ts +8 -5
  52. package/dist/src/dht/discovery/PeerDiscovery.js +34 -24
  53. package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
  54. package/dist/src/dht/discovery/RingDiscoverySession.d.ts +4 -4
  55. package/dist/src/dht/discovery/RingDiscoverySession.js +10 -19
  56. package/dist/src/dht/discovery/RingDiscoverySession.js.map +1 -1
  57. package/dist/src/dht/recursive-operation/RecursiveOperationManager.d.ts +2 -0
  58. package/dist/src/dht/recursive-operation/RecursiveOperationManager.js +3 -3
  59. package/dist/src/dht/recursive-operation/RecursiveOperationManager.js.map +1 -1
  60. package/dist/src/dht/store/StoreManager.d.ts +5 -6
  61. package/dist/src/dht/store/StoreManager.js +21 -76
  62. package/dist/src/dht/store/StoreManager.js.map +1 -1
  63. package/dist/src/dht/store/StoreRpcLocal.d.ts +5 -2
  64. package/dist/src/dht/store/StoreRpcLocal.js +22 -5
  65. package/dist/src/dht/store/StoreRpcLocal.js.map +1 -1
  66. package/dist/src/exports.d.ts +2 -1
  67. package/dist/src/exports.js.map +1 -1
  68. package/dist/src/helpers/version.d.ts +1 -1
  69. package/dist/src/helpers/version.js +1 -1
  70. package/dist/src/proto/google/protobuf/any.d.ts +8 -5
  71. package/dist/src/proto/google/protobuf/any.js.map +1 -1
  72. package/dist/src/proto/google/protobuf/empty.d.ts +0 -1
  73. package/dist/src/proto/google/protobuf/empty.js.map +1 -1
  74. package/dist/src/proto/google/protobuf/timestamp.d.ts +10 -1
  75. package/dist/src/proto/google/protobuf/timestamp.js.map +1 -1
  76. package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +8 -0
  77. package/dist/src/proto/packages/dht/protos/DhtRpc.js +3 -1
  78. package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -1
  79. package/dist/src/transport/ITransport.d.ts +0 -4
  80. package/dist/src/transport/ITransport.js.map +1 -1
  81. package/karma.config.js +2 -2
  82. package/package.json +8 -9
  83. package/protos/DhtRpc.proto +2 -0
  84. package/src/connection/ConnectionManager.ts +4 -10
  85. package/src/connection/ConnectionsView.ts +8 -0
  86. package/src/connection/ConnectorFacade.ts +7 -5
  87. package/src/connection/connectivityRequestHandler.ts +18 -5
  88. package/src/connection/{ManagedWebrtcConnection.ts → webrtc/ManagedWebrtcConnection.ts} +4 -4
  89. package/src/connection/webrtc/NodeWebrtcConnection.ts +3 -3
  90. package/src/connection/webrtc/WebrtcConnector.ts +1 -1
  91. package/src/connection/webrtc/WebrtcConnectorRpcLocal.ts +1 -1
  92. package/src/connection/websocket/WebsocketConnector.ts +26 -16
  93. package/src/connection/websocket/WebsocketServerConnection.ts +6 -1
  94. package/src/dht/DhtNode.ts +102 -74
  95. package/src/dht/DhtNodeRpcLocal.ts +12 -5
  96. package/src/dht/PeerManager.ts +58 -49
  97. package/src/dht/contact/ContactList.ts +1 -4
  98. package/src/dht/contact/RandomContactList.ts +7 -5
  99. package/src/dht/contact/{getClosestContacts.ts → getClosestNodes.ts} +8 -6
  100. package/src/dht/discovery/DiscoverySession.ts +34 -22
  101. package/src/dht/discovery/PeerDiscovery.ts +44 -30
  102. package/src/dht/discovery/RingDiscoverySession.ts +15 -29
  103. package/src/dht/recursive-operation/RecursiveOperationManager.ts +5 -3
  104. package/src/dht/store/StoreManager.ts +46 -84
  105. package/src/dht/store/StoreRpcLocal.ts +32 -9
  106. package/src/exports.ts +2 -1
  107. package/src/helpers/version.ts +1 -1
  108. package/src/proto/google/protobuf/any.ts +8 -5
  109. package/src/proto/google/protobuf/empty.ts +0 -1
  110. package/src/proto/google/protobuf/timestamp.ts +10 -1
  111. package/src/proto/packages/dht/protos/DhtRpc.ts +11 -1
  112. package/src/transport/ITransport.ts +0 -4
  113. package/test/benchmark/Find.test.ts +1 -1
  114. package/test/end-to-end/GeoIpLayer0.test.ts +55 -0
  115. package/test/end-to-end/Layer0-Layer1.test.ts +4 -4
  116. package/test/end-to-end/Layer0Webrtc-Layer1.test.ts +11 -5
  117. package/test/end-to-end/Layer1-Scale-WebSocket.test.ts +7 -1
  118. package/test/end-to-end/Layer1-Scale-Webrtc.test.ts +11 -2
  119. package/test/integration/ConnectionLocking.test.ts +1 -1
  120. package/test/integration/ConnectionManager.test.ts +3 -3
  121. package/test/integration/ConnectivityChecking.test.ts +2 -2
  122. package/test/integration/DhtNode.test.ts +5 -20
  123. package/test/integration/GeoIpConnectivityChecking.test.ts +71 -0
  124. package/test/integration/Layer1-scale.test.ts +6 -6
  125. package/test/integration/RouteMessage.test.ts +4 -0
  126. package/test/integration/ScaleDownDht.test.ts +1 -1
  127. package/test/integration/SimultaneousConnections.test.ts +2 -2
  128. package/test/integration/WebrtcConnectionManagement.test.ts +1 -1
  129. package/test/integration/WebsocketConnectionManagement.test.ts +1 -1
  130. package/test/integration/rpc-connections-over-webrpc.test.ts +1 -1
  131. package/test/unit/AutoCertifierClientFacade.test.ts +1 -1
  132. package/test/unit/DiscoverySession.test.ts +4 -2
  133. package/test/unit/PeerManager.test.ts +45 -51
  134. package/test/unit/RandomContactList.test.ts +10 -0
  135. package/test/unit/RecursiveOperationManager.test.ts +4 -2
  136. package/test/unit/StoreManager.test.ts +42 -34
  137. package/test/unit/StoreRpcLocal.test.ts +167 -0
  138. package/test/unit/WebsocketConnector.test.ts +1 -1
  139. package/test/unit/connectivityRequestHandler.test.ts +1 -1
  140. package/test/unit/getClosestNodes.test.ts +30 -0
  141. package/test/utils/FakeTransport.ts +4 -2
  142. package/test/utils/mock/MockConnectionsView.ts +18 -0
  143. package/test/utils/mock/{Transport.ts → MockTransport.ts} +0 -15
  144. package/test/utils/utils.ts +4 -1
  145. package/tsconfig.jest.json +2 -1
  146. package/tsconfig.node.json +2 -1
  147. package/dist/src/connection/ManagedWebrtcConnection.js.map +0 -1
  148. package/dist/src/dht/contact/getClosestContacts.d.ts +0 -7
  149. package/dist/src/dht/contact/getClosestContacts.js.map +0 -1
  150. package/test/unit/getClosestContacts.test.ts +0 -28
  151. /package/test/utils/mock/{Router.ts → MockRouter.ts} +0 -0
@@ -3,15 +3,18 @@ import {
3
3
  Logger,
4
4
  MetricsContext,
5
5
  merge,
6
+ scheduleAtInterval,
6
7
  waitForCondition
7
8
  } from '@streamr/utils'
8
9
  import { EventEmitter } from 'eventemitter3'
9
10
  import { sample } from 'lodash'
10
11
  import { MarkRequired } from 'ts-essentials'
11
12
  import { ConnectionLocker, ConnectionManager, PortRange, TlsCertificate } from '../connection/ConnectionManager'
13
+ import { ConnectionsView } from '../connection/ConnectionsView'
12
14
  import { DefaultConnectorFacade, DefaultConnectorFacadeConfig } from '../connection/ConnectorFacade'
13
15
  import { IceServer } from '../connection/webrtc/WebrtcConnector'
14
16
  import { isBrowserEnvironment } from '../helpers/browser/isBrowserEnvironment'
17
+ import { createPeerDescriptor } from '../helpers/createPeerDescriptor'
15
18
  import { DhtAddress, KADEMLIA_ID_LENGTH_IN_BYTES, getNodeIdFromPeerDescriptor } from '../identifiers'
16
19
  import { Any } from '../proto/google/protobuf/any'
17
20
  import {
@@ -41,24 +44,24 @@ import { DhtNodeRpcRemote } from './DhtNodeRpcRemote'
41
44
  import { ExternalApiRpcLocal } from './ExternalApiRpcLocal'
42
45
  import { ExternalApiRpcRemote } from './ExternalApiRpcRemote'
43
46
  import { PeerManager } from './PeerManager'
47
+ import { RingContacts } from './contact/RingContactList'
48
+ import { RingIdRaw } from './contact/ringIdentifiers'
44
49
  import { PeerDiscovery } from './discovery/PeerDiscovery'
45
50
  import { RecursiveOperationManager } from './recursive-operation/RecursiveOperationManager'
46
51
  import { Router } from './routing/Router'
47
52
  import { LocalDataStore } from './store/LocalDataStore'
48
53
  import { StoreManager } from './store/StoreManager'
49
54
  import { StoreRpcRemote } from './store/StoreRpcRemote'
50
- import { createPeerDescriptor } from '../helpers/createPeerDescriptor'
51
- import { RingIdRaw } from './contact/ringIdentifiers'
52
- import { getLocalRegion } from '@streamr/cdn-location'
53
- import { RingContacts } from './contact/RingContactList'
55
+ import { getLocalRegionByCoordinates, getLocalRegionWithCache } from '@streamr/cdn-location'
54
56
 
55
57
  export interface DhtNodeEvents {
56
- closestContactAdded: (peerDescriptor: PeerDescriptor) => void
57
- closestContactRemoved: (peerDescriptor: PeerDescriptor) => void
58
+ nearbyContactAdded: (peerDescriptor: PeerDescriptor) => void
59
+ nearbyContactRemoved: (peerDescriptor: PeerDescriptor) => void
58
60
  randomContactAdded: (peerDescriptor: PeerDescriptor) => void
59
61
  randomContactRemoved: (peerDescriptor: PeerDescriptor) => void
60
62
  ringContactAdded: (peerDescriptor: PeerDescriptor) => void
61
63
  ringContactRemoved: (peerDescriptor: PeerDescriptor) => void
64
+ manualRejoinRequired: () => void
62
65
  }
63
66
 
64
67
  export interface DhtNodeOptions {
@@ -74,9 +77,11 @@ export interface DhtNodeOptions {
74
77
  storeMaxTtl?: number
75
78
  networkConnectivityTimeout?: number
76
79
  storageRedundancyFactor?: number
77
- region?: number
80
+ periodicallyPingNeighbors?: boolean
81
+ periodicallyPingRingContacts?: boolean
78
82
 
79
83
  transport?: ITransport
84
+ connectionsView?: ConnectionsView
80
85
  connectionLocker?: ConnectionLocker
81
86
  peerDescriptor?: PeerDescriptor
82
87
  entryPoints?: PeerDescriptor[]
@@ -84,6 +89,7 @@ export interface DhtNodeOptions {
84
89
  websocketPortRange?: PortRange
85
90
  websocketServerEnableTls?: boolean
86
91
  nodeId?: DhtAddress
92
+ region?: number
87
93
 
88
94
  rpcRequestTimeout?: number
89
95
  iceServers?: IceServer[]
@@ -98,6 +104,7 @@ export interface DhtNodeOptions {
98
104
  externalIp?: string
99
105
  autoCertifierUrl?: string
100
106
  autoCertifierConfigFile?: string
107
+ geoIpDatabaseFolder?: string
101
108
  }
102
109
 
103
110
  type StrictDhtNodeOptions = MarkRequired<DhtNodeOptions,
@@ -117,6 +124,8 @@ type StrictDhtNodeOptions = MarkRequired<DhtNodeOptions,
117
124
 
118
125
  const logger = new Logger(module)
119
126
 
127
+ const PERIODICAL_PING_INTERVAL = 60 * 1000
128
+
120
129
  export type Events = TransportEvents & DhtNodeEvents
121
130
 
122
131
  export class DhtNode extends EventEmitter<Events> implements ITransport {
@@ -125,16 +134,17 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
125
134
  private rpcCommunicator?: RoutingRpcCommunicator
126
135
  private transport?: ITransport
127
136
  private localPeerDescriptor?: PeerDescriptor
128
- public router?: Router
137
+ private router?: Router
129
138
  private storeManager?: StoreManager
130
139
  private localDataStore: LocalDataStore
131
140
  private recursiveOperationManager?: RecursiveOperationManager
132
141
  private peerDiscovery?: PeerDiscovery
133
142
  private peerManager?: PeerManager
143
+ private connectionsView?: ConnectionsView
134
144
  public connectionLocker?: ConnectionLocker
135
- private region?: number
136
145
  private started = false
137
146
  private abortController = new AbortController()
147
+
138
148
  constructor(conf: DhtNodeOptions) {
139
149
  super()
140
150
  this.config = merge({
@@ -149,7 +159,7 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
149
159
  storeHighestTtl: 60000,
150
160
  storeMaxTtl: 60000,
151
161
  networkConnectivityTimeout: 10000,
152
- storageRedundancyFactor: 5,
162
+ storageRedundancyFactor: 5, // TODO validate that this is > 1 (as each node should replicate the data to other node)
153
163
  metricsContext: new MetricsContext()
154
164
  }, conf)
155
165
  this.validateConfig()
@@ -171,6 +181,9 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
171
181
  throw new Error(`Invalid peerDescriptor, the length of the nodeId should be ${KADEMLIA_ID_LENGTH_IN_BYTES} bytes`)
172
182
  }
173
183
  }
184
+ if (this.config.transport !== undefined && this.config.connectionsView === undefined) {
185
+ throw new Error('connectionsView is required when transport is given')
186
+ }
174
187
  }
175
188
 
176
189
  public async start(): Promise<void> {
@@ -185,17 +198,12 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
185
198
  if (this.config.peerDescriptor) {
186
199
  this.config.peerDescriptor.websocket = undefined
187
200
  }
188
- }
189
- if (this.region !== undefined) {
190
- this.region = this.config.region
191
- } else if (this.config.peerDescriptor?.region !== undefined) {
192
- this.region = this.config.peerDescriptor.region
193
- } else {
194
- this.region = await getLocalRegion()
195
- }
196
-
201
+ }
202
+
203
+ // If transport is given, do not create a ConnectionManager
197
204
  if (this.config.transport) {
198
205
  this.transport = this.config.transport
206
+ this.connectionsView = this.config.connectionsView
199
207
  this.connectionLocker = this.config.connectionLocker
200
208
  this.localPeerDescriptor = this.transport.getLocalPeerDescriptor()
201
209
  } else {
@@ -214,7 +222,8 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
214
222
  externalIp: this.config.externalIp,
215
223
  autoCertifierUrl: this.config.autoCertifierUrl,
216
224
  autoCertifierConfigFile: this.config.autoCertifierConfigFile,
217
- createLocalPeerDescriptor: (connectivityResponse: ConnectivityResponse) => this.generatePeerDescriptorCallBack(connectivityResponse),
225
+ geoIpDatabaseFolder: this.config.geoIpDatabaseFolder,
226
+ createLocalPeerDescriptor: (connectivityResponse: ConnectivityResponse) => this.generatePeerDescriptorCallBack(connectivityResponse)
218
227
  }
219
228
  // If own PeerDescriptor is given in config, create a ConnectionManager with ws server
220
229
  if (this.config.peerDescriptor?.websocket) {
@@ -235,6 +244,7 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
235
244
  metricsContext: this.config.metricsContext
236
245
  })
237
246
  await connectionManager.start()
247
+ this.connectionsView = connectionManager
238
248
  this.connectionLocker = connectionManager
239
249
  this.transport = connectionManager
240
250
  }
@@ -256,18 +266,21 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
256
266
  serviceId: this.config.serviceId,
257
267
  parallelism: this.config.joinParallelism,
258
268
  connectionLocker: this.connectionLocker,
259
- peerManager: this.peerManager!
269
+ peerManager: this.peerManager!,
270
+ abortSignal: this.abortController.signal,
271
+ createDhtNodeRpcRemote: (peerDescriptor: PeerDescriptor) => this.createDhtNodeRpcRemote(peerDescriptor),
260
272
  })
261
273
  this.router = new Router({
262
274
  rpcCommunicator: this.rpcCommunicator,
263
275
  localPeerDescriptor: this.localPeerDescriptor!,
264
276
  handleMessage: (message: Message) => this.handleMessageFromRouter(message),
265
- getConnections: () => this.getConnections()
277
+ getConnections: () => this.connectionsView!.getConnections()
266
278
  })
267
279
  this.recursiveOperationManager = new RecursiveOperationManager({
268
280
  rpcCommunicator: this.rpcCommunicator,
269
281
  router: this.router,
270
282
  sessionTransport: this,
283
+ connectionsView: this.connectionsView!,
271
284
  localPeerDescriptor: this.localPeerDescriptor!,
272
285
  serviceId: this.config.serviceId,
273
286
  localDataStore: this.localDataStore,
@@ -282,9 +295,7 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
282
295
  highestTtl: this.config.storeHighestTtl,
283
296
  redundancyFactor: this.config.storageRedundancyFactor,
284
297
  localDataStore: this.localDataStore,
285
- getClosestNeighborsTo: (key: DhtAddress, n?: number) => {
286
- return this.peerManager!.getClosestNeighborsTo(key, n).map((n) => n.getPeerDescriptor())
287
- },
298
+ getNeighbors: () => this.peerManager!.getNeighbors().map((n) => n.getPeerDescriptor()),
288
299
  createRpcRemote: (contact: PeerDescriptor) => {
289
300
  return new StoreRpcRemote(
290
301
  this.localPeerDescriptor!,
@@ -295,10 +306,26 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
295
306
  )
296
307
  }
297
308
  })
298
- this.on('closestContactAdded', (peerDescriptor: PeerDescriptor) => {
309
+ this.on('nearbyContactAdded', (peerDescriptor: PeerDescriptor) => {
299
310
  this.storeManager!.onContactAdded(peerDescriptor)
300
311
  })
301
312
  this.bindRpcLocalMethods()
313
+
314
+ const pruneTargets = []
315
+ if (this.config.periodicallyPingNeighbors === true) {
316
+ pruneTargets.push(() => this.peerManager!.getNeighbors().map((node) => this.createDhtNodeRpcRemote(node.getPeerDescriptor())))
317
+ }
318
+ if (this.config.periodicallyPingRingContacts === true) {
319
+ pruneTargets.push(() => this.peerManager!.getRingContacts().getAllContacts())
320
+ }
321
+ for (const pruneTarget of pruneTargets) {
322
+ await scheduleAtInterval(
323
+ async () => {
324
+ const nodes = pruneTarget()
325
+ await this.peerManager!.pruneOfflineNodes(nodes)
326
+ }, PERIODICAL_PING_INTERVAL, false, this.abortController.signal
327
+ )
328
+ }
302
329
  }
303
330
 
304
331
  private initPeerManager() {
@@ -310,13 +337,13 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
310
337
  connectionLocker: this.connectionLocker,
311
338
  lockId: this.config.serviceId,
312
339
  createDhtNodeRpcRemote: (peerDescriptor: PeerDescriptor) => this.createDhtNodeRpcRemote(peerDescriptor),
313
- hasConnection: (nodeId: DhtAddress) => this.transport!.hasConnection(nodeId)
340
+ hasConnection: (nodeId: DhtAddress) => this.connectionsView!.hasConnection(nodeId)
314
341
  })
315
- this.peerManager.on('closestContactRemoved', (peerDescriptor: PeerDescriptor) => {
316
- this.emit('closestContactRemoved', peerDescriptor)
342
+ this.peerManager.on('nearbyContactRemoved', (peerDescriptor: PeerDescriptor) => {
343
+ this.emit('nearbyContactRemoved', peerDescriptor)
317
344
  })
318
- this.peerManager.on('closestContactAdded', (peerDescriptor: PeerDescriptor) =>
319
- this.emit('closestContactAdded', peerDescriptor)
345
+ this.peerManager.on('nearbyContactAdded', (peerDescriptor: PeerDescriptor) =>
346
+ this.emit('nearbyContactAdded', peerDescriptor)
320
347
  )
321
348
  this.peerManager.on('randomContactRemoved', (peerDescriptor: PeerDescriptor) =>
322
349
  this.emit('randomContactRemoved', peerDescriptor)
@@ -331,18 +358,19 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
331
358
  this.emit('ringContactAdded', peerDescriptor)
332
359
  })
333
360
  this.peerManager.on('kBucketEmpty', () => {
334
- if (!this.peerDiscovery!.isJoinOngoing()
335
- && this.config.entryPoints
336
- && this.config.entryPoints.length > 0
337
- ) {
338
- setImmediate(async () => {
339
- const contactedPeers = new Set<DhtAddress>()
340
- const distantJoinContactPeers = new Set<DhtAddress>()
341
- // TODO should we catch possible promise rejection?
342
- await Promise.all(this.config.entryPoints!.map((entryPoint) =>
343
- this.peerDiscovery!.rejoinDht(entryPoint, contactedPeers, distantJoinContactPeers)
344
- ))
345
- })
361
+ if (!this.peerDiscovery!.isJoinOngoing()) {
362
+ if (this.config.entryPoints && this.config.entryPoints.length > 0) {
363
+ setImmediate(async () => {
364
+ const contactedPeers = new Set<DhtAddress>()
365
+ const distantJoinContactPeers = new Set<DhtAddress>()
366
+ // TODO should we catch possible promise rejection?
367
+ await Promise.all(this.config.entryPoints!.map((entryPoint) =>
368
+ this.peerDiscovery!.rejoinDht(entryPoint, contactedPeers, distantJoinContactPeers)
369
+ ))
370
+ })
371
+ } else {
372
+ this.emit('manualRejoinRequired')
373
+ }
346
374
  }
347
375
  })
348
376
  this.transport!.on('connected', (peerDescriptor: PeerDescriptor) => {
@@ -370,10 +398,7 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
370
398
  }
371
399
  const dhtNodeRpcLocal = new DhtNodeRpcLocal({
372
400
  peerDiscoveryQueryBatchSize: this.config.peerDiscoveryQueryBatchSize,
373
- getClosestNeighborsTo: (nodeId: DhtAddress, limit: number) => {
374
- return this.peerManager!.getClosestNeighborsTo(nodeId, limit)
375
- .map((dhtPeer: DhtNodeRpcRemote) => dhtPeer.getPeerDescriptor())
376
- },
401
+ getNeighbors: () => this.peerManager!.getNeighbors().map((n) => n.getPeerDescriptor()),
377
402
  getClosestRingContactsTo: (ringIdRaw: RingIdRaw, limit: number) => {
378
403
  return this.getClosestRingContactsTo(ringIdRaw, limit)
379
404
  },
@@ -424,24 +449,37 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
424
449
  }
425
450
  }
426
451
 
427
- private generatePeerDescriptorCallBack(connectivityResponse: ConnectivityResponse) {
452
+ private async generatePeerDescriptorCallBack(connectivityResponse: ConnectivityResponse) {
428
453
  if (this.config.peerDescriptor !== undefined) {
429
454
  this.localPeerDescriptor = this.config.peerDescriptor
430
455
  } else {
431
- this.localPeerDescriptor = createPeerDescriptor(connectivityResponse, this.region!, this.config.nodeId)
456
+ let region: number | undefined = undefined
457
+ if (this.config.region !== undefined) {
458
+ region = this.config.region
459
+ logger.debug(`Using region ${region} from config when generating local PeerDescriptor`)
460
+ } else if (connectivityResponse.latitude !== undefined && connectivityResponse.longitude !== undefined) {
461
+ region = getLocalRegionByCoordinates(connectivityResponse.latitude, connectivityResponse.longitude)
462
+ logger.debug(`Using region ${region} from GeoIP when generating local PeerDescriptor`)
463
+ } else {
464
+ // as a fallback get the region from the CDN
465
+ // and if it's not available, use a random region
466
+ region = await getLocalRegionWithCache()
467
+ logger.debug(`Using region ${region} from CDN when generating local PeerDescriptor`)
468
+ }
469
+
470
+ this.localPeerDescriptor = createPeerDescriptor(connectivityResponse, region, this.config.nodeId)
432
471
  }
433
472
  return this.localPeerDescriptor
434
473
  }
435
474
 
436
475
  public getClosestContacts(limit?: number): PeerDescriptor[] {
437
- return this.peerManager!.getClosestContacts()
476
+ return this.peerManager!.getNearbyContacts()
438
477
  .getClosestContacts(limit)
439
478
  .map((peer) => peer.getPeerDescriptor())
440
479
  }
441
480
 
442
- // TODO remove defaultContactQueryLimit parameter from RandomContactList#getContacts and use explicit value here?
443
- getRandomContacts(): PeerDescriptor[] {
444
- return this.peerManager!.getRandomContacts().getContacts().map((c) => c.getPeerDescriptor())
481
+ getRandomContacts(limit?: number): PeerDescriptor[] {
482
+ return this.peerManager!.getRandomContacts().getContacts(limit).map((c) => c.getPeerDescriptor())
445
483
  }
446
484
 
447
485
  getRingContacts(): RingContacts {
@@ -485,7 +523,7 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
485
523
 
486
524
  private getConnectedEntryPoints(): PeerDescriptor[] {
487
525
  return this.config.entryPoints !== undefined ? this.config.entryPoints.filter((entryPoint) =>
488
- this.transport!.hasConnection(getNodeIdFromPeerDescriptor(entryPoint))
526
+ this.connectionsView!.hasConnection(getNodeIdFromPeerDescriptor(entryPoint))
489
527
  ) : []
490
528
  }
491
529
 
@@ -560,19 +598,11 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
560
598
  }
561
599
 
562
600
  public getNeighbors(): PeerDescriptor[] {
563
- return this.started ? this.peerManager!.getNeighbors() : []
564
- }
565
-
566
- public getConnections(): PeerDescriptor[] {
567
- return this.transport!.getConnections()
568
- }
569
-
570
- public getConnectionCount(): number {
571
- return this.transport!.getConnectionCount()
601
+ return this.started ? this.peerManager!.getNeighbors().map((remote: DhtNodeRpcRemote) => remote.getPeerDescriptor()) : []
572
602
  }
573
603
 
574
- public hasConnection(nodeId: DhtAddress): boolean {
575
- return this.transport!.hasConnection(nodeId)
604
+ getConnectionsView(): ConnectionsView {
605
+ return this.connectionsView!
576
606
  }
577
607
 
578
608
  public getLocalLockedConnectionCount(): number {
@@ -586,15 +616,14 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
586
616
  public getWeakLockedConnectionCount(): number {
587
617
  return this.connectionLocker!.getWeakLockedConnectionCount()
588
618
  }
589
-
619
+
590
620
  public async waitForNetworkConnectivity(): Promise<void> {
591
- await waitForCondition(() => {
592
- if (!this.peerManager) {
593
- return false
594
- } else {
595
- return (this.getConnectionCount() > 0)
596
- }
597
- }, this.config.networkConnectivityTimeout, 100, this.abortController.signal)
621
+ await waitForCondition(
622
+ () => this.connectionsView!.getConnectionCount() > 0,
623
+ this.config.networkConnectivityTimeout,
624
+ 100,
625
+ this.abortController.signal
626
+ )
598
627
  }
599
628
 
600
629
  public hasJoined(): boolean {
@@ -613,7 +642,6 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
613
642
  this.rpcCommunicator!.stop()
614
643
  this.router!.stop()
615
644
  this.recursiveOperationManager!.stop()
616
- this.peerDiscovery!.stop()
617
645
  if (this.config.transport === undefined) {
618
646
  // if the transport was not given in config, the instance was created in start() and
619
647
  // this component is responsible for stopping it
@@ -1,5 +1,6 @@
1
1
  import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
2
2
  import { Logger } from '@streamr/utils'
3
+ import { DhtAddress, getDhtAddressFromRaw, getNodeIdFromPeerDescriptor } from '../identifiers'
3
4
  import { Empty } from '../proto/google/protobuf/empty'
4
5
  import {
5
6
  ClosestPeersRequest,
@@ -12,13 +13,13 @@ import {
12
13
  } from '../proto/packages/dht/protos/DhtRpc'
13
14
  import { IDhtNodeRpc } from '../proto/packages/dht/protos/DhtRpc.server'
14
15
  import { DhtCallContext } from '../rpc-protocol/DhtCallContext'
15
- import { DhtAddress, getDhtAddressFromRaw, getNodeIdFromPeerDescriptor } from '../identifiers'
16
- import { RingIdRaw } from './contact/ringIdentifiers'
17
16
  import { RingContacts } from './contact/RingContactList'
17
+ import { getClosestNodes } from './contact/getClosestNodes'
18
+ import { RingIdRaw } from './contact/ringIdentifiers'
18
19
 
19
20
  interface DhtNodeRpcLocalConfig {
20
21
  peerDiscoveryQueryBatchSize: number
21
- getClosestNeighborsTo: (nodeId: DhtAddress, limit: number) => PeerDescriptor[]
22
+ getNeighbors: () => ReadonlyArray<PeerDescriptor>
22
23
  getClosestRingContactsTo: (id: RingIdRaw, limit: number) => RingContacts
23
24
  addContact: (contact: PeerDescriptor) => void
24
25
  removeContact: (nodeId: DhtAddress) => void
@@ -34,16 +35,22 @@ export class DhtNodeRpcLocal implements IDhtNodeRpc {
34
35
  this.config = config
35
36
  }
36
37
 
38
+ // TODO rename to getClosestNeighbors (breaking change)
37
39
  async getClosestPeers(request: ClosestPeersRequest, context: ServerCallContext): Promise<ClosestPeersResponse> {
38
40
  this.config.addContact((context as DhtCallContext).incomingSourceDescriptor!)
41
+ const peers = getClosestNodes(
42
+ getDhtAddressFromRaw(request.nodeId),
43
+ this.config.getNeighbors(),
44
+ { maxCount: this.config.peerDiscoveryQueryBatchSize }
45
+ )
39
46
  const response = {
40
- peers: this.config.getClosestNeighborsTo(getDhtAddressFromRaw(request.nodeId), this.config.peerDiscoveryQueryBatchSize),
47
+ peers,
41
48
  requestId: request.requestId
42
49
  }
43
50
  return response
44
51
  }
45
52
 
46
- // TODO rename to getClosestRingContacts
53
+ // TODO rename to getClosestRingContacts (breaking change)
47
54
  async getClosestRingPeers(request: ClosestRingPeersRequest, context: ServerCallContext): Promise<ClosestRingPeersResponse> {
48
55
  this.config.addContact((context as DhtCallContext).incomingSourceDescriptor!)
49
56
  const closestContacts = this.config.getClosestRingContactsTo(request.ringId as RingIdRaw, this.config.peerDiscoveryQueryBatchSize)