@streamr/dht 100.0.0-testnet-three.5 → 100.0.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.
- package/README.md +1 -1
- package/dist/package.json +14 -9
- package/dist/src/connection/ConnectionLockHandler.d.ts +2 -2
- package/dist/src/connection/ConnectionLockHandler.js +13 -5
- package/dist/src/connection/ConnectionLockHandler.js.map +1 -1
- package/dist/src/connection/ConnectionManager.d.ts +6 -5
- package/dist/src/connection/ConnectionManager.js +16 -8
- package/dist/src/connection/ConnectionManager.js.map +1 -1
- package/dist/src/connection/ConnectorFacade.js.map +1 -1
- package/dist/src/connection/Handshaker.d.ts +2 -0
- package/dist/src/connection/Handshaker.js +12 -14
- package/dist/src/connection/Handshaker.js.map +1 -1
- package/dist/src/connection/ManagedConnection.js +1 -0
- package/dist/src/connection/ManagedConnection.js.map +1 -1
- package/dist/src/connection/connectivityChecker.d.ts +1 -1
- package/dist/src/connection/connectivityChecker.js +5 -5
- package/dist/src/connection/connectivityChecker.js.map +1 -1
- package/dist/src/connection/connectivityRequestHandler.d.ts +2 -2
- package/dist/src/connection/connectivityRequestHandler.js +6 -7
- package/dist/src/connection/connectivityRequestHandler.js.map +1 -1
- package/dist/src/connection/webrtc/WebrtcConnector.d.ts +1 -0
- package/dist/src/connection/webrtc/WebrtcConnector.js +13 -8
- package/dist/src/connection/webrtc/WebrtcConnector.js.map +1 -1
- package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.d.ts +2 -0
- package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js +4 -6
- package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js.map +1 -1
- package/dist/src/connection/websocket/WebsocketConnector.js +24 -21
- package/dist/src/connection/websocket/WebsocketConnector.js.map +1 -1
- package/dist/src/connection/websocket/WebsocketServer.js +25 -35
- package/dist/src/connection/websocket/WebsocketServer.js.map +1 -1
- package/dist/src/connection/websocket/{ServerWebsocket.d.ts → WebsocketServerConnection.d.ts} +4 -5
- package/dist/src/connection/websocket/{ServerWebsocket.js → WebsocketServerConnection.js} +15 -48
- package/dist/src/connection/websocket/WebsocketServerConnection.js.map +1 -0
- package/dist/src/dht/DhtNode.d.ts +15 -7
- package/dist/src/dht/DhtNode.js +63 -21
- package/dist/src/dht/DhtNode.js.map +1 -1
- package/dist/src/dht/DhtNodeRpcLocal.d.ts +5 -1
- package/dist/src/dht/DhtNodeRpcLocal.js +10 -0
- package/dist/src/dht/DhtNodeRpcLocal.js.map +1 -1
- package/dist/src/dht/DhtNodeRpcRemote.d.ts +3 -0
- package/dist/src/dht/DhtNodeRpcRemote.js +15 -0
- package/dist/src/dht/DhtNodeRpcRemote.js.map +1 -1
- package/dist/src/dht/ExternalApiRpcLocal.d.ts +2 -2
- package/dist/src/dht/ExternalApiRpcLocal.js +3 -3
- package/dist/src/dht/ExternalApiRpcLocal.js.map +1 -1
- package/dist/src/dht/ExternalApiRpcRemote.d.ts +1 -1
- package/dist/src/dht/ExternalApiRpcRemote.js +2 -2
- package/dist/src/dht/ExternalApiRpcRemote.js.map +1 -1
- package/dist/src/dht/PeerManager.d.ts +12 -0
- package/dist/src/dht/PeerManager.js +30 -5
- package/dist/src/dht/PeerManager.js.map +1 -1
- package/dist/src/dht/contact/RingContactList.d.ts +31 -0
- package/dist/src/dht/contact/RingContactList.js +133 -0
- package/dist/src/dht/contact/RingContactList.js.map +1 -0
- package/dist/src/dht/contact/ringIdentifiers.d.ts +16 -0
- package/dist/src/dht/contact/ringIdentifiers.js +54 -0
- package/dist/src/dht/contact/ringIdentifiers.js.map +1 -0
- package/dist/src/dht/discovery/PeerDiscovery.d.ts +4 -0
- package/dist/src/dht/discovery/PeerDiscovery.js +35 -0
- package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
- package/dist/src/dht/discovery/RingDiscoverySession.d.ts +29 -0
- package/dist/src/dht/discovery/RingDiscoverySession.js +123 -0
- package/dist/src/dht/discovery/RingDiscoverySession.js.map +1 -0
- package/dist/src/dht/recursive-operation/RecursiveOperationSession.js +0 -1
- package/dist/src/dht/recursive-operation/RecursiveOperationSession.js.map +1 -1
- package/dist/src/dht/routing/Router.d.ts +5 -2
- package/dist/src/dht/routing/Router.js +17 -3
- package/dist/src/dht/routing/Router.js.map +1 -1
- package/dist/src/dht/routing/RouterRpcLocal.d.ts +2 -3
- package/dist/src/dht/routing/RouterRpcLocal.js +2 -2
- package/dist/src/dht/routing/RouterRpcLocal.js.map +1 -1
- package/dist/src/dht/routing/RoutingSession.d.ts +8 -6
- package/dist/src/dht/routing/RoutingSession.js +42 -40
- package/dist/src/dht/routing/RoutingSession.js.map +1 -1
- package/dist/src/dht/routing/RoutingTablesCache.d.ts +24 -0
- package/dist/src/dht/routing/RoutingTablesCache.js +46 -0
- package/dist/src/dht/routing/RoutingTablesCache.js.map +1 -0
- package/dist/src/dht/store/StoreManager.js +1 -1
- package/dist/src/dht/store/StoreManager.js.map +1 -1
- package/dist/src/exports.d.ts +1 -0
- package/dist/src/exports.js.map +1 -1
- package/dist/src/helpers/createPeerDescriptor.d.ts +1 -1
- package/dist/src/helpers/createPeerDescriptor.js +2 -1
- package/dist/src/helpers/createPeerDescriptor.js.map +1 -1
- package/dist/src/helpers/version.d.ts +6 -0
- package/dist/src/helpers/version.js +38 -0
- package/dist/src/helpers/version.js.map +1 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.d.ts +16 -6
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.js +11 -4
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.js.map +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +98 -87
- package/dist/src/proto/packages/dht/protos/DhtRpc.js +45 -49
- package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.server.d.ts +10 -4
- package/dist/src/transport/RoutingRpcCommunicator.js +0 -2
- package/dist/src/transport/RoutingRpcCommunicator.js.map +1 -1
- package/package.json +14 -9
- package/protos/DhtRpc.proto +21 -21
- package/src/connection/ConnectionLockHandler.ts +13 -5
- package/src/connection/ConnectionManager.ts +20 -12
- package/src/connection/ConnectorFacade.ts +0 -1
- package/src/connection/Handshaker.ts +14 -17
- package/src/connection/ManagedConnection.ts +1 -0
- package/src/connection/connectivityChecker.ts +6 -7
- package/src/connection/connectivityRequestHandler.ts +12 -12
- package/src/connection/webrtc/NodeWebrtcConnection.ts +1 -1
- package/src/connection/webrtc/WebrtcConnector.ts +14 -8
- package/src/connection/webrtc/WebrtcConnectorRpcLocal.ts +5 -5
- package/src/connection/websocket/WebsocketConnector.ts +25 -26
- package/src/connection/websocket/WebsocketServer.ts +27 -42
- package/src/connection/websocket/{ServerWebsocket.ts → WebsocketServerConnection.ts} +14 -55
- package/src/dht/DhtNode.ts +85 -40
- package/src/dht/DhtNodeRpcLocal.ts +16 -0
- package/src/dht/DhtNodeRpcRemote.ts +18 -0
- package/src/dht/ExternalApiRpcLocal.ts +5 -5
- package/src/dht/ExternalApiRpcRemote.ts +4 -4
- package/src/dht/PeerManager.ts +48 -12
- package/src/dht/contact/RingContactList.ts +151 -0
- package/src/dht/contact/ringIdentifiers.ts +62 -0
- package/src/dht/discovery/PeerDiscovery.ts +37 -0
- package/src/dht/discovery/RingDiscoverySession.ts +160 -0
- package/src/dht/recursive-operation/RecursiveOperationSession.ts +1 -3
- package/src/dht/routing/Router.ts +22 -6
- package/src/dht/routing/RouterRpcLocal.ts +4 -5
- package/src/dht/routing/RoutingSession.ts +50 -44
- package/src/dht/routing/RoutingTablesCache.ts +58 -0
- package/src/dht/store/StoreManager.ts +1 -1
- package/src/exports.ts +1 -0
- package/src/helpers/createPeerDescriptor.ts +2 -1
- package/src/helpers/version.ts +32 -0
- package/src/proto/packages/dht/protos/DhtRpc.client.ts +22 -9
- package/src/proto/packages/dht/protos/DhtRpc.server.ts +10 -4
- package/src/proto/packages/dht/protos/DhtRpc.ts +122 -100
- package/src/transport/RoutingRpcCommunicator.ts +1 -2
- package/test/benchmark/Find.test.ts +3 -4
- package/test/benchmark/KademliaCorrectness.test.ts +14 -8
- package/test/benchmark/RingCorrectness.test.ts +157 -0
- package/test/benchmark/hybrid-network-simulation/RingContactList.test.ts +72 -0
- package/test/data/generateGroundTruthData.ts +2 -2
- package/test/end-to-end/memory-leak.test.ts +1 -2
- package/test/integration/ConnectionManager.test.ts +28 -10
- package/test/integration/ConnectivityChecking.test.ts +3 -15
- package/test/integration/DhtNodeExternalAPI.test.ts +6 -6
- package/test/integration/Find.test.ts +4 -4
- package/test/integration/Layer1-scale.test.ts +0 -1
- package/test/integration/ReplicateData.test.ts +1 -1
- package/test/integration/RouteMessage.test.ts +1 -6
- package/test/integration/RouterRpcRemote.test.ts +1 -3
- package/test/integration/SimultaneousConnections.test.ts +9 -10
- package/test/integration/Store.test.ts +2 -2
- package/test/integration/StoreAndDelete.test.ts +3 -3
- package/test/integration/StoreOnDhtWithThreeNodes.test.ts +5 -5
- package/test/integration/StoreOnDhtWithTwoNodes.test.ts +3 -3
- package/test/integration/WebrtcConnectionManagement.test.ts +3 -9
- package/test/integration/WebsocketConnectionManagement.test.ts +1 -6
- package/test/integration/rpc-connections-over-webrpc.test.ts +1 -2
- package/test/unit/PeerManager.test.ts +5 -2
- package/test/unit/RecursiveOperationManager.test.ts +14 -8
- package/test/unit/RecursiveOperationSession.test.ts +1 -1
- package/test/unit/Router.test.ts +2 -3
- package/test/unit/RoutingSession.test.ts +8 -3
- package/test/unit/connectivityRequestHandler.test.ts +5 -9
- package/test/unit/createPeerDescriptor.test.ts +12 -6
- package/test/unit/version.test.ts +18 -0
- package/test/utils/mock/Router.ts +9 -0
- package/test/utils/utils.ts +43 -10
- package/tsconfig.jest.json +2 -1
- package/tsconfig.node.json +2 -1
- package/dist/src/connection/websocket/ServerWebsocket.js.map +0 -1
- package/dist/src/helpers/versionCompatibility.d.ts +0 -2
- package/dist/src/helpers/versionCompatibility.js +0 -18
- package/dist/src/helpers/versionCompatibility.js.map +0 -1
- package/src/helpers/versionCompatibility.ts +0 -13
- package/test/unit/versionCompatibility.test.ts +0 -16
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { ipv4ToNumber, Logger } from '@streamr/utils'
|
|
2
2
|
import { v4 } from 'uuid'
|
|
3
3
|
import {
|
|
4
|
-
ConnectivityRequest,
|
|
5
|
-
|
|
4
|
+
ConnectivityRequest,
|
|
5
|
+
ConnectivityResponse,
|
|
6
|
+
Message
|
|
6
7
|
} from '../proto/packages/dht/protos/DhtRpc'
|
|
7
8
|
import { NatType } from './ConnectionManager'
|
|
8
9
|
import { CONNECTIVITY_CHECKER_SERVICE_ID, connectAsync } from './connectivityChecker'
|
|
9
10
|
import { IConnection } from './IConnection'
|
|
10
|
-
import {
|
|
11
|
+
import { WebsocketServerConnection } from './websocket/WebsocketServerConnection'
|
|
11
12
|
import { connectivityMethodToWebsocketUrl } from './websocket/WebsocketConnector'
|
|
12
|
-
import {
|
|
13
|
+
import { LOCAL_PROTOCOL_VERSION } from '../helpers/version'
|
|
13
14
|
|
|
14
15
|
export const DISABLE_CONNECTIVITY_PROBE = 0
|
|
15
16
|
|
|
16
17
|
const logger = new Logger(module)
|
|
17
18
|
|
|
18
|
-
export const attachConnectivityRequestHandler = (connectionToListenTo:
|
|
19
|
+
export const attachConnectivityRequestHandler = (connectionToListenTo: WebsocketServerConnection): void => {
|
|
19
20
|
connectionToListenTo.on('data', async (data: Uint8Array) => {
|
|
20
21
|
logger.trace('server received data')
|
|
21
22
|
try {
|
|
@@ -35,9 +36,9 @@ export const attachConnectivityRequestHandler = (connectionToListenTo: ServerWeb
|
|
|
35
36
|
})
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
const handleIncomingConnectivityRequest = async (connection:
|
|
39
|
-
const host = connectivityRequest.host ?? connection.
|
|
40
|
-
const ipAddress = connection.
|
|
39
|
+
const handleIncomingConnectivityRequest = async (connection: WebsocketServerConnection, connectivityRequest: ConnectivityRequest): Promise<void> => {
|
|
40
|
+
const host = connectivityRequest.host ?? connection.remoteIpAddress
|
|
41
|
+
const ipAddress = connection.remoteIpAddress
|
|
41
42
|
let connectivityResponse: ConnectivityResponse
|
|
42
43
|
if (connectivityRequest.port !== DISABLE_CONNECTIVITY_PROBE) {
|
|
43
44
|
connectivityResponse = await connectivityProbe(connectivityRequest, ipAddress, host)
|
|
@@ -47,12 +48,11 @@ const handleIncomingConnectivityRequest = async (connection: ServerWebsocket, co
|
|
|
47
48
|
host,
|
|
48
49
|
natType: NatType.UNKNOWN,
|
|
49
50
|
ipAddress: ipv4ToNumber(ipAddress),
|
|
50
|
-
version:
|
|
51
|
+
version: LOCAL_PROTOCOL_VERSION
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
const msg: Message = {
|
|
54
55
|
serviceId: CONNECTIVITY_CHECKER_SERVICE_ID,
|
|
55
|
-
messageType: MessageType.CONNECTIVITY_RESPONSE,
|
|
56
56
|
messageId: v4(),
|
|
57
57
|
body: {
|
|
58
58
|
oneofKind: 'connectivityResponse',
|
|
@@ -84,7 +84,7 @@ const connectivityProbe = async (connectivityRequest: ConnectivityRequest, ipAdd
|
|
|
84
84
|
natType: NatType.OPEN_INTERNET,
|
|
85
85
|
websocket: { host, port: connectivityRequest.port, tls: connectivityRequest.tls },
|
|
86
86
|
ipAddress: ipv4ToNumber(ipAddress),
|
|
87
|
-
version:
|
|
87
|
+
version: LOCAL_PROTOCOL_VERSION
|
|
88
88
|
}
|
|
89
89
|
} catch (err) {
|
|
90
90
|
logger.debug('error', { err })
|
|
@@ -92,7 +92,7 @@ const connectivityProbe = async (connectivityRequest: ConnectivityRequest, ipAdd
|
|
|
92
92
|
host,
|
|
93
93
|
natType: NatType.UNKNOWN,
|
|
94
94
|
ipAddress: ipv4ToNumber(ipAddress),
|
|
95
|
-
version:
|
|
95
|
+
version: LOCAL_PROTOCOL_VERSION
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
if (outgoingConnection) {
|
|
@@ -26,7 +26,7 @@ export interface Params {
|
|
|
26
26
|
bufferThresholdLow?: number
|
|
27
27
|
connectingTimeout?: number
|
|
28
28
|
maxMessageSize?: number
|
|
29
|
-
iceServers?: IceServer[]
|
|
29
|
+
iceServers?: IceServer[] // TODO make this parameter required (empty array is a good fallback which can be set by the caller if needed)
|
|
30
30
|
portRange?: PortRange
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -75,6 +75,7 @@ export class WebrtcConnector {
|
|
|
75
75
|
onNewConnection: (connection: ManagedConnection) => boolean
|
|
76
76
|
) {
|
|
77
77
|
const localRpc = new WebrtcConnectorRpcLocal({
|
|
78
|
+
createConnection: (targetPeerDescriptor: PeerDescriptor) => this.createConnection(targetPeerDescriptor),
|
|
78
79
|
connect: (targetPeerDescriptor: PeerDescriptor) => this.connect(targetPeerDescriptor),
|
|
79
80
|
onNewConnection,
|
|
80
81
|
ongoingConnectAttempts: this.ongoingConnectAttempts,
|
|
@@ -133,14 +134,7 @@ export class WebrtcConnector {
|
|
|
133
134
|
return existingConnection
|
|
134
135
|
}
|
|
135
136
|
|
|
136
|
-
const connection =
|
|
137
|
-
remotePeerDescriptor: targetPeerDescriptor,
|
|
138
|
-
iceServers: this.config.iceServers,
|
|
139
|
-
bufferThresholdLow: this.config.bufferThresholdLow,
|
|
140
|
-
bufferThresholdHigh: this.config.bufferThresholdHigh,
|
|
141
|
-
connectingTimeout: this.config.connectionTimeout,
|
|
142
|
-
portRange: this.config.portRange
|
|
143
|
-
})
|
|
137
|
+
const connection = this.createConnection(targetPeerDescriptor)
|
|
144
138
|
|
|
145
139
|
const localNodeId = getNodeIdFromPeerDescriptor(this.localPeerDescriptor!)
|
|
146
140
|
const targetNodeId = getNodeIdFromPeerDescriptor(targetPeerDescriptor)
|
|
@@ -199,6 +193,18 @@ export class WebrtcConnector {
|
|
|
199
193
|
return managedConnection
|
|
200
194
|
}
|
|
201
195
|
|
|
196
|
+
private createConnection(targetPeerDescriptor: PeerDescriptor): NodeWebrtcConnection {
|
|
197
|
+
return new NodeWebrtcConnection({
|
|
198
|
+
remotePeerDescriptor: targetPeerDescriptor,
|
|
199
|
+
iceServers: this.config.iceServers,
|
|
200
|
+
bufferThresholdLow: this.config.bufferThresholdLow,
|
|
201
|
+
bufferThresholdHigh: this.config.bufferThresholdHigh,
|
|
202
|
+
connectingTimeout: this.config.connectionTimeout,
|
|
203
|
+
portRange: this.config.portRange
|
|
204
|
+
// TODO should we pass maxMessageSize?
|
|
205
|
+
})
|
|
206
|
+
}
|
|
207
|
+
|
|
202
208
|
setLocalPeerDescriptor(peerDescriptor: PeerDescriptor): void {
|
|
203
209
|
this.localPeerDescriptor = peerDescriptor
|
|
204
210
|
}
|
|
@@ -18,13 +18,13 @@ import { ManagedWebrtcConnection } from '../ManagedWebrtcConnection'
|
|
|
18
18
|
import { NodeWebrtcConnection } from './NodeWebrtcConnection'
|
|
19
19
|
import { WebrtcConnectorRpcRemote } from './WebrtcConnectorRpcRemote'
|
|
20
20
|
import { DhtAddress, getNodeIdFromPeerDescriptor } from '../../identifiers'
|
|
21
|
-
import {
|
|
22
|
-
import { isCompatibleVersion } from '../../helpers/versionCompatibility'
|
|
21
|
+
import { isMaybeSupportedVersion } from '../../helpers/version'
|
|
23
22
|
import { ConnectionID } from '../IConnection'
|
|
24
23
|
|
|
25
24
|
const logger = new Logger(module)
|
|
26
25
|
|
|
27
26
|
interface WebrtcConnectorRpcLocalConfig {
|
|
27
|
+
createConnection: (targetPeerDescriptor: PeerDescriptor) => NodeWebrtcConnection
|
|
28
28
|
connect: (targetPeerDescriptor: PeerDescriptor) => ManagedConnection
|
|
29
29
|
onNewConnection: (connection: ManagedConnection) => boolean
|
|
30
30
|
// TODO pass accessor methods instead of passing a mutable entity
|
|
@@ -60,7 +60,7 @@ export class WebrtcConnectorRpcLocal implements IWebrtcConnectorRpc {
|
|
|
60
60
|
let connection = managedConnection?.getWebrtcConnection()
|
|
61
61
|
|
|
62
62
|
if (!managedConnection) {
|
|
63
|
-
connection =
|
|
63
|
+
connection = this.config.createConnection(remotePeer)
|
|
64
64
|
managedConnection = new ManagedWebrtcConnection(this.config.getLocalPeerDescriptor(), undefined, connection)
|
|
65
65
|
managedConnection.setRemotePeerDescriptor(remotePeer)
|
|
66
66
|
this.config.ongoingConnectAttempts.set(nodeId, managedConnection)
|
|
@@ -84,11 +84,11 @@ export class WebrtcConnectorRpcLocal implements IWebrtcConnectorRpc {
|
|
|
84
84
|
connection!.setConnectionId(request.connectionId as ConnectionID)
|
|
85
85
|
connection!.setRemoteDescription(request.description, 'offer')
|
|
86
86
|
|
|
87
|
-
managedConnection.on('handshakeRequest', (_sourceDescriptor: PeerDescriptor,
|
|
87
|
+
managedConnection.on('handshakeRequest', (_sourceDescriptor: PeerDescriptor, remoteVersion: string) => {
|
|
88
88
|
if (this.config.ongoingConnectAttempts.has(nodeId)) {
|
|
89
89
|
this.config.ongoingConnectAttempts.delete(nodeId)
|
|
90
90
|
}
|
|
91
|
-
if (!
|
|
91
|
+
if (!isMaybeSupportedVersion(remoteVersion)) {
|
|
92
92
|
managedConnection!.rejectHandshake(HandshakeError.UNSUPPORTED_VERSION)
|
|
93
93
|
} else {
|
|
94
94
|
managedConnection!.acceptHandshake()
|
|
@@ -17,10 +17,10 @@ import { ManagedConnection } from '../ManagedConnection'
|
|
|
17
17
|
import { WebsocketServer } from './WebsocketServer'
|
|
18
18
|
import { sendConnectivityRequest } from '../connectivityChecker'
|
|
19
19
|
import { NatType, PortRange, TlsCertificate } from '../ConnectionManager'
|
|
20
|
-
import {
|
|
20
|
+
import { WebsocketServerConnection } from './WebsocketServerConnection'
|
|
21
21
|
import { Handshaker } from '../Handshaker'
|
|
22
|
-
import
|
|
23
|
-
import {
|
|
22
|
+
import queryString from 'querystring'
|
|
23
|
+
import { shuffle } from 'lodash'
|
|
24
24
|
import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
|
|
25
25
|
import { expectedConnectionType } from '../../helpers/Connectivity'
|
|
26
26
|
import { WebsocketServerStartError } from '../../helpers/errors'
|
|
@@ -29,8 +29,7 @@ import { DISABLE_CONNECTIVITY_PROBE, attachConnectivityRequestHandler } from '..
|
|
|
29
29
|
import * as Err from '../../helpers/errors'
|
|
30
30
|
import { Empty } from '../../proto/google/protobuf/empty'
|
|
31
31
|
import { DhtAddress, areEqualPeerDescriptors, getNodeIdFromPeerDescriptor } from '../../identifiers'
|
|
32
|
-
import {
|
|
33
|
-
import { isCompatibleVersion } from '../../helpers/versionCompatibility'
|
|
32
|
+
import { LOCAL_PROTOCOL_VERSION, isMaybeSupportedVersion } from '../../helpers/version'
|
|
34
33
|
|
|
35
34
|
const logger = new Logger(module)
|
|
36
35
|
|
|
@@ -143,10 +142,10 @@ export class WebsocketConnector {
|
|
|
143
142
|
public async start(): Promise<void> {
|
|
144
143
|
if (!this.abortController.signal.aborted && this.websocketServer) {
|
|
145
144
|
this.websocketServer.on('connected', (connection: IConnection) => {
|
|
146
|
-
const serverSocket = connection as unknown as
|
|
147
|
-
const query = serverSocket.resourceURL.query as
|
|
148
|
-
const action = query
|
|
149
|
-
logger.trace('WebSocket client connected', { action, remoteAddress: serverSocket.
|
|
145
|
+
const serverSocket = connection as unknown as WebsocketServerConnection
|
|
146
|
+
const query = queryString.parse(serverSocket.resourceURL.query as string ?? '')
|
|
147
|
+
const action = query.action as (Action | undefined)
|
|
148
|
+
logger.trace('WebSocket client connected', { action, remoteAddress: serverSocket.remoteIpAddress })
|
|
150
149
|
if (action === 'connectivityRequest') {
|
|
151
150
|
attachConnectivityRequestHandler(serverSocket)
|
|
152
151
|
} else if (action === 'connectivityProbe') {
|
|
@@ -175,7 +174,7 @@ export class WebsocketConnector {
|
|
|
175
174
|
host: '127.0.0.1',
|
|
176
175
|
natType: NatType.UNKNOWN,
|
|
177
176
|
ipAddress: ipv4ToNumber('127.0.0.1'),
|
|
178
|
-
version:
|
|
177
|
+
version: LOCAL_PROTOCOL_VERSION
|
|
179
178
|
}
|
|
180
179
|
}
|
|
181
180
|
if (!this.config.entrypoints || this.config.entrypoints.length === 0) {
|
|
@@ -190,11 +189,12 @@ export class WebsocketConnector {
|
|
|
190
189
|
},
|
|
191
190
|
// TODO: Resolve the given host name or or use as is if IP was given.
|
|
192
191
|
ipAddress: ipv4ToNumber('127.0.0.1'),
|
|
193
|
-
version:
|
|
192
|
+
version: LOCAL_PROTOCOL_VERSION
|
|
194
193
|
}
|
|
195
194
|
}
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
const shuffledEntrypoints = shuffle(this.config.entrypoints)
|
|
196
|
+
while (shuffledEntrypoints.length > 0 && !this.abortController.signal.aborted) {
|
|
197
|
+
const entryPoint = shuffledEntrypoints[0]
|
|
198
198
|
try {
|
|
199
199
|
// Do real connectivity checking
|
|
200
200
|
const connectivityRequest = {
|
|
@@ -204,17 +204,16 @@ export class WebsocketConnector {
|
|
|
204
204
|
selfSigned
|
|
205
205
|
}
|
|
206
206
|
if (!this.abortController.signal.aborted) {
|
|
207
|
-
return await sendConnectivityRequest(connectivityRequest, entryPoint
|
|
207
|
+
return await sendConnectivityRequest(connectivityRequest, entryPoint)
|
|
208
208
|
} else {
|
|
209
209
|
throw new Err.ConnectionFailed('ConnectivityChecker is destroyed')
|
|
210
210
|
}
|
|
211
211
|
} catch (err) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
212
|
+
const error = `Failed to connect to entrypoint with id ${getNodeIdFromPeerDescriptor(entryPoint)} `
|
|
213
|
+
+ `and URL ${connectivityMethodToWebsocketUrl(entryPoint.websocket!)}`
|
|
214
|
+
logger.error(error, { error: err })
|
|
215
|
+
shuffledEntrypoints.shift()
|
|
216
|
+
await wait(2000, this.abortController.signal)
|
|
218
217
|
}
|
|
219
218
|
}
|
|
220
219
|
throw new WebsocketServerStartError(`Failed to connect to the entrypoints after ${ENTRY_POINT_CONNECTION_ATTEMPTS} attempts`)
|
|
@@ -299,17 +298,17 @@ export class WebsocketConnector {
|
|
|
299
298
|
|
|
300
299
|
private onServerSocketHandshakeRequest(
|
|
301
300
|
sourcePeerDescriptor: PeerDescriptor,
|
|
302
|
-
|
|
303
|
-
|
|
301
|
+
websocketServerConnection: IConnection,
|
|
302
|
+
remoteVersion: string,
|
|
304
303
|
targetPeerDescriptor?: PeerDescriptor
|
|
305
304
|
) {
|
|
306
305
|
const nodeId = getNodeIdFromPeerDescriptor(sourcePeerDescriptor)
|
|
307
306
|
if (this.ongoingConnectRequests.has(nodeId)) {
|
|
308
307
|
const ongoingConnectRequest = this.ongoingConnectRequests.get(nodeId)!
|
|
309
|
-
if (!
|
|
308
|
+
if (!isMaybeSupportedVersion(remoteVersion)) {
|
|
310
309
|
ongoingConnectRequest.rejectHandshake(HandshakeError.UNSUPPORTED_VERSION)
|
|
311
310
|
} else {
|
|
312
|
-
ongoingConnectRequest.attachImplementation(
|
|
311
|
+
ongoingConnectRequest.attachImplementation(websocketServerConnection)
|
|
313
312
|
ongoingConnectRequest.acceptHandshake()
|
|
314
313
|
}
|
|
315
314
|
this.ongoingConnectRequests.delete(nodeId)
|
|
@@ -318,11 +317,11 @@ export class WebsocketConnector {
|
|
|
318
317
|
this.localPeerDescriptor!,
|
|
319
318
|
ConnectionType.WEBSOCKET_SERVER,
|
|
320
319
|
undefined,
|
|
321
|
-
|
|
320
|
+
websocketServerConnection,
|
|
322
321
|
targetPeerDescriptor
|
|
323
322
|
)
|
|
324
323
|
managedConnection.setRemotePeerDescriptor(sourcePeerDescriptor)
|
|
325
|
-
if (!
|
|
324
|
+
if (!isMaybeSupportedVersion(remoteVersion)) {
|
|
326
325
|
managedConnection.rejectHandshake(HandshakeError.UNSUPPORTED_VERSION)
|
|
327
326
|
} else if (targetPeerDescriptor && !areEqualPeerDescriptors(this.localPeerDescriptor!, targetPeerDescriptor)) {
|
|
328
327
|
managedConnection.rejectHandshake(HandshakeError.INVALID_TARGET_PEER_DESCRIPTOR)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createServer as createHttpServer, Server as HttpServer, IncomingMessage, ServerResponse } from 'http'
|
|
2
2
|
import { createServer as createHttpsServer, Server as HttpsServer } from 'https'
|
|
3
3
|
import EventEmitter from 'eventemitter3'
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
4
|
+
import WebSocket from 'ws'
|
|
5
|
+
import { WebsocketServerConnection } from './WebsocketServerConnection'
|
|
6
6
|
import { ConnectionSourceEvents } from '../IConnectionSource'
|
|
7
7
|
import { Logger, asAbortable } from '@streamr/utils'
|
|
8
8
|
import { createSelfSignedCertificate } from '@streamr/autocertifier-client'
|
|
@@ -11,16 +11,10 @@ import { PortRange, TlsCertificate } from '../ConnectionManager'
|
|
|
11
11
|
import { range } from 'lodash'
|
|
12
12
|
import fs from 'fs'
|
|
13
13
|
import { v4 as uuid } from 'uuid'
|
|
14
|
+
import { parse } from 'url'
|
|
14
15
|
|
|
15
16
|
const logger = new Logger(module)
|
|
16
17
|
|
|
17
|
-
// NodeJsWsServer is declared as a global in test-browser Electron tests
|
|
18
|
-
// in preload.js using "window.NodeJsWsServer = require('websocket').server".
|
|
19
|
-
// This is done in order to use the real nodejs websocket server in tests
|
|
20
|
-
// instead of a dummy polyfill.
|
|
21
|
-
|
|
22
|
-
declare class NodeJsWsServer extends WsServer { }
|
|
23
|
-
|
|
24
18
|
interface WebsocketServerConfig {
|
|
25
19
|
portRange: PortRange
|
|
26
20
|
enableTls: boolean
|
|
@@ -31,7 +25,7 @@ interface WebsocketServerConfig {
|
|
|
31
25
|
export class WebsocketServer extends EventEmitter<ConnectionSourceEvents> {
|
|
32
26
|
|
|
33
27
|
private httpServer?: HttpServer | HttpsServer
|
|
34
|
-
private wsServer?:
|
|
28
|
+
private wsServer?: WebSocket.Server
|
|
35
29
|
private readonly abortController = new AbortController()
|
|
36
30
|
private readonly config: WebsocketServerConfig
|
|
37
31
|
|
|
@@ -88,28 +82,26 @@ export class WebsocketServer extends EventEmitter<ConnectionSourceEvents> {
|
|
|
88
82
|
return true
|
|
89
83
|
}
|
|
90
84
|
|
|
91
|
-
this.wsServer = this.createWsServer(
|
|
85
|
+
this.wsServer = this.createWsServer()
|
|
92
86
|
|
|
93
|
-
this.wsServer.on('
|
|
87
|
+
this.wsServer.on('connection', (ws: WebSocket, request: IncomingMessage) => {
|
|
88
|
+
logger.trace(`New connection from ${request.socket.remoteAddress}`)
|
|
94
89
|
if (!originIsAllowed()) {
|
|
95
90
|
// Make sure we only accept requests from an allowed origin
|
|
96
|
-
|
|
97
|
-
logger.trace('IConnection from origin ' + request.origin + ' rejected.')
|
|
91
|
+
ws.close()
|
|
92
|
+
logger.trace('IConnection from origin ' + request.headers.origin + ' rejected.')
|
|
98
93
|
return
|
|
99
94
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
connection = request.accept(undefined, request.origin)
|
|
104
|
-
logger.trace('Connection accepted.', { remoteAddress: request.remoteAddress })
|
|
105
|
-
} catch (err) {
|
|
106
|
-
logger.debug('Accepting websocket connection failed', { remoteAddress: request.remoteAddress, err })
|
|
107
|
-
}
|
|
95
|
+
this.emit('connected', new WebsocketServerConnection(ws, parse(request.url!), request.socket.remoteAddress!))
|
|
96
|
+
})
|
|
108
97
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
98
|
+
this.httpServer.on('upgrade', (request, socket, head) => {
|
|
99
|
+
logger.trace('Received upgrade request for ' + request.url)
|
|
100
|
+
this.wsServer!.handleUpgrade(request, socket, head, (ws: WebSocket) => {
|
|
101
|
+
this.wsServer!.emit('connection', ws, request)
|
|
102
|
+
})
|
|
112
103
|
})
|
|
104
|
+
|
|
113
105
|
this.httpServer.once('error', (err: Error) => {
|
|
114
106
|
reject(new WebsocketServerStartError('Starting Websocket server failed', err))
|
|
115
107
|
})
|
|
@@ -139,7 +131,10 @@ export class WebsocketServer extends EventEmitter<ConnectionSourceEvents> {
|
|
|
139
131
|
this.abortController.abort()
|
|
140
132
|
this.removeAllListeners()
|
|
141
133
|
return new Promise((resolve, _reject) => {
|
|
142
|
-
this.wsServer
|
|
134
|
+
this.wsServer!.close()
|
|
135
|
+
for (const ws of this.wsServer!.clients) {
|
|
136
|
+
ws.terminate()
|
|
137
|
+
}
|
|
143
138
|
this.httpServer?.once('close', () => {
|
|
144
139
|
// removeAllListeners is maybe not needed?
|
|
145
140
|
this.httpServer?.removeAllListeners()
|
|
@@ -155,21 +150,11 @@ export class WebsocketServer extends EventEmitter<ConnectionSourceEvents> {
|
|
|
155
150
|
})
|
|
156
151
|
}
|
|
157
152
|
|
|
158
|
-
private createWsServer(
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
autoAcceptConnections: false,
|
|
165
|
-
maxReceivedMessageSize
|
|
166
|
-
})
|
|
167
|
-
} else {
|
|
168
|
-
return this.wsServer = new WsServer({
|
|
169
|
-
httpServer,
|
|
170
|
-
autoAcceptConnections: false,
|
|
171
|
-
maxReceivedMessageSize
|
|
172
|
-
})
|
|
173
|
-
}
|
|
153
|
+
private createWsServer(): WebSocket.Server {
|
|
154
|
+
const maxPayload = this.config.maxMessageSize ?? 1048576
|
|
155
|
+
return this.wsServer = new WebSocket.Server({
|
|
156
|
+
noServer: true,
|
|
157
|
+
maxPayload
|
|
158
|
+
})
|
|
174
159
|
}
|
|
175
160
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import EventEmitter from 'eventemitter3'
|
|
2
2
|
import { IConnection, ConnectionID, ConnectionEvents, ConnectionType } from '../IConnection'
|
|
3
|
-
import
|
|
3
|
+
import WebSocket from 'ws'
|
|
4
4
|
import { Logger } from '@streamr/utils'
|
|
5
5
|
import { Url } from 'url'
|
|
6
6
|
import { CUSTOM_GOING_AWAY, GOING_AWAY } from './ClientWebsocket'
|
|
@@ -8,26 +8,16 @@ import { createRandomConnectionId } from '../Connection'
|
|
|
8
8
|
|
|
9
9
|
const logger = new Logger(module)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
// It is used to make Karma/Electron tests to use the NodeJS
|
|
13
|
-
// implementation of Buffer instead of the browser polyfill
|
|
14
|
-
|
|
15
|
-
declare let NodeJsBuffer: BufferConstructor
|
|
16
|
-
|
|
17
|
-
enum MessageType {
|
|
18
|
-
UTF8 = 'utf8',
|
|
19
|
-
BINARY = 'binary'
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export class ServerWebsocket extends EventEmitter<ConnectionEvents> implements IConnection {
|
|
11
|
+
export class WebsocketServerConnection extends EventEmitter<ConnectionEvents> implements IConnection {
|
|
23
12
|
|
|
24
13
|
public readonly connectionId: ConnectionID
|
|
25
14
|
public readonly connectionType = ConnectionType.WEBSOCKET_SERVER
|
|
26
15
|
public readonly resourceURL: Url
|
|
27
|
-
|
|
16
|
+
public readonly remoteIpAddress: string
|
|
17
|
+
private socket?: WebSocket
|
|
28
18
|
private stopped = false
|
|
29
19
|
|
|
30
|
-
constructor(socket:
|
|
20
|
+
constructor(socket: WebSocket, resourceURL: Url, remoteAddress: string) {
|
|
31
21
|
super()
|
|
32
22
|
|
|
33
23
|
this.onMessage = this.onMessage.bind(this)
|
|
@@ -36,6 +26,7 @@ export class ServerWebsocket extends EventEmitter<ConnectionEvents> implements I
|
|
|
36
26
|
|
|
37
27
|
this.resourceURL = resourceURL
|
|
38
28
|
this.connectionId = createRandomConnectionId()
|
|
29
|
+
this.remoteIpAddress = remoteAddress
|
|
39
30
|
|
|
40
31
|
socket.on('message', this.onMessage)
|
|
41
32
|
socket.on('close', this.onClose)
|
|
@@ -44,20 +35,17 @@ export class ServerWebsocket extends EventEmitter<ConnectionEvents> implements I
|
|
|
44
35
|
this.socket = socket
|
|
45
36
|
}
|
|
46
37
|
|
|
47
|
-
private onMessage(message:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
this.emit('data',
|
|
54
|
-
new Uint8Array(message.binaryData.buffer, message.binaryData.byteOffset,
|
|
55
|
-
message.binaryData.byteLength / Uint8Array.BYTES_PER_ELEMENT))
|
|
38
|
+
private onMessage(message: WebSocket.RawData, isBinary: boolean): void {
|
|
39
|
+
if (!isBinary) {
|
|
40
|
+
logger.trace('Received string Message')
|
|
41
|
+
} else {
|
|
42
|
+
logger.trace('Websocket server received Message')
|
|
43
|
+
this.emit('data', new Uint8Array(message as Buffer))
|
|
56
44
|
}
|
|
57
45
|
}
|
|
58
46
|
|
|
59
47
|
private onClose(reasonCode: number, description: string): void {
|
|
60
|
-
logger.trace('Peer ' + this.
|
|
48
|
+
logger.trace('Peer ' + this.remoteIpAddress + ' disconnected.')
|
|
61
49
|
this.doDisconnect(reasonCode, description)
|
|
62
50
|
}
|
|
63
51
|
|
|
@@ -80,16 +68,9 @@ export class ServerWebsocket extends EventEmitter<ConnectionEvents> implements I
|
|
|
80
68
|
}
|
|
81
69
|
|
|
82
70
|
public send(data: Uint8Array): void {
|
|
83
|
-
// If in an Karma / Electron test, use the NodeJS implementation
|
|
84
|
-
// of Buffer instead of the browser polyfill
|
|
85
|
-
|
|
86
71
|
// TODO: no need to check this.socket as it is always defined when stopped is false?
|
|
87
72
|
if (!this.stopped && this.socket) {
|
|
88
|
-
|
|
89
|
-
this.socket.sendBytes(NodeJsBuffer.from(data))
|
|
90
|
-
} else {
|
|
91
|
-
this.socket.sendBytes(Buffer.from(data))
|
|
92
|
-
}
|
|
73
|
+
this.socket.send(data, { binary: true })
|
|
93
74
|
} else {
|
|
94
75
|
logger.debug('Tried to call send() on a stopped socket')
|
|
95
76
|
}
|
|
@@ -120,26 +101,4 @@ export class ServerWebsocket extends EventEmitter<ConnectionEvents> implements I
|
|
|
120
101
|
logger.debug('Tried to destroy() a stopped connection')
|
|
121
102
|
}
|
|
122
103
|
}
|
|
123
|
-
|
|
124
|
-
public getRemoteAddress(): string {
|
|
125
|
-
// TODO: no need to check this.socket as it is always defined when stopped is false?
|
|
126
|
-
if (!this.stopped && this.socket) {
|
|
127
|
-
return this.socket.remoteAddress
|
|
128
|
-
} else {
|
|
129
|
-
// TODO throw
|
|
130
|
-
logger.error('Tried to get the remoteAddress of a stopped connection')
|
|
131
|
-
return ''
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
public getRemoteIp(): string {
|
|
136
|
-
// TODO: no need to check this.socket as it is always defined when stopped is false?
|
|
137
|
-
if (!this.stopped && this.socket) {
|
|
138
|
-
return this.socket.socket.remoteAddress!
|
|
139
|
-
} else {
|
|
140
|
-
// TODO throw
|
|
141
|
-
logger.error('Tried to get the remoteAddress of a stopped connection')
|
|
142
|
-
return ''
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
104
|
}
|