@streamr/dht 0.0.1-tatum.1 → 0.0.1-tatum.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/connection/ConnectionManager.d.ts +6 -0
- package/dist/src/connection/ConnectionManager.js +6 -3
- package/dist/src/connection/ConnectionManager.js.map +1 -1
- package/dist/src/connection/ConnectivityChecker.d.ts +3 -2
- package/dist/src/connection/ConnectivityChecker.js +21 -19
- package/dist/src/connection/ConnectivityChecker.js.map +1 -1
- package/dist/src/connection/WebRTC/WebRtcConnector.d.ts +2 -0
- package/dist/src/connection/WebRTC/WebRtcConnector.js +14 -1
- package/dist/src/connection/WebRTC/WebRtcConnector.js.map +1 -1
- package/dist/src/connection/WebSocket/WebSocketConnector.d.ts +5 -3
- package/dist/src/connection/WebSocket/WebSocketConnector.js +18 -12
- package/dist/src/connection/WebSocket/WebSocketConnector.js.map +1 -1
- package/dist/src/connection/WebSocket/WebSocketServer.d.ts +2 -2
- package/dist/src/connection/WebSocket/WebSocketServer.js +27 -36
- package/dist/src/connection/WebSocket/WebSocketServer.js.map +1 -1
- package/dist/src/dht/DhtNode.d.ts +6 -2
- package/dist/src/dht/DhtNode.js +8 -6
- package/dist/src/dht/DhtNode.js.map +1 -1
- package/dist/src/dht/discovery/PeerDiscovery.d.ts +4 -2
- package/dist/src/dht/discovery/PeerDiscovery.js +18 -33
- package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
- package/dist/src/exports.d.ts +1 -1
- package/dist/src/exports.js.map +1 -1
- package/dist/src/helpers/errors.d.ts +1 -1
- package/dist/src/helpers/errors.js +3 -3
- package/dist/src/helpers/errors.js.map +1 -1
- package/dist/src/helpers/protoClasses.js +0 -2
- package/dist/src/helpers/protoClasses.js.map +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.js +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +10 -50
- package/dist/src/proto/packages/dht/protos/DhtRpc.js +8 -35
- package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -1
- package/dist/src/proto/packages/proto-rpc/protos/ProtoRpc.js +1 -1
- package/package.json +4 -4
- package/protos/DhtRpc.proto +5 -15
- package/src/connection/ConnectionManager.ts +15 -3
- package/src/connection/ConnectivityChecker.ts +25 -23
- package/src/connection/WebRTC/WebRtcConnector.ts +14 -0
- package/src/connection/WebSocket/WebSocketConnector.ts +22 -12
- package/src/connection/WebSocket/WebSocketServer.ts +31 -19
- package/src/dht/DhtNode.ts +13 -7
- package/src/dht/discovery/PeerDiscovery.ts +17 -8
- package/src/exports.ts +1 -1
- package/src/helpers/errors.ts +1 -1
- package/src/helpers/protoClasses.ts +1 -5
- package/src/proto/google/protobuf/any.ts +1 -1
- package/src/proto/google/protobuf/empty.ts +1 -1
- package/src/proto/google/protobuf/timestamp.ts +1 -1
- package/src/proto/packages/dht/protos/DhtRpc.client.ts +1 -1
- package/src/proto/packages/dht/protos/DhtRpc.server.ts +1 -1
- package/src/proto/packages/dht/protos/DhtRpc.ts +17 -69
- package/src/proto/packages/proto-rpc/protos/ProtoRpc.ts +1 -1
- package/test/end-to-end/Layer0-Layer1.test.ts +1 -1
- package/test/end-to-end/Layer0.test.ts +1 -1
- package/test/end-to-end/Layer0MixedConnectionTypes.test.ts +1 -1
- package/test/end-to-end/Layer0WebRTC-Layer1.test.ts +3 -2
- package/test/end-to-end/Layer0WebRTC.test.ts +1 -1
- package/test/end-to-end/Layer1-Scale-WebRTC.test.ts +1 -1
- package/test/end-to-end/Layer1-Scale-WebSocket.test.ts +1 -1
- package/test/end-to-end/WebSocketConnectionRequest.test.ts +1 -1
- package/test/integration/ConnectionManager.test.ts +9 -9
- package/test/integration/SimultaneousConnections.test.ts +9 -6
- package/test/integration/WebSocketConnectionManagement.test.ts +3 -2
- package/test/unit/webrtcReplaceInternalIpWithExternalIp.ts +18 -0
|
@@ -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,16 @@ 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.host, this.tlsCertificate)
|
|
105
115
|
this.selectedPort = port
|
|
106
|
-
this.connectivityChecker = new ConnectivityChecker(this.selectedPort)
|
|
116
|
+
this.connectivityChecker = new ConnectivityChecker(this.selectedPort, this.tlsCertificate !== undefined)
|
|
107
117
|
}
|
|
108
118
|
}
|
|
109
119
|
|
|
110
120
|
public async checkConnectivity(reattempt = 0): Promise<ConnectivityResponse> {
|
|
111
121
|
const noServerConnectivityResponse: ConnectivityResponse = {
|
|
112
122
|
openInternet: false,
|
|
113
|
-
|
|
123
|
+
host: '127.0.0.1',
|
|
114
124
|
natType: NatType.UNKNOWN
|
|
115
125
|
}
|
|
116
126
|
if (this.destroyed) {
|
|
@@ -125,9 +135,9 @@ export class WebSocketConnector implements IWebSocketConnectorService {
|
|
|
125
135
|
// return connectivity info given in config
|
|
126
136
|
const preconfiguredConnectivityResponse: ConnectivityResponse = {
|
|
127
137
|
openInternet: true,
|
|
128
|
-
|
|
138
|
+
host: this.host!,
|
|
129
139
|
natType: NatType.OPEN_INTERNET,
|
|
130
|
-
websocket: {
|
|
140
|
+
websocket: { host: this.host!, port: this.selectedPort!, tls: this.tlsCertificate !== undefined }
|
|
131
141
|
}
|
|
132
142
|
return preconfiguredConnectivityResponse
|
|
133
143
|
} else {
|
|
@@ -136,7 +146,8 @@ export class WebSocketConnector implements IWebSocketConnectorService {
|
|
|
136
146
|
}
|
|
137
147
|
}
|
|
138
148
|
} catch (err) {
|
|
139
|
-
if (reattempt <
|
|
149
|
+
if (reattempt < ENTRY_POINT_CONNECTION_ATTEMPTS) {
|
|
150
|
+
logger.error('Failed to connect to the entrypoint', { error: err })
|
|
140
151
|
await wait(2000)
|
|
141
152
|
return this.checkConnectivity(reattempt + 1)
|
|
142
153
|
} else {
|
|
@@ -158,8 +169,7 @@ export class WebSocketConnector implements IWebSocketConnectorService {
|
|
|
158
169
|
} else {
|
|
159
170
|
const socket = new ClientWebSocket()
|
|
160
171
|
|
|
161
|
-
const
|
|
162
|
-
targetPeerDescriptor.websocket!.port
|
|
172
|
+
const url = connectivityMethodToWebSocketUrl(targetPeerDescriptor.websocket!)
|
|
163
173
|
|
|
164
174
|
const managedConnection = new ManagedConnection(this.ownPeerDescriptor!, this.protocolVersion,
|
|
165
175
|
ConnectionType.WEBSOCKET_CLIENT, socket, undefined)
|
|
@@ -177,7 +187,7 @@ export class WebSocketConnector implements IWebSocketConnectorService {
|
|
|
177
187
|
socket.on('disconnected', delFunc)
|
|
178
188
|
managedConnection.on('handshakeCompleted', delFunc)
|
|
179
189
|
|
|
180
|
-
socket.connect(
|
|
190
|
+
socket.connect(url)
|
|
181
191
|
|
|
182
192
|
return managedConnection
|
|
183
193
|
}
|
|
@@ -189,7 +199,7 @@ export class WebSocketConnector implements IWebSocketConnectorService {
|
|
|
189
199
|
targetPeerDescriptor,
|
|
190
200
|
toProtoRpcClient(new WebSocketConnectorServiceClient(this.rpcCommunicator.getRpcClientTransport()))
|
|
191
201
|
)
|
|
192
|
-
remoteConnector.requestConnection(ownPeerDescriptor, ownPeerDescriptor.websocket!.
|
|
202
|
+
remoteConnector.requestConnection(ownPeerDescriptor, ownPeerDescriptor.websocket!.host, ownPeerDescriptor.websocket!.port)
|
|
193
203
|
})
|
|
194
204
|
const managedConnection = new ManagedConnection(this.ownPeerDescriptor!, this.protocolVersion, ConnectionType.WEBSOCKET_SERVER)
|
|
195
205
|
managedConnection.on('disconnected', () => this.ongoingConnectRequests.delete(keyFromPeerDescriptor(targetPeerDescriptor)))
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
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 {
|
|
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?:
|
|
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, host?: string, 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, host, tlsCertificate), this.abortController.signal)
|
|
34
36
|
return port
|
|
35
37
|
} catch (err) {
|
|
36
|
-
|
|
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
|
|
45
|
+
throw new WebSocketServerStartError('Failed to start WebSocket server on any port in range')
|
|
40
46
|
}
|
|
41
47
|
|
|
42
|
-
private startServer(port: number, host?: string): Promise<void> {
|
|
48
|
+
private startServer(port: number, host?: string, 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 =
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
|
84
|
+
reject(new WebSocketServerStartError('Starting Websocket server failed', err))
|
|
73
85
|
})
|
|
74
86
|
|
|
75
87
|
this.httpServer.once('listening', () => {
|
|
@@ -80,7 +92,7 @@ export class WebSocketServer extends EventEmitter<ConnectionSourceEvents> {
|
|
|
80
92
|
try {
|
|
81
93
|
this.httpServer.listen(port, host)
|
|
82
94
|
} catch (e) {
|
|
83
|
-
reject(new
|
|
95
|
+
reject(new WebSocketServerStartError('Websocket server threw an exception', e))
|
|
84
96
|
}
|
|
85
97
|
})
|
|
86
98
|
}
|
|
@@ -96,7 +108,7 @@ export class WebSocketServer extends EventEmitter<ConnectionSourceEvents> {
|
|
|
96
108
|
})
|
|
97
109
|
}
|
|
98
110
|
|
|
99
|
-
private createWsServer(httpServer:
|
|
111
|
+
private createWsServer(httpServer: HttpServer | HttpsServer): WsServer {
|
|
100
112
|
// Use the real nodejs WebSocket server in Electron tests
|
|
101
113
|
|
|
102
114
|
if (typeof NodeJsWsServer !== 'undefined') {
|
package/src/dht/DhtNode.ts
CHANGED
|
@@ -20,7 +20,7 @@ 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,
|
|
@@ -82,6 +82,8 @@ export interface DhtNodeOptions {
|
|
|
82
82
|
webrtcNewConnectionTimeout?: number
|
|
83
83
|
webrtcPortRange?: PortRange
|
|
84
84
|
maxConnections?: number
|
|
85
|
+
tlsCertificate?: TlsCertificate
|
|
86
|
+
externalIp?: string
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
export class DhtNodeConfig {
|
|
@@ -111,7 +113,9 @@ export class DhtNodeConfig {
|
|
|
111
113
|
webrtcDatachannelBufferThresholdLow?: number
|
|
112
114
|
webrtcDatachannelBufferThresholdHigh?: number
|
|
113
115
|
webrtcNewConnectionTimeout?: number
|
|
116
|
+
externalIp?: string
|
|
114
117
|
webrtcPortRange?: PortRange
|
|
118
|
+
tlsCertificate?: TlsCertificate
|
|
115
119
|
|
|
116
120
|
constructor(conf: Partial<DhtNodeOptions>) {
|
|
117
121
|
// assign given non-undefined config vars over defaults
|
|
@@ -132,13 +136,13 @@ export type Events = TransportEvents & DhtNodeEvents
|
|
|
132
136
|
export const createPeerDescriptor = (msg?: ConnectivityResponse, peerIdString?: string, nodeName?: string): PeerDescriptor => {
|
|
133
137
|
let peerId: Uint8Array
|
|
134
138
|
if (msg) {
|
|
135
|
-
peerId = peerIdString ? PeerID.fromString(peerIdString).value : PeerID.fromIp(msg.
|
|
139
|
+
peerId = peerIdString ? PeerID.fromString(peerIdString).value : PeerID.fromIp(msg.host).value
|
|
136
140
|
} else {
|
|
137
141
|
peerId = PeerID.fromString(peerIdString!).value
|
|
138
142
|
}
|
|
139
143
|
const ret: PeerDescriptor = { kademliaId: peerId, nodeName: nodeName, type: NodeType.NODEJS }
|
|
140
144
|
if (msg && msg.websocket) {
|
|
141
|
-
ret.websocket = {
|
|
145
|
+
ret.websocket = { host: msg.websocket.host, port: msg.websocket.port, tls: msg.websocket.tls }
|
|
142
146
|
ret.openInternet = true
|
|
143
147
|
}
|
|
144
148
|
return ret
|
|
@@ -208,11 +212,13 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
208
212
|
webrtcNewConnectionTimeout: this.config.webrtcNewConnectionTimeout,
|
|
209
213
|
webrtcPortRange: this.config.webrtcPortRange,
|
|
210
214
|
nodeName: this.getNodeName(),
|
|
211
|
-
maxConnections: this.config.maxConnections
|
|
215
|
+
maxConnections: this.config.maxConnections,
|
|
216
|
+
tlsCertificate: this.config.tlsCertificate,
|
|
217
|
+
externalIp: this.config.externalIp
|
|
212
218
|
}
|
|
213
219
|
// If own PeerDescriptor is given in config, create a ConnectionManager with ws server
|
|
214
220
|
if (this.config.peerDescriptor?.websocket) {
|
|
215
|
-
connectionManagerConfig.websocketHost = this.config.peerDescriptor.websocket.
|
|
221
|
+
connectionManagerConfig.websocketHost = this.config.peerDescriptor.websocket.host
|
|
216
222
|
connectionManagerConfig.websocketPortRange = {
|
|
217
223
|
min: this.config.peerDescriptor.websocket.port,
|
|
218
224
|
max: this.config.peerDescriptor.websocket.port
|
|
@@ -619,12 +625,12 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
619
625
|
await this.router!.send(msg, reachableThrough)
|
|
620
626
|
}
|
|
621
627
|
|
|
622
|
-
public async joinDht(entryPointDescriptors: PeerDescriptor[], doRandomJoin?: boolean): Promise<void> {
|
|
628
|
+
public async joinDht(entryPointDescriptors: PeerDescriptor[], doRandomJoin?: boolean, retry?: boolean): Promise<void> {
|
|
623
629
|
if (!this.started) {
|
|
624
630
|
throw new Error('Cannot join DHT before calling start() on DhtNode')
|
|
625
631
|
}
|
|
626
632
|
await Promise.all(entryPointDescriptors.map((entryPoint) =>
|
|
627
|
-
this.peerDiscovery!.joinDht(entryPoint, doRandomJoin)
|
|
633
|
+
this.peerDiscovery!.joinDht(entryPoint, doRandomJoin, retry)
|
|
628
634
|
))
|
|
629
635
|
}
|
|
630
636
|
|
|
@@ -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
|
-
|
|
98
|
+
if (retry) {
|
|
99
|
+
setAbortableTimeout(() => this.rejoinDht(entryPointDescriptor), 1000, this.abortController.signal)
|
|
100
|
+
}
|
|
96
101
|
} else {
|
|
97
|
-
await
|
|
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
|
|
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
|
}
|
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'
|
package/src/helpers/errors.ts
CHANGED
|
@@ -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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @generated by protobuf-ts 2.
|
|
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 { Empty } from "../../../google/protobuf/empty";
|
|
@@ -240,48 +240,18 @@ export interface PeerDescriptor {
|
|
|
240
240
|
* @generated from protobuf message dht.ConnectivityMethod
|
|
241
241
|
*/
|
|
242
242
|
export interface ConnectivityMethod {
|
|
243
|
-
/**
|
|
244
|
-
* @generated from protobuf field: uint32 port = 2;
|
|
245
|
-
*/
|
|
246
|
-
port: number;
|
|
247
|
-
/**
|
|
248
|
-
* @generated from protobuf field: string ip = 3;
|
|
249
|
-
*/
|
|
250
|
-
ip: string;
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* @generated from protobuf message dht.ConnectivityReportRequest
|
|
254
|
-
*/
|
|
255
|
-
export interface ConnectivityReportRequest {
|
|
256
243
|
/**
|
|
257
244
|
* @generated from protobuf field: uint32 port = 1;
|
|
258
245
|
*/
|
|
259
246
|
port: number;
|
|
260
247
|
/**
|
|
261
|
-
* @generated from protobuf field: string
|
|
262
|
-
*/
|
|
263
|
-
requestId: string;
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* @generated from protobuf message dht.ConnectivityReportResponse
|
|
267
|
-
*/
|
|
268
|
-
export interface ConnectivityReportResponse {
|
|
269
|
-
/**
|
|
270
|
-
* @generated from protobuf field: string open_internet = 1;
|
|
271
|
-
*/
|
|
272
|
-
openInternet: string;
|
|
273
|
-
/**
|
|
274
|
-
* @generated from protobuf field: string ip = 2;
|
|
275
|
-
*/
|
|
276
|
-
ip: string;
|
|
277
|
-
/**
|
|
278
|
-
* @generated from protobuf field: string natType = 3;
|
|
248
|
+
* @generated from protobuf field: string host = 2;
|
|
279
249
|
*/
|
|
280
|
-
|
|
250
|
+
host: string;
|
|
281
251
|
/**
|
|
282
|
-
* @generated from protobuf field:
|
|
252
|
+
* @generated from protobuf field: bool tls = 3;
|
|
283
253
|
*/
|
|
284
|
-
|
|
254
|
+
tls: boolean;
|
|
285
255
|
}
|
|
286
256
|
/**
|
|
287
257
|
* @generated from protobuf message dht.RouteMessageWrapper
|
|
@@ -347,6 +317,10 @@ export interface ConnectivityRequest {
|
|
|
347
317
|
* @generated from protobuf field: uint32 port = 1;
|
|
348
318
|
*/
|
|
349
319
|
port: number;
|
|
320
|
+
/**
|
|
321
|
+
* @generated from protobuf field: bool tls = 2;
|
|
322
|
+
*/
|
|
323
|
+
tls: boolean;
|
|
350
324
|
}
|
|
351
325
|
/**
|
|
352
326
|
* @generated from protobuf message dht.ConnectivityResponse
|
|
@@ -357,9 +331,9 @@ export interface ConnectivityResponse {
|
|
|
357
331
|
*/
|
|
358
332
|
openInternet: boolean;
|
|
359
333
|
/**
|
|
360
|
-
* @generated from protobuf field: string
|
|
334
|
+
* @generated from protobuf field: string host = 2;
|
|
361
335
|
*/
|
|
362
|
-
|
|
336
|
+
host: string;
|
|
363
337
|
/**
|
|
364
338
|
* @generated from protobuf field: string natType = 3;
|
|
365
339
|
*/
|
|
@@ -1007,8 +981,9 @@ export const PeerDescriptor = new PeerDescriptor$Type();
|
|
|
1007
981
|
class ConnectivityMethod$Type extends MessageType$<ConnectivityMethod> {
|
|
1008
982
|
constructor() {
|
|
1009
983
|
super("dht.ConnectivityMethod", [
|
|
1010
|
-
{ no:
|
|
1011
|
-
{ no:
|
|
984
|
+
{ no: 1, name: "port", kind: "scalar", T: 13 /*ScalarType.UINT32*/ },
|
|
985
|
+
{ no: 2, name: "host", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
986
|
+
{ no: 3, name: "tls", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
|
|
1012
987
|
]);
|
|
1013
988
|
}
|
|
1014
989
|
}
|
|
@@ -1017,34 +992,6 @@ class ConnectivityMethod$Type extends MessageType$<ConnectivityMethod> {
|
|
|
1017
992
|
*/
|
|
1018
993
|
export const ConnectivityMethod = new ConnectivityMethod$Type();
|
|
1019
994
|
// @generated message type with reflection information, may provide speed optimized methods
|
|
1020
|
-
class ConnectivityReportRequest$Type extends MessageType$<ConnectivityReportRequest> {
|
|
1021
|
-
constructor() {
|
|
1022
|
-
super("dht.ConnectivityReportRequest", [
|
|
1023
|
-
{ no: 1, name: "port", kind: "scalar", T: 13 /*ScalarType.UINT32*/ },
|
|
1024
|
-
{ no: 2, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
1025
|
-
]);
|
|
1026
|
-
}
|
|
1027
|
-
}
|
|
1028
|
-
/**
|
|
1029
|
-
* @generated MessageType for protobuf message dht.ConnectivityReportRequest
|
|
1030
|
-
*/
|
|
1031
|
-
export const ConnectivityReportRequest = new ConnectivityReportRequest$Type();
|
|
1032
|
-
// @generated message type with reflection information, may provide speed optimized methods
|
|
1033
|
-
class ConnectivityReportResponse$Type extends MessageType$<ConnectivityReportResponse> {
|
|
1034
|
-
constructor() {
|
|
1035
|
-
super("dht.ConnectivityReportResponse", [
|
|
1036
|
-
{ no: 1, name: "open_internet", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1037
|
-
{ no: 2, name: "ip", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1038
|
-
{ no: 3, name: "natType", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1039
|
-
{ no: 4, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
1040
|
-
]);
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
/**
|
|
1044
|
-
* @generated MessageType for protobuf message dht.ConnectivityReportResponse
|
|
1045
|
-
*/
|
|
1046
|
-
export const ConnectivityReportResponse = new ConnectivityReportResponse$Type();
|
|
1047
|
-
// @generated message type with reflection information, may provide speed optimized methods
|
|
1048
995
|
class RouteMessageWrapper$Type extends MessageType$<RouteMessageWrapper> {
|
|
1049
996
|
constructor() {
|
|
1050
997
|
super("dht.RouteMessageWrapper", [
|
|
@@ -1081,7 +1028,8 @@ export const RouteMessageAck = new RouteMessageAck$Type();
|
|
|
1081
1028
|
class ConnectivityRequest$Type extends MessageType$<ConnectivityRequest> {
|
|
1082
1029
|
constructor() {
|
|
1083
1030
|
super("dht.ConnectivityRequest", [
|
|
1084
|
-
{ no: 1, name: "port", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }
|
|
1031
|
+
{ no: 1, name: "port", kind: "scalar", T: 13 /*ScalarType.UINT32*/ },
|
|
1032
|
+
{ no: 2, name: "tls", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
|
|
1085
1033
|
]);
|
|
1086
1034
|
}
|
|
1087
1035
|
}
|
|
@@ -1094,7 +1042,7 @@ class ConnectivityResponse$Type extends MessageType$<ConnectivityResponse> {
|
|
|
1094
1042
|
constructor() {
|
|
1095
1043
|
super("dht.ConnectivityResponse", [
|
|
1096
1044
|
{ no: 1, name: "open_internet", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
|
1097
|
-
{ no: 2, name: "
|
|
1045
|
+
{ no: 2, name: "host", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1098
1046
|
{ no: 3, name: "natType", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1099
1047
|
{ no: 4, name: "websocket", kind: "message", T: () => ConnectivityMethod }
|
|
1100
1048
|
]);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @generated by protobuf-ts 2.
|
|
1
|
+
// @generated by protobuf-ts 2.9.1 with parameter server_generic,generate_dependencies,long_type_number
|
|
2
2
|
// @generated from protobuf file "packages/proto-rpc/protos/ProtoRpc.proto" (package "protorpc", syntax proto3)
|
|
3
3
|
// tslint:disable
|
|
4
4
|
import { MessageType } from "@protobuf-ts/runtime";
|
|
@@ -6,7 +6,7 @@ describe('Layer0-Layer1', () => {
|
|
|
6
6
|
const epPeerDescriptor: PeerDescriptor = {
|
|
7
7
|
kademliaId: Uint8Array.from([1, 2, 3]),
|
|
8
8
|
type: NodeType.NODEJS,
|
|
9
|
-
websocket: {
|
|
9
|
+
websocket: { host: '127.0.0.1', port: 10016, tls: false }
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
const STREAM_ID1 = 'stream1'
|
|
@@ -6,7 +6,7 @@ describe('Layer0', () => {
|
|
|
6
6
|
const epPeerDescriptor: PeerDescriptor = {
|
|
7
7
|
kademliaId: Uint8Array.from([1, 2, 3]),
|
|
8
8
|
type: NodeType.NODEJS,
|
|
9
|
-
websocket: {
|
|
9
|
+
websocket: { host: '127.0.0.1', port: 10011, tls: false }
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
let epDhtNode: DhtNode
|
|
@@ -8,7 +8,7 @@ describe('Layer0MixedConnectionTypes', () => {
|
|
|
8
8
|
const epPeerDescriptor: PeerDescriptor = {
|
|
9
9
|
kademliaId: Uint8Array.from([1, 2, 3]),
|
|
10
10
|
type: NodeType.NODEJS,
|
|
11
|
-
websocket: {
|
|
11
|
+
websocket: { host: '127.0.0.1', port: 11221, tls: false }
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
let epDhtNode: DhtNode
|
|
@@ -9,8 +9,9 @@ describe('Layer 1 on Layer 0 with mocked connections', () => {
|
|
|
9
9
|
kademliaId: PeerID.fromString(entryPointId).value,
|
|
10
10
|
type: NodeType.NODEJS,
|
|
11
11
|
websocket: {
|
|
12
|
-
|
|
13
|
-
port: 23232
|
|
12
|
+
host: '127.0.0.1',
|
|
13
|
+
port: 23232,
|
|
14
|
+
tls: false
|
|
14
15
|
}
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -11,7 +11,7 @@ describe('Layer0 with WebRTC connections', () => {
|
|
|
11
11
|
kademliaId: PeerID.fromString('entrypoint').value,
|
|
12
12
|
nodeName: 'entrypoint',
|
|
13
13
|
type: NodeType.NODEJS,
|
|
14
|
-
websocket: {
|
|
14
|
+
websocket: { host: '127.0.0.1', port: 10029, tls: false }
|
|
15
15
|
}
|
|
16
16
|
let epDhtNode: DhtNode
|
|
17
17
|
let node1: DhtNode
|