@streamr/dht 100.2.4-beta.0 → 100.2.5-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) 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/connectivityChecker.d.ts +3 -3
  12. package/dist/src/connection/connectivityChecker.js +3 -3
  13. package/dist/src/connection/connectivityChecker.js.map +1 -1
  14. package/dist/src/connection/connectivityRequestHandler.d.ts +2 -1
  15. package/dist/src/connection/connectivityRequestHandler.js +13 -6
  16. package/dist/src/connection/connectivityRequestHandler.js.map +1 -1
  17. package/dist/src/connection/{ManagedWebrtcConnection.d.ts → webrtc/ManagedWebrtcConnection.d.ts} +3 -3
  18. package/dist/src/connection/{ManagedWebrtcConnection.js → webrtc/ManagedWebrtcConnection.js} +2 -2
  19. package/dist/src/connection/webrtc/ManagedWebrtcConnection.js.map +1 -0
  20. package/dist/src/connection/webrtc/NodeWebrtcConnection.js +3 -26
  21. package/dist/src/connection/webrtc/NodeWebrtcConnection.js.map +1 -1
  22. package/dist/src/connection/webrtc/WebrtcConnector.js +1 -1
  23. package/dist/src/connection/webrtc/WebrtcConnector.js.map +1 -1
  24. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.d.ts +1 -1
  25. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js +1 -1
  26. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js.map +1 -1
  27. package/dist/src/connection/websocket/AbstractWebsocketClientConnection.d.ts +1 -1
  28. package/dist/src/connection/websocket/WebsocketConnector.d.ts +3 -1
  29. package/dist/src/connection/websocket/WebsocketConnector.js +26 -18
  30. package/dist/src/connection/websocket/WebsocketConnector.js.map +1 -1
  31. package/dist/src/connection/websocket/WebsocketServerConnection.d.ts +2 -1
  32. package/dist/src/connection/websocket/WebsocketServerConnection.js +4 -0
  33. package/dist/src/connection/websocket/WebsocketServerConnection.js.map +1 -1
  34. package/dist/src/dht/DhtNode.d.ts +14 -11
  35. package/dist/src/dht/DhtNode.js +74 -61
  36. package/dist/src/dht/DhtNode.js.map +1 -1
  37. package/dist/src/dht/DhtNodeRpcLocal.d.ts +3 -3
  38. package/dist/src/dht/DhtNodeRpcLocal.js +5 -2
  39. package/dist/src/dht/DhtNodeRpcLocal.js.map +1 -1
  40. package/dist/src/dht/PeerManager.d.ts +14 -14
  41. package/dist/src/dht/PeerManager.js +51 -42
  42. package/dist/src/dht/PeerManager.js.map +1 -1
  43. package/dist/src/dht/contact/ContactList.d.ts +1 -2
  44. package/dist/src/dht/contact/ContactList.js +1 -3
  45. package/dist/src/dht/contact/ContactList.js.map +1 -1
  46. package/dist/src/dht/contact/RandomContactList.d.ts +1 -1
  47. package/dist/src/dht/contact/RandomContactList.js +7 -4
  48. package/dist/src/dht/contact/RandomContactList.js.map +1 -1
  49. package/dist/src/dht/contact/getClosestNodes.d.ts +6 -0
  50. package/dist/src/dht/contact/{getClosestContacts.js → getClosestNodes.js} +7 -6
  51. package/dist/src/dht/contact/getClosestNodes.js.map +1 -0
  52. package/dist/src/dht/discovery/DiscoverySession.d.ts +4 -0
  53. package/dist/src/dht/discovery/DiscoverySession.js +27 -21
  54. package/dist/src/dht/discovery/DiscoverySession.js.map +1 -1
  55. package/dist/src/dht/discovery/PeerDiscovery.d.ts +8 -5
  56. package/dist/src/dht/discovery/PeerDiscovery.js +34 -24
  57. package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
  58. package/dist/src/dht/discovery/RingDiscoverySession.d.ts +4 -4
  59. package/dist/src/dht/discovery/RingDiscoverySession.js +10 -19
  60. package/dist/src/dht/discovery/RingDiscoverySession.js.map +1 -1
  61. package/dist/src/dht/recursive-operation/RecursiveOperationManager.d.ts +2 -0
  62. package/dist/src/dht/recursive-operation/RecursiveOperationManager.js +3 -3
  63. package/dist/src/dht/recursive-operation/RecursiveOperationManager.js.map +1 -1
  64. package/dist/src/dht/store/StoreManager.d.ts +5 -6
  65. package/dist/src/dht/store/StoreManager.js +21 -76
  66. package/dist/src/dht/store/StoreManager.js.map +1 -1
  67. package/dist/src/dht/store/StoreRpcLocal.d.ts +5 -2
  68. package/dist/src/dht/store/StoreRpcLocal.js +22 -5
  69. package/dist/src/dht/store/StoreRpcLocal.js.map +1 -1
  70. package/dist/src/exports.d.ts +2 -1
  71. package/dist/src/exports.js.map +1 -1
  72. package/dist/src/helpers/version.d.ts +1 -1
  73. package/dist/src/helpers/version.js +1 -1
  74. package/dist/src/proto/google/protobuf/any.d.ts +8 -5
  75. package/dist/src/proto/google/protobuf/any.js.map +1 -1
  76. package/dist/src/proto/google/protobuf/empty.d.ts +0 -1
  77. package/dist/src/proto/google/protobuf/empty.js.map +1 -1
  78. package/dist/src/proto/google/protobuf/timestamp.d.ts +10 -1
  79. package/dist/src/proto/google/protobuf/timestamp.js.map +1 -1
  80. package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +10 -2
  81. package/dist/src/proto/packages/dht/protos/DhtRpc.js +4 -2
  82. package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -1
  83. package/dist/src/transport/ITransport.d.ts +0 -4
  84. package/dist/src/transport/ITransport.js.map +1 -1
  85. package/karma.config.js +2 -2
  86. package/package.json +8 -9
  87. package/protos/DhtRpc.proto +3 -1
  88. package/src/connection/ConnectionManager.ts +4 -10
  89. package/src/connection/ConnectionsView.ts +8 -0
  90. package/src/connection/ConnectorFacade.ts +7 -5
  91. package/src/connection/connectivityChecker.ts +4 -4
  92. package/src/connection/connectivityRequestHandler.ts +19 -6
  93. package/src/connection/{ManagedWebrtcConnection.ts → webrtc/ManagedWebrtcConnection.ts} +4 -4
  94. package/src/connection/webrtc/NodeWebrtcConnection.ts +3 -3
  95. package/src/connection/webrtc/WebrtcConnector.ts +1 -1
  96. package/src/connection/webrtc/WebrtcConnectorRpcLocal.ts +3 -3
  97. package/src/connection/websocket/AbstractWebsocketClientConnection.ts +1 -1
  98. package/src/connection/websocket/WebsocketConnector.ts +33 -21
  99. package/src/connection/websocket/WebsocketServerConnection.ts +6 -1
  100. package/src/dht/DhtNode.ts +102 -74
  101. package/src/dht/DhtNodeRpcLocal.ts +12 -5
  102. package/src/dht/PeerManager.ts +58 -49
  103. package/src/dht/contact/ContactList.ts +1 -4
  104. package/src/dht/contact/RandomContactList.ts +7 -5
  105. package/src/dht/contact/{getClosestContacts.ts → getClosestNodes.ts} +8 -6
  106. package/src/dht/discovery/DiscoverySession.ts +34 -22
  107. package/src/dht/discovery/PeerDiscovery.ts +44 -30
  108. package/src/dht/discovery/RingDiscoverySession.ts +15 -29
  109. package/src/dht/recursive-operation/RecursiveOperationManager.ts +5 -3
  110. package/src/dht/store/StoreManager.ts +46 -84
  111. package/src/dht/store/StoreRpcLocal.ts +32 -9
  112. package/src/exports.ts +2 -1
  113. package/src/helpers/version.ts +1 -1
  114. package/src/proto/google/protobuf/any.ts +8 -5
  115. package/src/proto/google/protobuf/empty.ts +0 -1
  116. package/src/proto/google/protobuf/timestamp.ts +10 -1
  117. package/src/proto/packages/dht/protos/DhtRpc.ts +14 -4
  118. package/src/transport/ITransport.ts +0 -4
  119. package/test/benchmark/Find.test.ts +1 -1
  120. package/test/benchmark/WebsocketServerMemoryLeak.test.ts +1 -1
  121. package/test/end-to-end/GeoIpLayer0.test.ts +55 -0
  122. package/test/end-to-end/Layer0-Layer1.test.ts +4 -4
  123. package/test/end-to-end/Layer0Webrtc-Layer1.test.ts +11 -5
  124. package/test/end-to-end/Layer1-Scale-WebSocket.test.ts +7 -1
  125. package/test/end-to-end/Layer1-Scale-Webrtc.test.ts +11 -2
  126. package/test/integration/ConnectionLocking.test.ts +1 -1
  127. package/test/integration/ConnectionManager.test.ts +3 -3
  128. package/test/integration/ConnectivityChecking.test.ts +3 -3
  129. package/test/integration/DhtNode.test.ts +5 -20
  130. package/test/integration/GeoIpConnectivityChecking.test.ts +71 -0
  131. package/test/integration/Layer1-scale.test.ts +6 -6
  132. package/test/integration/RouteMessage.test.ts +4 -0
  133. package/test/integration/ScaleDownDht.test.ts +1 -1
  134. package/test/integration/SimultaneousConnections.test.ts +2 -2
  135. package/test/integration/WebrtcConnectionManagement.test.ts +1 -1
  136. package/test/integration/Websocket.test.ts +1 -1
  137. package/test/integration/WebsocketConnectionManagement.test.ts +1 -1
  138. package/test/integration/rpc-connections-over-webrpc.test.ts +1 -1
  139. package/test/unit/AutoCertifierClientFacade.test.ts +1 -1
  140. package/test/unit/DiscoverySession.test.ts +4 -2
  141. package/test/unit/PeerManager.test.ts +45 -51
  142. package/test/unit/RandomContactList.test.ts +10 -0
  143. package/test/unit/RecursiveOperationManager.test.ts +4 -2
  144. package/test/unit/StoreManager.test.ts +42 -34
  145. package/test/unit/StoreRpcLocal.test.ts +167 -0
  146. package/test/unit/WebsocketConnector.test.ts +1 -1
  147. package/test/unit/connectivityRequestHandler.test.ts +3 -3
  148. package/test/unit/getClosestNodes.test.ts +30 -0
  149. package/test/utils/FakeTransport.ts +4 -2
  150. package/test/utils/mock/MockConnectionsView.ts +18 -0
  151. package/test/utils/mock/{Transport.ts → MockTransport.ts} +0 -15
  152. package/test/utils/utils.ts +4 -1
  153. package/tsconfig.jest.json +2 -1
  154. package/tsconfig.node.json +2 -1
  155. package/dist/src/connection/ManagedWebrtcConnection.js.map +0 -1
  156. package/dist/src/dht/contact/getClosestContacts.d.ts +0 -7
  157. package/dist/src/dht/contact/getClosestContacts.js.map +0 -1
  158. package/test/unit/getClosestContacts.test.ts +0 -28
  159. /package/test/utils/mock/{Router.ts → MockRouter.ts} +0 -0
package/karma.config.js CHANGED
@@ -4,8 +4,8 @@ const { createKarmaConfig, createWebpackConfig } = require('@streamr/browser-tes
4
4
 
5
5
  const TEST_PATHS = [
6
6
  'test/unit/**/!(connectivityRequestHandler*).ts',
7
- './test/integration/**/!(DhtWith*|ReplicateData*).ts/',
8
- './test/end-to-end/**/!(RecoveryFromFailedAutoCertification*|memory-leak*).ts'
7
+ './test/integration/**/!(DhtWith*|ReplicateData*|GeoIpConnectivityChecking*).ts/',
8
+ './test/end-to-end/**/!(RecoveryFromFailedAutoCertification*|memory-leak*|GeoIpLayer0*).ts'
9
9
  ]
10
10
 
11
11
  const NodeWebrtcConnection = path.resolve(__dirname, 'src/connection/webrtc/NodeWebrtcConnection.ts')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamr/dht",
3
- "version": "100.2.4-beta.0",
3
+ "version": "100.2.5-beta.0",
4
4
  "description": "Streamr Network DHT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,17 +29,18 @@
29
29
  "@js-sdsl/ordered-map": "^4.4.2",
30
30
  "@protobuf-ts/runtime": "^2.8.2",
31
31
  "@protobuf-ts/runtime-rpc": "^2.8.2",
32
- "@streamr/autocertifier-client": "100.2.4-beta.0",
33
- "@streamr/cdn-location": "100.2.4-beta.0",
34
- "@streamr/proto-rpc": "100.2.4-beta.0",
35
- "@streamr/utils": "100.2.4-beta.0",
32
+ "@streamr/autocertifier-client": "100.2.5-beta.0",
33
+ "@streamr/cdn-location": "100.2.5-beta.0",
34
+ "@streamr/geoip-location": "100.2.5-beta.0",
35
+ "@streamr/proto-rpc": "100.2.5-beta.0",
36
+ "@streamr/utils": "100.2.5-beta.0",
36
37
  "eventemitter3": "^5.0.0",
37
38
  "heap": "^0.2.6",
38
39
  "ipaddr.js": "^2.0.1",
39
40
  "k-bucket": "^5.1.0",
40
41
  "lodash": "^4.17.21",
41
42
  "lru-cache": "10.2.0",
42
- "node-datachannel": "^0.4.3",
43
+ "node-datachannel": "^0.8.0",
43
44
  "querystring": "0.2.1",
44
45
  "uuid": "^9.0.1",
45
46
  "websocket": "^1.0.34",
@@ -47,15 +48,13 @@
47
48
  },
48
49
  "devDependencies": {
49
50
  "@streamr/browser-test-runner": "^0.0.1",
50
- "@streamr/test-utils": "100.2.4-beta.0",
51
- "@types/express": "^4.17.21",
51
+ "@streamr/test-utils": "100.2.5-beta.0",
52
52
  "@types/heap": "^0.2.34",
53
53
  "@types/k-bucket": "^5.0.1",
54
54
  "@types/lodash": "^4.14.202",
55
55
  "@types/uuid": "^9.0.8",
56
56
  "@types/websocket": "^1.0.10",
57
57
  "@types/ws": "^8.5.10",
58
- "express": "^4.19.2",
59
58
  "jest-leak-detector": "^27.3.1",
60
59
  "patch-package": "^8.0.0",
61
60
  "ts-essentials": "^9.4.1",
@@ -206,7 +206,7 @@ message ConnectivityRequest {
206
206
  uint32 port = 1;
207
207
  bool tls = 2;
208
208
  optional string host = 3;
209
- bool selfSigned = 4;
209
+ bool allowSelfSignedCertificate = 4;
210
210
  }
211
211
 
212
212
  message ConnectivityResponse {
@@ -215,6 +215,8 @@ message ConnectivityResponse {
215
215
  ConnectivityMethod websocket = 3;
216
216
  uint32 ipAddress = 4;
217
217
  string version = 5;
218
+ optional double latitude = 6;
219
+ optional double longitude = 7;
218
220
  }
219
221
 
220
222
  message HandshakeRequest {
@@ -24,6 +24,7 @@ import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
24
24
  import { ConnectionLockRpcLocal } from './ConnectionLockRpcLocal'
25
25
  import { DhtAddress, areEqualPeerDescriptors, getNodeIdFromPeerDescriptor } from '../identifiers'
26
26
  import { getOfferer } from '../helpers/offering'
27
+ import { ConnectionsView } from './ConnectionsView'
27
28
 
28
29
  export interface ConnectionManagerConfig {
29
30
  maxConnections?: number
@@ -93,7 +94,7 @@ export const getNodeIdOrUnknownFromPeerDescriptor = (peerDescriptor: PeerDescrip
93
94
  }
94
95
  }
95
96
 
96
- export class ConnectionManager extends EventEmitter<TransportEvents> implements ITransport, ConnectionLocker {
97
+ export class ConnectionManager extends EventEmitter<TransportEvents> implements ITransport, ConnectionsView, ConnectionLocker {
97
98
 
98
99
  private config: ConnectionManagerConfig
99
100
  private readonly metricsContext: MetricsContext
@@ -158,15 +159,8 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
158
159
  maxSize: 100000, // TODO use config option or named constant?
159
160
  allowToContainReferenceId: false
160
161
  })
161
- this.connections.forEach((connection, key) => {
162
- // TODO: Investigate why multiple invalid WS client connections to the same
163
- // server with a different nodeId can remain in the this.connections map.
164
- // Seems to only happen if the ConnectionManager acting as client is not running a WS server itself.
165
- if (connection.getPeerDescriptor() !== undefined && !this.hasConnection(getNodeIdFromPeerDescriptor(connection.getPeerDescriptor()!))) {
166
- logger.trace(`Attempting to disconnect a hanging connection to ${getNodeIdFromPeerDescriptor(connection.getPeerDescriptor()!)}`)
167
- connection.close(false).catch(() => {})
168
- this.connections.delete(key)
169
- } else if (!this.locks.isLocked(connection.getNodeId()) && Date.now() - connection.getLastUsedTimestamp() > maxIdleTime) {
162
+ this.connections.forEach((connection) => {
163
+ if (!this.locks.isLocked(connection.getNodeId()) && Date.now() - connection.getLastUsedTimestamp() > maxIdleTime) {
170
164
  logger.trace('disconnecting in timeout interval: ' + getNodeIdOrUnknownFromPeerDescriptor(connection.getPeerDescriptor()))
171
165
  disconnectionCandidates.addContact(connection)
172
166
  }
@@ -0,0 +1,8 @@
1
+ import { DhtAddress } from '../identifiers'
2
+ import { PeerDescriptor } from '../proto/packages/dht/protos/DhtRpc'
3
+
4
+ export interface ConnectionsView {
5
+ getConnections: () => PeerDescriptor[]
6
+ getConnectionCount: () => number
7
+ hasConnection: (nodeId: DhtAddress) => boolean
8
+ }
@@ -44,7 +44,8 @@ export interface DefaultConnectorFacadeConfig {
44
44
  websocketServerEnableTls?: boolean
45
45
  autoCertifierUrl?: string
46
46
  autoCertifierConfigFile?: string
47
- createLocalPeerDescriptor: (connectivityResponse: ConnectivityResponse) => PeerDescriptor
47
+ geoIpDatabaseFolder?: string
48
+ createLocalPeerDescriptor: (connectivityResponse: ConnectivityResponse) => Promise<PeerDescriptor>
48
49
  }
49
50
 
50
51
  export class DefaultConnectorFacade implements ConnectorFacade {
@@ -76,7 +77,8 @@ export class DefaultConnectorFacade implements ConnectorFacade {
76
77
  autoCertifierUrl: this.config.autoCertifierUrl!,
77
78
  autoCertifierConfigFile: this.config.autoCertifierConfigFile!,
78
79
  autoCertifierTransport,
79
- maxMessageSize: this.config.maxMessageSize
80
+ maxMessageSize: this.config.maxMessageSize,
81
+ geoIpDatabaseFolder: this.config.geoIpDatabaseFolder
80
82
  }
81
83
  this.websocketConnector = new WebsocketConnector(webSocketConnectorConfig)
82
84
  logger.trace(`Creating WebRtcConnectorRpcLocal`)
@@ -98,13 +100,13 @@ export class DefaultConnectorFacade implements ConnectorFacade {
98
100
  // LocalPeerDescriptor could be stored in one place and passed from there to the connectors
99
101
  const temporarilySelfSigned = (!this.config.tlsCertificate && this.config.websocketServerEnableTls === true)
100
102
  const connectivityResponse = await this.websocketConnector.checkConnectivity(temporarilySelfSigned)
101
- const localPeerDescriptor = this.config.createLocalPeerDescriptor(connectivityResponse)
103
+ const localPeerDescriptor = await this.config.createLocalPeerDescriptor(connectivityResponse)
102
104
  this.setLocalPeerDescriptor(localPeerDescriptor)
103
105
  if (localPeerDescriptor.websocket && !this.config.tlsCertificate && this.config.websocketServerEnableTls) {
104
106
  try {
105
107
  await this.websocketConnector.autoCertify()
106
108
  const connectivityResponse = await this.websocketConnector.checkConnectivity(false)
107
- const autocertifiedLocalPeerDescriptor = this.config.createLocalPeerDescriptor(connectivityResponse)
109
+ const autocertifiedLocalPeerDescriptor = await this.config.createLocalPeerDescriptor(connectivityResponse)
108
110
  if (autocertifiedLocalPeerDescriptor.websocket !== undefined) {
109
111
  this.setLocalPeerDescriptor(autocertifiedLocalPeerDescriptor)
110
112
  } else {
@@ -135,7 +137,7 @@ export class DefaultConnectorFacade implements ConnectorFacade {
135
137
  this.websocketConnector = new WebsocketConnector(webSocketConnectorConfig)
136
138
  await this.websocketConnector.start()
137
139
  const connectivityResponse = await this.websocketConnector.checkConnectivity(false)
138
- const localPeerDescriptor = this.config.createLocalPeerDescriptor(connectivityResponse)
140
+ const localPeerDescriptor = await this.config.createLocalPeerDescriptor(connectivityResponse)
139
141
  this.setLocalPeerDescriptor(localPeerDescriptor)
140
142
  }
141
143
 
@@ -13,14 +13,14 @@ import { isMaybeSupportedVersion } from '../helpers/version'
13
13
  const logger = new Logger(module)
14
14
 
15
15
  // TODO use config option or named constant?
16
- export const connectAsync = async ({ url, selfSigned, timeoutMs = 1000 }:
17
- { url: string, selfSigned: boolean, timeoutMs?: number }
16
+ export const connectAsync = async ({ url, allowSelfSignedCertificate, timeoutMs = 1000 }:
17
+ { url: string, allowSelfSignedCertificate: boolean, timeoutMs?: number }
18
18
  ): Promise<IConnection> => {
19
19
  const socket = new WebsocketClientConnection()
20
20
  let result: RunAndRaceEventsReturnType<ConnectionEvents>
21
21
  try {
22
22
  result = await runAndRaceEvents3<ConnectionEvents>([
23
- () => { socket.connect(url, selfSigned) }],
23
+ () => { socket.connect(url, allowSelfSignedCertificate) }],
24
24
  socket, ['connected', 'error'],
25
25
  timeoutMs)
26
26
  } catch (e) {
@@ -50,7 +50,7 @@ export const sendConnectivityRequest = async (
50
50
  try {
51
51
  outgoingConnection = await connectAsync({
52
52
  url,
53
- selfSigned: request.selfSigned
53
+ allowSelfSignedCertificate: request.allowSelfSignedCertificate
54
54
  })
55
55
  } catch (e) {
56
56
  throw new Err.ConnectionFailed(`Failed to connect to entrypoint for connectivity check: ${url}`, e)
@@ -11,12 +11,13 @@ import { IConnection } from './IConnection'
11
11
  import { WebsocketServerConnection } from './websocket/WebsocketServerConnection'
12
12
  import { connectivityMethodToWebsocketUrl } from './websocket/WebsocketConnector'
13
13
  import { LOCAL_PROTOCOL_VERSION } from '../helpers/version'
14
+ import { GeoIpLocator } from '@streamr/geoip-location'
14
15
 
15
16
  export const DISABLE_CONNECTIVITY_PROBE = 0
16
17
 
17
18
  const logger = new Logger(module)
18
19
 
19
- export const attachConnectivityRequestHandler = (connectionToListenTo: WebsocketServerConnection): void => {
20
+ export const attachConnectivityRequestHandler = (connectionToListenTo: WebsocketServerConnection, geoIpLocator?: GeoIpLocator): void => {
20
21
  connectionToListenTo.on('data', async (data: Uint8Array) => {
21
22
  logger.trace('server received data')
22
23
  try {
@@ -24,7 +25,8 @@ export const attachConnectivityRequestHandler = (connectionToListenTo: Websocket
24
25
  if (message.body.oneofKind === 'connectivityRequest') {
25
26
  logger.trace('ConnectivityRequest received: ' + JSON.stringify(Message.toJson(message)))
26
27
  try {
27
- await handleIncomingConnectivityRequest(connectionToListenTo, message.body.connectivityRequest)
28
+ await handleIncomingConnectivityRequest(connectionToListenTo,
29
+ message.body.connectivityRequest, geoIpLocator)
28
30
  logger.trace('handleIncomingConnectivityRequest ok')
29
31
  } catch (err1) {
30
32
  logger.error('handleIncomingConnectivityRequest', { err: err1 })
@@ -36,9 +38,13 @@ export const attachConnectivityRequestHandler = (connectionToListenTo: Websocket
36
38
  })
37
39
  }
38
40
 
39
- const handleIncomingConnectivityRequest = async (connection: WebsocketServerConnection, connectivityRequest: ConnectivityRequest): Promise<void> => {
40
- const host = connectivityRequest.host ?? connection.remoteIpAddress
41
- const ipAddress = connection.remoteIpAddress
41
+ const handleIncomingConnectivityRequest = async (
42
+ connection: WebsocketServerConnection,
43
+ connectivityRequest: ConnectivityRequest,
44
+ geoIpLocator?: GeoIpLocator
45
+ ): Promise<void> => {
46
+ const host = connectivityRequest.host ?? connection.getRemoteIpAddress()
47
+ const ipAddress = connection.getRemoteIpAddress()
42
48
  let connectivityResponse: ConnectivityResponse
43
49
  if (connectivityRequest.port !== DISABLE_CONNECTIVITY_PROBE) {
44
50
  connectivityResponse = await connectivityProbe(connectivityRequest, ipAddress, host)
@@ -51,6 +57,13 @@ const handleIncomingConnectivityRequest = async (connection: WebsocketServerConn
51
57
  version: LOCAL_PROTOCOL_VERSION
52
58
  }
53
59
  }
60
+ if (geoIpLocator !== undefined) {
61
+ const location = geoIpLocator.lookup(ipAddress)
62
+ if (location !== undefined) {
63
+ connectivityResponse.latitude = location.latitude
64
+ connectivityResponse.longitude = location.longitude
65
+ }
66
+ }
54
67
  const msg: Message = {
55
68
  serviceId: CONNECTIVITY_CHECKER_SERVICE_ID,
56
69
  messageId: v4(),
@@ -76,7 +89,7 @@ const connectivityProbe = async (connectivityRequest: ConnectivityRequest, ipAdd
76
89
  logger.trace(`Attempting Connectivity Check to ${url}`)
77
90
  outgoingConnection = await connectAsync({
78
91
  url,
79
- selfSigned: connectivityRequest.selfSigned
92
+ allowSelfSignedCertificate: connectivityRequest.allowSelfSignedCertificate
80
93
  })
81
94
  logger.trace('Connectivity test produced positive result, communicating reply to the requester ' + host + ':' + connectivityRequest.port)
82
95
  connectivityResponseMessage = {
@@ -1,7 +1,7 @@
1
- import { PeerDescriptor } from '../proto/packages/dht/protos/DhtRpc'
2
- import { ConnectionType } from './IConnection'
3
- import { ManagedConnection } from './ManagedConnection'
4
- import { NodeWebrtcConnection } from './webrtc/NodeWebrtcConnection'
1
+ import { PeerDescriptor } from '../../proto/packages/dht/protos/DhtRpc'
2
+ import { ConnectionType } from '../IConnection'
3
+ import { ManagedConnection } from '../ManagedConnection'
4
+ import { NodeWebrtcConnection } from './NodeWebrtcConnection'
5
5
 
6
6
  export class ManagedWebrtcConnection extends ManagedConnection {
7
7
 
@@ -2,7 +2,7 @@ import { IWebrtcConnection, WebrtcConnectionEvents } from './IWebrtcConnection'
2
2
  import { ConnectionType, IConnection, ConnectionID, ConnectionEvents } from '../IConnection'
3
3
  import { PeerDescriptor } from '../../proto/packages/dht/protos/DhtRpc'
4
4
  import EventEmitter from 'eventemitter3'
5
- import nodeDatachannel, { DataChannel, DescriptionType, PeerConnection } from 'node-datachannel'
5
+ import { DataChannel, DescriptionType, PeerConnection, cleanup, initLogger } from 'node-datachannel'
6
6
  import { Logger } from '@streamr/utils'
7
7
  import { IllegalRtcPeerConnectionState } from '../../helpers/errors'
8
8
  import { iceServerAsString } from './iceServerAsString'
@@ -16,7 +16,7 @@ const logger = new Logger(module)
16
16
  export const WEBRTC_CLEANUP = new class {
17
17
  // eslint-disable-next-line class-methods-use-this
18
18
  cleanUp(): void {
19
- nodeDatachannel.cleanup()
19
+ cleanup()
20
20
  }
21
21
  }
22
22
 
@@ -42,7 +42,7 @@ enum RtcPeerConnectionStateEnum {
42
42
  new = 'new'
43
43
  }
44
44
 
45
- nodeDatachannel.initLogger('Fatal')
45
+ initLogger('Fatal')
46
46
 
47
47
  type RtcPeerConnectionState = keyof typeof RtcPeerConnectionStateEnum
48
48
 
@@ -9,7 +9,7 @@ import { ListeningRpcCommunicator } from '../../transport/ListeningRpcCommunicat
9
9
  import { NodeWebrtcConnection } from './NodeWebrtcConnection'
10
10
  import { WebrtcConnectorRpcRemote } from './WebrtcConnectorRpcRemote'
11
11
  import { WebrtcConnectorRpcClient } from '../../proto/packages/dht/protos/DhtRpc.client'
12
- import { ManagedWebrtcConnection } from '../ManagedWebrtcConnection'
12
+ import { ManagedWebrtcConnection } from './ManagedWebrtcConnection'
13
13
  import { Logger } from '@streamr/utils'
14
14
  import * as Err from '../../helpers/errors'
15
15
  import { ManagedConnection } from '../ManagedConnection'
@@ -14,7 +14,7 @@ import { IWebrtcConnectorRpc } from '../../proto/packages/dht/protos/DhtRpc.serv
14
14
  import { DhtCallContext } from '../../rpc-protocol/DhtCallContext'
15
15
  import { ListeningRpcCommunicator } from '../../transport/ListeningRpcCommunicator'
16
16
  import { ManagedConnection } from '../ManagedConnection'
17
- import { ManagedWebrtcConnection } from '../ManagedWebrtcConnection'
17
+ import { ManagedWebrtcConnection } from './ManagedWebrtcConnection'
18
18
  import { NodeWebrtcConnection } from './NodeWebrtcConnection'
19
19
  import { WebrtcConnectorRpcRemote } from './WebrtcConnectorRpcRemote'
20
20
  import { DhtAddress, getNodeIdFromPeerDescriptor } from '../../identifiers'
@@ -89,9 +89,9 @@ export class WebrtcConnectorRpcLocal implements IWebrtcConnectorRpc {
89
89
  this.config.ongoingConnectAttempts.delete(nodeId)
90
90
  }
91
91
  if (!isMaybeSupportedVersion(remoteVersion)) {
92
- managedConnection!.rejectHandshake(HandshakeError.UNSUPPORTED_VERSION)
92
+ managedConnection.rejectHandshake(HandshakeError.UNSUPPORTED_VERSION)
93
93
  } else {
94
- managedConnection!.acceptHandshake()
94
+ managedConnection.acceptHandshake()
95
95
  }
96
96
  })
97
97
  return {}
@@ -34,7 +34,7 @@ export abstract class AbstractWebsocketClientConnection extends EventEmitter<Con
34
34
  }
35
35
 
36
36
  // TODO explicit default value for "selfSigned" or make it required
37
- public abstract connect(address: string, selfSigned?: boolean): void
37
+ public abstract connect(address: string, allowSelfSignedCertificate: boolean): void
38
38
 
39
39
  protected abstract stopListening(): void
40
40
 
@@ -30,6 +30,7 @@ import * as Err from '../../helpers/errors'
30
30
  import { Empty } from '../../proto/google/protobuf/empty'
31
31
  import { DhtAddress, areEqualPeerDescriptors, getNodeIdFromPeerDescriptor } from '../../identifiers'
32
32
  import { LOCAL_PROTOCOL_VERSION, isMaybeSupportedVersion } from '../../helpers/version'
33
+ import { GeoIpLocator } from '@streamr/geoip-location'
33
34
 
34
35
  const logger = new Logger(module)
35
36
 
@@ -39,7 +40,6 @@ export const connectivityMethodToWebsocketUrl = (ws: ConnectivityMethod, action?
39
40
  return (ws.tls ? 'wss://' : 'ws://') + ws.host + ':' + ws.port + ((action !== undefined) ? '?action=' + action : '')
40
41
  }
41
42
 
42
- const ENTRY_POINT_CONNECTION_ATTEMPTS = 5
43
43
  export interface WebsocketConnectorConfig {
44
44
  transport: ITransport
45
45
  onNewConnection: (connection: ManagedConnection) => boolean
@@ -53,6 +53,7 @@ export interface WebsocketConnectorConfig {
53
53
  autoCertifierUrl: string
54
54
  autoCertifierConfigFile: string
55
55
  serverEnableTls: boolean
56
+ geoIpDatabaseFolder?: string
56
57
  }
57
58
 
58
59
  export class WebsocketConnector {
@@ -60,6 +61,7 @@ export class WebsocketConnector {
60
61
  private static readonly WEBSOCKET_CONNECTOR_SERVICE_ID = 'system/websocket-connector'
61
62
  private readonly rpcCommunicator: ListeningRpcCommunicator
62
63
  private readonly websocketServer?: WebsocketServer
64
+ private geoIpLocator?: GeoIpLocator
63
65
  private readonly ongoingConnectRequests: Map<DhtAddress, ManagedConnection> = new Map()
64
66
  private host?: string
65
67
  private autoCertifierClient?: AutoCertifierClientFacade
@@ -87,17 +89,10 @@ export class WebsocketConnector {
87
89
  private registerLocalRpcMethods(config: WebsocketConnectorConfig) {
88
90
  const rpcLocal = new WebsocketConnectorRpcLocal({
89
91
  connect: (targetPeerDescriptor: PeerDescriptor) => this.connect(targetPeerDescriptor),
90
- hasConnection: (nodeId: DhtAddress): boolean => {
91
- if (this.connectingConnections.has(nodeId)
92
- || this.connectingConnections.has(nodeId)
93
- || this.ongoingConnectRequests.has(nodeId)
94
- || config.hasConnection(nodeId)
95
- ) {
96
- return true
97
- } else {
98
- return false
99
- }
100
- },
92
+ hasConnection: (nodeId: DhtAddress): boolean => (this.connectingConnections.has(nodeId)
93
+ || this.ongoingConnectRequests.has(nodeId)
94
+ || config.hasConnection(nodeId))
95
+ ,
101
96
  onNewConnection: (connection: ManagedConnection) => config.onNewConnection(connection),
102
97
  abortSignal: this.abortController.signal
103
98
  })
@@ -145,9 +140,9 @@ export class WebsocketConnector {
145
140
  const serverSocket = connection as unknown as WebsocketServerConnection
146
141
  const query = queryString.parse(serverSocket.resourceURL.query as string ?? '')
147
142
  const action = query.action as (Action | undefined)
148
- logger.trace('WebSocket client connected', { action, remoteAddress: serverSocket.remoteIpAddress })
143
+ logger.trace('WebSocket client connected', { action, remoteAddress: serverSocket.getRemoteIpAddress() })
149
144
  if (action === 'connectivityRequest') {
150
- attachConnectivityRequestHandler(serverSocket)
145
+ attachConnectivityRequestHandler(serverSocket, this.geoIpLocator)
151
146
  } else if (action === 'connectivityProbe') {
152
147
  // no-op
153
148
  } else {
@@ -163,12 +158,23 @@ export class WebsocketConnector {
163
158
  }
164
159
  }
165
160
  })
161
+
162
+ if (this.config.geoIpDatabaseFolder) {
163
+ const geoIpLocator = new GeoIpLocator(this.config.geoIpDatabaseFolder)
164
+ try {
165
+ await geoIpLocator.start()
166
+ this.geoIpLocator = geoIpLocator
167
+ } catch (err) {
168
+ logger.error('Failed to start GeoIpLocator', { err })
169
+ }
170
+ }
171
+
166
172
  const port = await this.websocketServer.start()
167
173
  this.selectedPort = port
168
174
  }
169
175
  }
170
176
 
171
- public async checkConnectivity(selfSigned: boolean): Promise<ConnectivityResponse> {
177
+ public async checkConnectivity(allowSelfSignedCertificate: boolean): Promise<ConnectivityResponse> {
172
178
  // TODO: this could throw?
173
179
  if (this.abortController.signal.aborted) {
174
180
  return {
@@ -183,9 +189,9 @@ export class WebsocketConnector {
183
189
  return {
184
190
  host: this.host!,
185
191
  natType: NatType.OPEN_INTERNET,
186
- websocket: {
187
- host: this.host!,
188
- port: this.selectedPort!,
192
+ websocket: {
193
+ host: this.host!,
194
+ port: this.selectedPort!,
189
195
  tls: this.config.tlsCertificate !== undefined
190
196
  },
191
197
  // TODO: Resolve the given host name or or use as is if IP was given.
@@ -202,7 +208,7 @@ export class WebsocketConnector {
202
208
  port: this.selectedPort ?? DISABLE_CONNECTIVITY_PROBE,
203
209
  host: this.host,
204
210
  tls: this.websocketServer ? this.config.serverEnableTls : false,
205
- selfSigned
211
+ allowSelfSignedCertificate
206
212
  }
207
213
  if (!this.abortController.signal.aborted) {
208
214
  return await sendConnectivityRequest(connectivityRequest, entryPoint)
@@ -217,7 +223,10 @@ export class WebsocketConnector {
217
223
  await wait(2000, this.abortController.signal)
218
224
  }
219
225
  }
220
- throw new WebsocketServerStartError(`Failed to connect to the entrypoints after ${ENTRY_POINT_CONNECTION_ATTEMPTS} attempts`)
226
+ throw new WebsocketServerStartError(
227
+ `Failed to connect to the entrypoints after ${this.config.entrypoints.length} attempts\n`
228
+ + `Attempted hosts: ${this.config.entrypoints.map((entry) => `${entry.websocket!.host}:${entry.websocket!.port}`).join(', ')}`
229
+ )
221
230
  }
222
231
 
223
232
  public isPossibleToFormConnection(targetPeerDescriptor: PeerDescriptor): boolean {
@@ -260,7 +269,7 @@ export class WebsocketConnector {
260
269
  socket.on('disconnected', delFunc)
261
270
  managedConnection.on('handshakeCompleted', delFunc)
262
271
 
263
- socket.connect(url)
272
+ socket.connect(url, false)
264
273
 
265
274
  return managedConnection
266
275
  }
@@ -307,6 +316,8 @@ export class WebsocketConnector {
307
316
  const ongoingConnectRequest = this.ongoingConnectRequests.get(nodeId)!
308
317
  if (!isMaybeSupportedVersion(remoteVersion)) {
309
318
  ongoingConnectRequest.rejectHandshake(HandshakeError.UNSUPPORTED_VERSION)
319
+ } else if (targetPeerDescriptor && !areEqualPeerDescriptors(this.localPeerDescriptor!, targetPeerDescriptor)) {
320
+ ongoingConnectRequest.rejectHandshake(HandshakeError.INVALID_TARGET_PEER_DESCRIPTOR)
310
321
  } else {
311
322
  ongoingConnectRequest.attachImplementation(websocketServerConnection)
312
323
  ongoingConnectRequest.acceptHandshake()
@@ -347,5 +358,6 @@ export class WebsocketConnector {
347
358
  const attempts = Array.from(this.connectingConnections.values())
348
359
  await Promise.allSettled(attempts.map((conn) => conn.close(false)))
349
360
  await this.websocketServer?.stop()
361
+ await this.geoIpLocator?.stop()
350
362
  }
351
363
  }
@@ -13,7 +13,7 @@ export class WebsocketServerConnection extends EventEmitter<ConnectionEvents> im
13
13
  public readonly connectionId: ConnectionID
14
14
  public readonly connectionType = ConnectionType.WEBSOCKET_SERVER
15
15
  public readonly resourceURL: Url
16
- public readonly remoteIpAddress: string
16
+ private readonly remoteIpAddress: string
17
17
  private socket?: WebSocket
18
18
  private stopped = false
19
19
 
@@ -34,6 +34,11 @@ export class WebsocketServerConnection extends EventEmitter<ConnectionEvents> im
34
34
 
35
35
  this.socket = socket
36
36
  }
37
+
38
+ // use a getter to make it possible to mock the value in tests
39
+ public getRemoteIpAddress(): string {
40
+ return this.remoteIpAddress
41
+ }
37
42
 
38
43
  private onMessage(message: WebSocket.RawData, isBinary: boolean): void {
39
44
  if (!isBinary) {