@streamr/dht 0.0.1-tatum.1 → 0.0.1-tatum.3

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 (89) hide show
  1. package/dist/src/connection/ConnectionManager.d.ts +6 -1
  2. package/dist/src/connection/ConnectionManager.js +21 -26
  3. package/dist/src/connection/ConnectionManager.js.map +1 -1
  4. package/dist/src/connection/ConnectivityChecker.d.ts +4 -2
  5. package/dist/src/connection/ConnectivityChecker.js +23 -19
  6. package/dist/src/connection/ConnectivityChecker.js.map +1 -1
  7. package/dist/src/connection/ManagedConnection.js +2 -6
  8. package/dist/src/connection/ManagedConnection.js.map +1 -1
  9. package/dist/src/connection/Simulator/SimulatorTransport.js +1 -1
  10. package/dist/src/connection/Simulator/SimulatorTransport.js.map +1 -1
  11. package/dist/src/connection/WebRTC/WebRtcConnector.d.ts +2 -0
  12. package/dist/src/connection/WebRTC/WebRtcConnector.js +14 -1
  13. package/dist/src/connection/WebRTC/WebRtcConnector.js.map +1 -1
  14. package/dist/src/connection/WebSocket/WebSocketConnector.d.ts +5 -3
  15. package/dist/src/connection/WebSocket/WebSocketConnector.js +19 -12
  16. package/dist/src/connection/WebSocket/WebSocketConnector.js.map +1 -1
  17. package/dist/src/connection/WebSocket/WebSocketServer.d.ts +2 -2
  18. package/dist/src/connection/WebSocket/WebSocketServer.js +29 -37
  19. package/dist/src/connection/WebSocket/WebSocketServer.js.map +1 -1
  20. package/dist/src/dht/DhtNode.d.ts +9 -6
  21. package/dist/src/dht/DhtNode.js +14 -21
  22. package/dist/src/dht/DhtNode.js.map +1 -1
  23. package/dist/src/dht/DhtPeer.js +1 -1
  24. package/dist/src/dht/discovery/PeerDiscovery.d.ts +4 -2
  25. package/dist/src/dht/discovery/PeerDiscovery.js +18 -33
  26. package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
  27. package/dist/src/dht/routing/RemoteRouter.js +2 -4
  28. package/dist/src/dht/routing/RemoteRouter.js.map +1 -1
  29. package/dist/src/dht/store/DataStore.js +6 -6
  30. package/dist/src/exports.d.ts +1 -1
  31. package/dist/src/exports.js.map +1 -1
  32. package/dist/src/helpers/errors.d.ts +1 -1
  33. package/dist/src/helpers/errors.js +3 -3
  34. package/dist/src/helpers/errors.js.map +1 -1
  35. package/dist/src/helpers/protoClasses.js +0 -2
  36. package/dist/src/helpers/protoClasses.js.map +1 -1
  37. package/dist/src/proto/packages/dht/protos/DhtRpc.client.js +1 -1
  38. package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +14 -50
  39. package/dist/src/proto/packages/dht/protos/DhtRpc.js +9 -35
  40. package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -1
  41. package/dist/src/proto/packages/proto-rpc/protos/ProtoRpc.js +1 -1
  42. package/package.json +9 -9
  43. package/protos/DhtRpc.proto +7 -16
  44. package/src/connection/ConnectionManager.ts +31 -28
  45. package/src/connection/ConnectivityChecker.ts +28 -23
  46. package/src/connection/ManagedConnection.ts +2 -6
  47. package/src/connection/Simulator/SimulatorTransport.ts +1 -1
  48. package/src/connection/WebRTC/BrowserWebRtcConnection.ts +13 -2
  49. package/src/connection/WebRTC/WebRtcConnector.ts +14 -0
  50. package/src/connection/WebSocket/WebSocketConnector.ts +23 -12
  51. package/src/connection/WebSocket/WebSocketServer.ts +33 -20
  52. package/src/dht/DhtNode.ts +23 -24
  53. package/src/dht/DhtPeer.ts +1 -1
  54. package/src/dht/discovery/PeerDiscovery.ts +17 -8
  55. package/src/dht/routing/RemoteRouter.ts +2 -4
  56. package/src/dht/store/DataStore.ts +6 -6
  57. package/src/exports.ts +1 -1
  58. package/src/helpers/errors.ts +1 -1
  59. package/src/helpers/protoClasses.ts +1 -5
  60. package/src/proto/google/protobuf/any.ts +1 -1
  61. package/src/proto/google/protobuf/empty.ts +1 -1
  62. package/src/proto/google/protobuf/timestamp.ts +1 -1
  63. package/src/proto/packages/dht/protos/DhtRpc.client.ts +1 -1
  64. package/src/proto/packages/dht/protos/DhtRpc.server.ts +1 -1
  65. package/src/proto/packages/dht/protos/DhtRpc.ts +22 -69
  66. package/src/proto/packages/proto-rpc/protos/ProtoRpc.ts +1 -1
  67. package/test/benchmark/KademliaCorrectness.test.ts +1 -1
  68. package/test/benchmark/RecursiveFind.test.ts +1 -1
  69. package/test/end-to-end/Layer0-Layer1.test.ts +3 -3
  70. package/test/end-to-end/Layer0.test.ts +5 -5
  71. package/test/end-to-end/Layer0MixedConnectionTypes.test.ts +6 -6
  72. package/test/end-to-end/Layer0WebRTC-Layer1.test.ts +18 -19
  73. package/test/end-to-end/Layer0WebRTC.test.ts +18 -24
  74. package/test/end-to-end/Layer1-Scale-WebRTC.test.ts +2 -2
  75. package/test/end-to-end/Layer1-Scale-WebSocket.test.ts +2 -2
  76. package/test/end-to-end/WebSocketConnectionRequest.test.ts +3 -3
  77. package/test/integration/ConnectionManager.test.ts +10 -9
  78. package/test/integration/DhtRpc.test.ts +2 -2
  79. package/test/integration/MigrateData.test.ts +3 -3
  80. package/test/integration/RouteMessage.test.ts +2 -2
  81. package/test/integration/ScaleDownDht.test.ts +1 -1
  82. package/test/integration/SimultaneousConnections.test.ts +9 -6
  83. package/test/integration/WebRtcConnectionManagement.test.ts +2 -2
  84. package/test/integration/WebRtcConnectorRpc.test.ts +2 -2
  85. package/test/integration/WebSocketConnectionManagement.test.ts +3 -2
  86. package/test/integration/WebSocketConnectorRpc.test.ts +4 -4
  87. package/test/unit/WebSocketServer.test.ts +1 -8
  88. package/test/unit/webrtcReplaceInternalIpWithExternalIp.ts +18 -0
  89. package/test/utils/utils.ts +1 -2
@@ -28,6 +28,15 @@ import { PortRange } from '../ConnectionManager'
28
28
 
29
29
  const logger = new Logger(module)
30
30
 
31
+ export const replaceInternalIpWithExternalIp = (candidate: string, ip: string): string => {
32
+ const parsed = candidate.split(' ')
33
+ const type = parsed[7]
34
+ if (type === 'host') {
35
+ parsed[4] = ip
36
+ }
37
+ return parsed.join(' ')
38
+ }
39
+
31
40
  export interface WebRtcConnectorConfig {
32
41
  rpcTransport: ITransport
33
42
  protocolVersion: string
@@ -36,6 +45,7 @@ export interface WebRtcConnectorConfig {
36
45
  bufferThresholdLow?: number
37
46
  bufferThresholdHigh?: number
38
47
  connectionTimeout?: number
48
+ externalIp?: string
39
49
  portRange?: PortRange
40
50
  }
41
51
 
@@ -131,6 +141,10 @@ export class WebRtcConnector implements IWebRtcConnectorService {
131
141
  )
132
142
 
133
143
  connection.on('localCandidate', (candidate: string, mid: string) => {
144
+ if (this.config.externalIp) {
145
+ candidate = replaceInternalIpWithExternalIp(candidate, this.config.externalIp)
146
+ logger.debug(`onLocalCandidate injected external ip ${candidate} ${mid}`)
147
+ }
134
148
  remoteConnector.sendIceCandidate(this.ownPeerDescriptor!, candidate, mid, connection.connectionId.toString())
135
149
  })
136
150
 
@@ -4,6 +4,7 @@ import { ITransport } from '../../transport/ITransport'
4
4
  import { ListeningRpcCommunicator } from '../../transport/ListeningRpcCommunicator'
5
5
  import { RemoteWebSocketConnector } from './RemoteWebSocketConnector'
6
6
  import {
7
+ ConnectivityMethod,
7
8
  ConnectivityResponse,
8
9
  PeerDescriptor,
9
10
  WebSocketConnectionRequest,
@@ -16,7 +17,7 @@ import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
16
17
  import { ManagedConnection } from '../ManagedConnection'
17
18
  import { WebSocketServer } from './WebSocketServer'
18
19
  import { ConnectivityChecker } from '../ConnectivityChecker'
19
- import { NatType, PortRange } from '../ConnectionManager'
20
+ import { NatType, PortRange, TlsCertificate } from '../ConnectionManager'
20
21
  import { PeerIDKey } from '../../helpers/PeerID'
21
22
  import { ServerWebSocket } from './ServerWebSocket'
22
23
  import { toProtoRpcClient } from '@streamr/proto-rpc'
@@ -27,6 +28,12 @@ import { sample } from 'lodash'
27
28
 
28
29
  const logger = new Logger(module)
29
30
 
31
+ export const connectivityMethodToWebSocketUrl = (ws: ConnectivityMethod): string => {
32
+ return (ws.tls ? 'wss://' : 'ws://') + ws.host + ':' + ws.port
33
+ }
34
+
35
+ const ENTRY_POINT_CONNECTION_ATTEMPTS = 5
36
+
30
37
  export class WebSocketConnector implements IWebSocketConnectorService {
31
38
  private static readonly WEBSOCKET_CONNECTOR_SERVICE_ID = 'system/websocketconnector'
32
39
  private readonly rpcCommunicator: ListeningRpcCommunicator
@@ -38,6 +45,7 @@ export class WebSocketConnector implements IWebSocketConnectorService {
38
45
  private portRange?: PortRange
39
46
  private host?: string
40
47
  private entrypoints?: PeerDescriptor[]
48
+ private readonly tlsCertificate?: TlsCertificate
41
49
  private selectedPort?: number
42
50
  private readonly protocolVersion: string
43
51
  private ownPeerDescriptor?: PeerDescriptor
@@ -51,7 +59,8 @@ export class WebSocketConnector implements IWebSocketConnectorService {
51
59
  incomingConnectionCallback: (connection: ManagedConnection) => boolean,
52
60
  portRange?: PortRange,
53
61
  host?: string,
54
- entrypoints?: PeerDescriptor[]
62
+ entrypoints?: PeerDescriptor[],
63
+ tlsCertificate?: TlsCertificate
55
64
  ) {
56
65
  this.protocolVersion = protocolVersion
57
66
  this.webSocketServer = portRange ? new WebSocketServer() : undefined
@@ -59,6 +68,7 @@ export class WebSocketConnector implements IWebSocketConnectorService {
59
68
  this.portRange = portRange
60
69
  this.host = host
61
70
  this.entrypoints = entrypoints
71
+ this.tlsCertificate = tlsCertificate
62
72
 
63
73
  this.canConnectFunction = fnCanConnect.bind(this)
64
74
 
@@ -101,16 +111,17 @@ export class WebSocketConnector implements IWebSocketConnectorService {
101
111
  this.attachHandshaker(connection)
102
112
  }
103
113
  })
104
- const port = await this.webSocketServer.start(this.portRange!, this.host)
114
+ const port = await this.webSocketServer.start(this.portRange!, this.tlsCertificate)
105
115
  this.selectedPort = port
106
- this.connectivityChecker = new ConnectivityChecker(this.selectedPort)
116
+ this.connectivityChecker = new ConnectivityChecker(this.selectedPort, this.tlsCertificate !== undefined, this.host)
107
117
  }
108
118
  }
109
119
 
110
120
  public async checkConnectivity(reattempt = 0): Promise<ConnectivityResponse> {
121
+ // TODO: this could throw if the server is not running
111
122
  const noServerConnectivityResponse: ConnectivityResponse = {
112
123
  openInternet: false,
113
- ip: '127.0.0.1',
124
+ host: '127.0.0.1',
114
125
  natType: NatType.UNKNOWN
115
126
  }
116
127
  if (this.destroyed) {
@@ -125,9 +136,9 @@ export class WebSocketConnector implements IWebSocketConnectorService {
125
136
  // return connectivity info given in config
126
137
  const preconfiguredConnectivityResponse: ConnectivityResponse = {
127
138
  openInternet: true,
128
- ip: this.host!,
139
+ host: this.host!,
129
140
  natType: NatType.OPEN_INTERNET,
130
- websocket: { ip: this.host!, port: this.selectedPort! }
141
+ websocket: { host: this.host!, port: this.selectedPort!, tls: this.tlsCertificate !== undefined }
131
142
  }
132
143
  return preconfiguredConnectivityResponse
133
144
  } else {
@@ -136,7 +147,8 @@ export class WebSocketConnector implements IWebSocketConnectorService {
136
147
  }
137
148
  }
138
149
  } catch (err) {
139
- if (reattempt < 5) {
150
+ if (reattempt < ENTRY_POINT_CONNECTION_ATTEMPTS) {
151
+ logger.error('Failed to connect to the entrypoint', { error: err })
140
152
  await wait(2000)
141
153
  return this.checkConnectivity(reattempt + 1)
142
154
  } else {
@@ -158,8 +170,7 @@ export class WebSocketConnector implements IWebSocketConnectorService {
158
170
  } else {
159
171
  const socket = new ClientWebSocket()
160
172
 
161
- const address = 'ws://' + targetPeerDescriptor.websocket!.ip + ':' +
162
- targetPeerDescriptor.websocket!.port
173
+ const url = connectivityMethodToWebSocketUrl(targetPeerDescriptor.websocket!)
163
174
 
164
175
  const managedConnection = new ManagedConnection(this.ownPeerDescriptor!, this.protocolVersion,
165
176
  ConnectionType.WEBSOCKET_CLIENT, socket, undefined)
@@ -177,7 +188,7 @@ export class WebSocketConnector implements IWebSocketConnectorService {
177
188
  socket.on('disconnected', delFunc)
178
189
  managedConnection.on('handshakeCompleted', delFunc)
179
190
 
180
- socket.connect(address)
191
+ socket.connect(url)
181
192
 
182
193
  return managedConnection
183
194
  }
@@ -189,7 +200,7 @@ export class WebSocketConnector implements IWebSocketConnectorService {
189
200
  targetPeerDescriptor,
190
201
  toProtoRpcClient(new WebSocketConnectorServiceClient(this.rpcCommunicator.getRpcClientTransport()))
191
202
  )
192
- remoteConnector.requestConnection(ownPeerDescriptor, ownPeerDescriptor.websocket!.ip, ownPeerDescriptor.websocket!.port)
203
+ remoteConnector.requestConnection(ownPeerDescriptor, ownPeerDescriptor.websocket!.host, ownPeerDescriptor.websocket!.port)
193
204
  })
194
205
  const managedConnection = new ManagedConnection(this.ownPeerDescriptor!, this.protocolVersion, ConnectionType.WEBSOCKET_SERVER)
195
206
  managedConnection.on('disconnected', () => this.ongoingConnectRequests.delete(keyFromPeerDescriptor(targetPeerDescriptor)))
@@ -1,4 +1,5 @@
1
- import * as http from 'http'
1
+ import { createServer as createHttpServer, Server as HttpServer, IncomingMessage, ServerResponse } from 'http'
2
+ import { createServer as createHttpsServer, Server as HttpsServer } from 'https'
2
3
  import EventEmitter from 'eventemitter3'
3
4
  import { server as WsServer } from 'websocket'
4
5
  import { ServerWebSocket } from './ServerWebSocket'
@@ -7,9 +8,10 @@ import {
7
8
  } from '../IConnectionSource'
8
9
 
9
10
  import { Logger, asAbortable } from '@streamr/utils'
10
- import { StartingWebSocketServerFailed } from '../../helpers/errors'
11
- import { PortRange } from '../ConnectionManager'
11
+ import { WebSocketServerStartError } from '../../helpers/errors'
12
+ import { PortRange, TlsCertificate } from '../ConnectionManager'
12
13
  import { range } from 'lodash'
14
+ import fs from 'fs'
13
15
 
14
16
  const logger = new Logger(module)
15
17
 
@@ -22,30 +24,41 @@ declare class NodeJsWsServer extends WsServer { }
22
24
 
23
25
  export class WebSocketServer extends EventEmitter<ConnectionSourceEvents> {
24
26
 
25
- private httpServer?: http.Server
27
+ private httpServer?: HttpServer | HttpsServer
26
28
  private wsServer?: WsServer
27
29
  private readonly abortController = new AbortController()
28
-
29
- public async start(portRange: PortRange, host?: string): Promise<number> {
30
+
31
+ public async start(portRange: PortRange, tlsCertificate?: TlsCertificate): Promise<number> {
30
32
  const ports = range(portRange.min, portRange.max + 1)
31
33
  for (const port of ports) {
32
34
  try {
33
- await asAbortable(this.startServer(port, host), this.abortController.signal)
35
+ await asAbortable(this.startServer(port, tlsCertificate), this.abortController.signal)
34
36
  return port
35
37
  } catch (err) {
36
- logger.debug(`failed to start WebSocket server on port: ${port} reattempting on next port`)
38
+ if (err.originalError?.code === 'EADDRINUSE') {
39
+ logger.debug(`failed to start WebSocket server on port: ${port} reattempting on next port`)
40
+ } else {
41
+ throw new WebSocketServerStartError(err)
42
+ }
37
43
  }
38
44
  }
39
- throw new StartingWebSocketServerFailed('Failed to start WebSocket server on any port in range')
45
+ throw new WebSocketServerStartError(`Failed to start WebSocket server on any port in range: ${portRange.min}-${portRange.min}`)
40
46
  }
41
47
 
42
- private startServer(port: number, host?: string): Promise<void> {
48
+ private startServer(port: number, tlsCertificate?: TlsCertificate): Promise<void> {
49
+ const requestListener = (request: IncomingMessage, response: ServerResponse<IncomingMessage>) => {
50
+ logger.trace('Received request for ' + request.url)
51
+ response.writeHead(404)
52
+ response.end()
53
+ }
43
54
  return new Promise((resolve, reject) => {
44
- this.httpServer = http.createServer((request, response) => {
45
- logger.trace('Received request for ' + request.url)
46
- response.writeHead(404)
47
- response.end()
48
- })
55
+ this.httpServer = tlsCertificate ?
56
+ createHttpsServer({
57
+ key: fs.readFileSync(tlsCertificate.privateKeyFileName),
58
+ cert: fs.readFileSync(tlsCertificate.certFileName)
59
+ }, requestListener)
60
+ :
61
+ createHttpServer(requestListener)
49
62
 
50
63
  function originIsAllowed(_uorigin: string) {
51
64
  return true
@@ -67,9 +80,8 @@ export class WebSocketServer extends EventEmitter<ConnectionSourceEvents> {
67
80
 
68
81
  this.emit('connected', new ServerWebSocket(connection, request.resourceURL))
69
82
  })
70
-
71
83
  this.httpServer.once('error', (err: Error) => {
72
- reject(new StartingWebSocketServerFailed('Starting Websocket server failed', err))
84
+ reject(new WebSocketServerStartError('Starting Websocket server failed', err))
73
85
  })
74
86
 
75
87
  this.httpServer.once('listening', () => {
@@ -78,9 +90,10 @@ export class WebSocketServer extends EventEmitter<ConnectionSourceEvents> {
78
90
  })
79
91
 
80
92
  try {
81
- this.httpServer.listen(port, host)
93
+ // Listen only to IPv4 network interfaces, default value listens to IPv6 as well
94
+ this.httpServer.listen(port, '0.0.0.0')
82
95
  } catch (e) {
83
- reject(new StartingWebSocketServerFailed('Websocket server threw an exception', e))
96
+ reject(new WebSocketServerStartError('Websocket server threw an exception', e))
84
97
  }
85
98
  })
86
99
  }
@@ -96,7 +109,7 @@ export class WebSocketServer extends EventEmitter<ConnectionSourceEvents> {
96
109
  })
97
110
  }
98
111
 
99
- private createWsServer(httpServer: http.Server): WsServer {
112
+ private createWsServer(httpServer: HttpServer | HttpsServer): WsServer {
100
113
  // Use the real nodejs WebSocket server in Electron tests
101
114
 
102
115
  if (typeof NodeJsWsServer !== 'undefined') {
@@ -20,11 +20,13 @@ import {
20
20
  } from '../proto/packages/dht/protos/DhtRpc'
21
21
  import * as Err from '../helpers/errors'
22
22
  import { DisconnectionType, ITransport, TransportEvents } from '../transport/ITransport'
23
- import { ConnectionManager, ConnectionManagerConfig, PortRange } from '../connection/ConnectionManager'
23
+ import { ConnectionManager, ConnectionManagerConfig, PortRange, TlsCertificate } from '../connection/ConnectionManager'
24
24
  import { DhtRpcServiceClient, ExternalApiServiceClient } from '../proto/packages/dht/protos/DhtRpc.client'
25
25
  import {
26
26
  Logger,
27
- MetricsContext
27
+ MetricsContext,
28
+ hexToBinary,
29
+ binaryToHex
28
30
  } from '@streamr/utils'
29
31
  import { toProtoRpcClient } from '@streamr/proto-rpc'
30
32
  import { RandomContactList } from './contact/RandomContactList'
@@ -71,7 +73,7 @@ export interface DhtNodeOptions {
71
73
  entryPoints?: PeerDescriptor[]
72
74
  websocketHost?: string
73
75
  websocketPortRange?: PortRange
74
- peerIdString?: string
76
+ peerId?: string
75
77
 
76
78
  nodeName?: string
77
79
  rpcRequestTimeout?: number
@@ -82,6 +84,8 @@ export interface DhtNodeOptions {
82
84
  webrtcNewConnectionTimeout?: number
83
85
  webrtcPortRange?: PortRange
84
86
  maxConnections?: number
87
+ tlsCertificate?: TlsCertificate
88
+ externalIp?: string
85
89
  }
86
90
 
87
91
  export class DhtNodeConfig {
@@ -97,7 +101,7 @@ export class DhtNodeConfig {
97
101
  storeMaxTtl = 60000
98
102
  storeNumberOfCopies = 5
99
103
  metricsContext = new MetricsContext()
100
- peerIdString = new UUID().toHex()
104
+ peerId = new UUID().toHex()
101
105
 
102
106
  transportLayer?: ITransport
103
107
  peerDescriptor?: PeerDescriptor
@@ -111,7 +115,9 @@ export class DhtNodeConfig {
111
115
  webrtcDatachannelBufferThresholdLow?: number
112
116
  webrtcDatachannelBufferThresholdHigh?: number
113
117
  webrtcNewConnectionTimeout?: number
118
+ externalIp?: string
114
119
  webrtcPortRange?: PortRange
120
+ tlsCertificate?: TlsCertificate
115
121
 
116
122
  constructor(conf: Partial<DhtNodeOptions>) {
117
123
  // assign given non-undefined config vars over defaults
@@ -129,16 +135,16 @@ const logger = new Logger(module)
129
135
 
130
136
  export type Events = TransportEvents & DhtNodeEvents
131
137
 
132
- export const createPeerDescriptor = (msg?: ConnectivityResponse, peerIdString?: string, nodeName?: string): PeerDescriptor => {
133
- let peerId: Uint8Array
138
+ export const createPeerDescriptor = (msg?: ConnectivityResponse, peerId?: string, nodeName?: string): PeerDescriptor => {
139
+ let kademliaId: Uint8Array
134
140
  if (msg) {
135
- peerId = peerIdString ? PeerID.fromString(peerIdString).value : PeerID.fromIp(msg.ip).value
141
+ kademliaId = peerId ? hexToBinary(peerId) : PeerID.fromIp(msg.host).value
136
142
  } else {
137
- peerId = PeerID.fromString(peerIdString!).value
143
+ kademliaId = hexToBinary(peerId!)
138
144
  }
139
- const ret: PeerDescriptor = { kademliaId: peerId, nodeName: nodeName, type: NodeType.NODEJS }
145
+ const ret: PeerDescriptor = { kademliaId, nodeName: nodeName ? nodeName : binaryToHex(kademliaId), type: NodeType.NODEJS }
140
146
  if (msg && msg.websocket) {
141
- ret.websocket = { ip: msg.websocket.ip, port: msg.websocket.port }
147
+ ret.websocket = { host: msg.websocket.host, port: msg.websocket.port, tls: msg.websocket.tls }
142
148
  ret.openInternet = true
143
149
  }
144
150
  return ret
@@ -207,12 +213,13 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
207
213
  webrtcDatachannelBufferThresholdHigh: this.config.webrtcDatachannelBufferThresholdHigh,
208
214
  webrtcNewConnectionTimeout: this.config.webrtcNewConnectionTimeout,
209
215
  webrtcPortRange: this.config.webrtcPortRange,
210
- nodeName: this.getNodeName(),
211
- maxConnections: this.config.maxConnections
216
+ maxConnections: this.config.maxConnections,
217
+ tlsCertificate: this.config.tlsCertificate,
218
+ externalIp: this.config.externalIp
212
219
  }
213
220
  // If own PeerDescriptor is given in config, create a ConnectionManager with ws server
214
221
  if (this.config.peerDescriptor?.websocket) {
215
- connectionManagerConfig.websocketHost = this.config.peerDescriptor.websocket.ip
222
+ connectionManagerConfig.websocketHost = this.config.peerDescriptor.websocket.host
216
223
  connectionManagerConfig.websocketPortRange = {
217
224
  min: this.config.peerDescriptor.websocket.port,
218
225
  max: this.config.peerDescriptor.websocket.port
@@ -442,7 +449,7 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
442
449
  this.ownPeerDescriptor = this.config.peerDescriptor
443
450
  } else {
444
451
  this.ownPeerDescriptor = createPeerDescriptor(connectivityResponse,
445
- this.config.peerIdString,
452
+ this.config.peerId,
446
453
  this.config.nodeName)
447
454
  }
448
455
  return this.ownPeerDescriptor
@@ -619,12 +626,12 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
619
626
  await this.router!.send(msg, reachableThrough)
620
627
  }
621
628
 
622
- public async joinDht(entryPointDescriptors: PeerDescriptor[], doRandomJoin?: boolean): Promise<void> {
629
+ public async joinDht(entryPointDescriptors: PeerDescriptor[], doRandomJoin?: boolean, retry?: boolean): Promise<void> {
623
630
  if (!this.started) {
624
631
  throw new Error('Cannot join DHT before calling start() on DhtNode')
625
632
  }
626
633
  await Promise.all(entryPointDescriptors.map((entryPoint) =>
627
- this.peerDiscovery!.joinDht(entryPoint, doRandomJoin)
634
+ this.peerDiscovery!.joinDht(entryPoint, doRandomJoin, retry)
628
635
  ))
629
636
  }
630
637
 
@@ -700,14 +707,6 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
700
707
  return this.connectionManager!.getNumberOfWeakLockedConnections()
701
708
  }
702
709
 
703
- public getNodeName(): string {
704
- if (this.config.nodeName) {
705
- return this.config.nodeName
706
- } else {
707
- return 'unnamed node'
708
- }
709
- }
710
-
711
710
  public isJoinOngoing(): boolean {
712
711
  return this.peerDiscovery!.isJoinOngoing()
713
712
  }
@@ -69,7 +69,7 @@ export class DhtPeer extends Remote<IDhtRpcServiceClient> implements KBucketCont
69
69
  return true
70
70
  }
71
71
  } catch (err) {
72
- logger.debug(`ping failed on ${this.serviceId} to ${this.peerId.toKey()}: ${err}`)
72
+ logger.trace(`ping failed on ${this.serviceId} to ${this.peerId.toKey()}: ${err}`)
73
73
  }
74
74
  return false
75
75
  }
@@ -1,7 +1,6 @@
1
1
  import { DiscoverySession } from './DiscoverySession'
2
2
  import { DhtPeer } from '../DhtPeer'
3
3
  import crypto from 'crypto'
4
- import * as Err from '../../helpers/errors'
5
4
  import { isSamePeerDescriptor, keyFromPeerDescriptor } from '../../helpers/peerIdFromPeerDescriptor'
6
5
  import { PeerDescriptor } from '../../proto/packages/dht/protos/DhtRpc'
7
6
  import { Logger, scheduleAtInterval, setAbortableTimeout } from '@streamr/utils'
@@ -41,13 +40,14 @@ export class PeerDiscovery {
41
40
 
42
41
  private rejoinTimeoutRef?: NodeJS.Timeout
43
42
  private readonly abortController: AbortController
43
+ private recoveryIntervalStarted = false
44
44
 
45
45
  constructor(config: PeerDiscoveryConfig) {
46
46
  this.config = config
47
47
  this.abortController = new AbortController()
48
48
  }
49
49
 
50
- async joinDht(entryPointDescriptor: PeerDescriptor, doRandomJoin = true): Promise<void> {
50
+ async joinDht(entryPointDescriptor: PeerDescriptor, doRandomJoin = true, retry = true): Promise<void> {
51
51
  if (this.stopped) {
52
52
  return
53
53
  }
@@ -90,16 +90,18 @@ export class PeerDiscovery {
90
90
  if (randomSession) {
91
91
  await randomSession.findClosestNodes(this.config.joinTimeout)
92
92
  }
93
+ } catch (_e) {
94
+ logger.debug(`DHT join on ${this.config.serviceId} timed out`)
95
+ } finally {
93
96
  if (!this.stopped) {
94
97
  if (this.config.bucket.count() === 0) {
95
- this.rejoinDht(entryPointDescriptor).catch(() => {})
98
+ if (retry) {
99
+ setAbortableTimeout(() => this.rejoinDht(entryPointDescriptor), 1000, this.abortController.signal)
100
+ }
96
101
  } else {
97
- await scheduleAtInterval(() => this.getClosestPeersFromBucket(), 60000, true, this.abortController.signal)
102
+ await this.ensureRecoveryIntervalIsRunning()
98
103
  }
99
104
  }
100
- } catch (_e) {
101
- throw new Err.DhtJoinTimeout('join timed out')
102
- } finally {
103
105
  this.ongoingDiscoverySessions.delete(session.sessionId)
104
106
  if (randomSession) {
105
107
  this.ongoingDiscoverySessions.delete(randomSession.sessionId)
@@ -128,7 +130,14 @@ export class PeerDiscovery {
128
130
  }
129
131
  }
130
132
 
131
- private async getClosestPeersFromBucket(): Promise<void> {
133
+ private async ensureRecoveryIntervalIsRunning(): Promise<void> {
134
+ if (!this.recoveryIntervalStarted) {
135
+ this.recoveryIntervalStarted = true
136
+ await scheduleAtInterval(() => this.fetchClosestPeersFromBucket(), 60000, true, this.abortController.signal)
137
+ }
138
+ }
139
+
140
+ private async fetchClosestPeersFromBucket(): Promise<void> {
132
141
  if (this.stopped) {
133
142
  return
134
143
  }
@@ -30,9 +30,7 @@ export class RemoteRouter extends Remote<IRoutingServiceClient> {
30
30
  timeout: 10000
31
31
  }
32
32
  try {
33
- logger.trace('calling dhtClient.routeMessage')
34
33
  const ack = await this.client.routeMessage(message, options)
35
- logger.trace('dhtClient.routeMessage returned')
36
34
  // Success signal if sent to destination and error includes duplicate
37
35
  if (
38
36
  isSamePeerDescriptor(params.destinationPeer!, this.peerDescriptor)
@@ -45,7 +43,7 @@ export class RemoteRouter extends Remote<IRoutingServiceClient> {
45
43
  } catch (err) {
46
44
  const fromNode = params.previousPeer ?
47
45
  peerIdFromPeerDescriptor(params.previousPeer) : keyFromPeerDescriptor(params.sourcePeer!)
48
- logger.debug(`Failed to send routeMessage from ${fromNode} to ${this.peerId.toKey()} with: ${err}`)
46
+ logger.trace(`Failed to send routeMessage from ${fromNode} to ${this.peerId.toKey()} with: ${err}`)
49
47
  return false
50
48
  }
51
49
  return true
@@ -75,7 +73,7 @@ export class RemoteRouter extends Remote<IRoutingServiceClient> {
75
73
  const fromNode = params.previousPeer ?
76
74
  keyFromPeerDescriptor(params.previousPeer) : keyFromPeerDescriptor(params.sourcePeer!)
77
75
 
78
- logger.debug(
76
+ logger.trace(
79
77
  `Failed to send forwardMessage from ${fromNode} to ${this.peerId.toKey()} with: ${err}`
80
78
  )
81
79
  return false
@@ -136,10 +136,10 @@ export class DataStore implements IStoreService {
136
136
  try {
137
137
  const response = await remoteStore.migrateData({ dataEntry }, doNotConnect)
138
138
  if (response.error) {
139
- logger.debug('RemoteStore::migrateData() returned error: ' + response.error)
139
+ logger.trace('RemoteStore::migrateData() returned error: ' + response.error)
140
140
  }
141
141
  } catch (e) {
142
- logger.debug('RemoteStore::migrateData() threw an exception ' + e)
142
+ logger.trace('RemoteStore::migrateData() threw an exception ' + e)
143
143
  }
144
144
  }
145
145
 
@@ -177,10 +177,10 @@ export class DataStore implements IStoreService {
177
177
  successfulNodes.push(closestNodes[i])
178
178
  logger.trace('remoteStore.storeData() returned success')
179
179
  } else {
180
- logger.debug('remoteStore.storeData() returned error: ' + response.error)
180
+ logger.trace('remoteStore.storeData() returned error: ' + response.error)
181
181
  }
182
182
  } catch (e) {
183
- logger.debug('remoteStore.storeData() threw an exception ' + e)
183
+ logger.trace('remoteStore.storeData() threw an exception ' + e)
184
184
  }
185
185
  }
186
186
  return successfulNodes
@@ -217,11 +217,11 @@ export class DataStore implements IStoreService {
217
217
  if (response.deleted) {
218
218
  logger.trace('remoteStore.deleteData() returned success')
219
219
  } else {
220
- logger.debug('could not delete data from ' + PeerID.fromValue(closestNodes[i].kademliaId))
220
+ logger.trace('could not delete data from ' + PeerID.fromValue(closestNodes[i].kademliaId))
221
221
  }
222
222
  successfulNodes.push(closestNodes[i])
223
223
  } catch (e) {
224
- logger.debug('remoteStore.deleteData() threw an exception ' + e)
224
+ logger.trace('remoteStore.deleteData() threw an exception ' + e)
225
225
  }
226
226
  }
227
227
  }
package/src/exports.ts CHANGED
@@ -5,7 +5,7 @@ export { SimulatorTransport } from './connection/Simulator/SimulatorTransport'
5
5
  export { getRandomRegion, getRegionDelayMatrix } from './connection/Simulator/pings'
6
6
  export { PeerDescriptor, Message, NodeType, DataEntry } from './proto/packages/dht/protos/DhtRpc'
7
7
  export { ITransport } from './transport/ITransport'
8
- export { ConnectionManager, ConnectionLocker, PortRange } from './connection/ConnectionManager'
8
+ export { ConnectionManager, ConnectionLocker, PortRange, TlsCertificate } from './connection/ConnectionManager'
9
9
  export { PeerID, PeerIDKey } from './helpers/PeerID'
10
10
  export { DhtPeer } from './dht/DhtPeer'
11
11
  export { UUID } from './helpers/UUID'
@@ -33,7 +33,7 @@ class Err extends Error {
33
33
 
34
34
  export class ConnectionFailed extends Err { constructor( message?: string, originalError?: Error | string) { super(ErrorCode.CONNECTION_FAILED, message, originalError) } }
35
35
  export class CouldNotRoute extends Err { constructor(message?: string, originalError?: Error | string) { super(ErrorCode.COULD_NOT_ROUTE, message, originalError) } }
36
- export class StartingWebSocketServerFailed extends Err { constructor(message?: string, originalError?: Error | string) { super(ErrorCode.STARTING_WEBSOCKET_SERVER_FAILED, message, originalError) } }
36
+ export class WebSocketServerStartError extends Err { constructor(message?: string, originalError?: Error | string) { super(ErrorCode.STARTING_WEBSOCKET_SERVER_FAILED, message, originalError) } }
37
37
  export class WebSocketConnectionRequestRejected extends Err { constructor(message?: string, originalError?: Error | string) { super(ErrorCode.WEBSOCKET_CONNECTION_REQUEST_REJECTED, message, originalError) } }
38
38
  export class CouldNotStart extends Err { constructor(message?: string, originalError?: Error | string) { super(ErrorCode.COULD_NOT_START, message, originalError) } }
39
39
  export class CouldNotStop extends Err { constructor(message?: string, originalError?: Error | string) { super(ErrorCode.COULD_NOT_STOP, message, originalError) } }
@@ -2,9 +2,7 @@ import { IMessageType } from '@protobuf-ts/runtime'
2
2
  import {
3
3
  ClosestPeersRequest,
4
4
  ClosestPeersResponse,
5
- ConnectivityMethod,
6
- ConnectivityReportRequest,
7
- ConnectivityReportResponse,
5
+ ConnectivityMethod,
8
6
  ConnectivityRequest,
9
7
  ConnectivityResponse,
10
8
  DisconnectNotice,
@@ -41,8 +39,6 @@ export const protoClasses: Array<IMessageType<any>> = [
41
39
  LeaveNotice,
42
40
  PeerDescriptor,
43
41
  ConnectivityMethod,
44
- ConnectivityReportRequest,
45
- ConnectivityReportResponse,
46
42
  DisconnectNotice,
47
43
  RouteMessageWrapper,
48
44
  RouteMessageAck,
@@ -1,4 +1,4 @@
1
- // @generated by protobuf-ts 2.8.2 with parameter server_generic,generate_dependencies,long_type_number
1
+ // @generated by protobuf-ts 2.9.1 with parameter server_generic,generate_dependencies,long_type_number
2
2
  // @generated from protobuf file "google/protobuf/any.proto" (package "google.protobuf", syntax proto3)
3
3
  // tslint:disable
4
4
  //
@@ -1,4 +1,4 @@
1
- // @generated by protobuf-ts 2.8.2 with parameter server_generic,generate_dependencies,long_type_number
1
+ // @generated by protobuf-ts 2.9.1 with parameter server_generic,generate_dependencies,long_type_number
2
2
  // @generated from protobuf file "google/protobuf/empty.proto" (package "google.protobuf", syntax proto3)
3
3
  // tslint:disable
4
4
  //
@@ -1,4 +1,4 @@
1
- // @generated by protobuf-ts 2.8.2 with parameter server_generic,generate_dependencies,long_type_number
1
+ // @generated by protobuf-ts 2.9.1 with parameter server_generic,generate_dependencies,long_type_number
2
2
  // @generated from protobuf file "google/protobuf/timestamp.proto" (package "google.protobuf", syntax proto3)
3
3
  // tslint:disable
4
4
  //
@@ -1,4 +1,4 @@
1
- // @generated by protobuf-ts 2.8.2 with parameter server_generic,generate_dependencies,long_type_number
1
+ // @generated by protobuf-ts 2.9.1 with parameter server_generic,generate_dependencies,long_type_number
2
2
  // @generated from protobuf file "packages/dht/protos/DhtRpc.proto" (package "dht", syntax proto3)
3
3
  // tslint:disable
4
4
  import { ExternalApiService } from "./DhtRpc";
@@ -1,4 +1,4 @@
1
- // @generated by protobuf-ts 2.8.2 with parameter server_generic,generate_dependencies,long_type_number
1
+ // @generated by protobuf-ts 2.9.1 with parameter server_generic,generate_dependencies,long_type_number
2
2
  // @generated from protobuf file "packages/dht/protos/DhtRpc.proto" (package "dht", syntax proto3)
3
3
  // tslint:disable
4
4
  import { FindDataResponse } from "./DhtRpc";