@streamr/dht 100.0.0 → 100.1.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/dist/package.json +6 -6
- package/dist/src/connection/ConnectionLockRpcLocal.d.ts +1 -1
- package/dist/src/connection/ConnectionLockRpcRemote.d.ts +1 -1
- package/dist/src/connection/ConnectionLockRpcRemote.js +1 -1
- package/dist/src/connection/ConnectionLockRpcRemote.js.map +1 -1
- package/dist/src/connection/{ConnectionLockHandler.d.ts → ConnectionLockStates.d.ts} +1 -1
- package/dist/src/connection/{ConnectionLockHandler.js → ConnectionLockStates.js} +4 -4
- package/dist/src/connection/ConnectionLockStates.js.map +1 -0
- package/dist/src/connection/ConnectionManager.d.ts +5 -3
- package/dist/src/connection/ConnectionManager.js +8 -11
- package/dist/src/connection/ConnectionManager.js.map +1 -1
- package/dist/src/connection/ConnectorFacade.js +1 -1
- package/dist/src/connection/ConnectorFacade.js.map +1 -1
- package/dist/src/connection/ManagedConnection.d.ts +2 -2
- package/dist/src/connection/ManagedConnection.js +8 -8
- package/dist/src/connection/ManagedConnection.js.map +1 -1
- package/dist/src/connection/connectivityChecker.js +3 -3
- package/dist/src/connection/connectivityChecker.js.map +1 -1
- package/dist/src/connection/connectivityRequestHandler.js +4 -4
- package/dist/src/connection/connectivityRequestHandler.js.map +1 -1
- package/dist/src/connection/websocket/AbstractWebsocketClientConnection.d.ts +28 -0
- package/dist/src/connection/websocket/{ClientWebsocket.js → AbstractWebsocketClientConnection.js} +42 -68
- package/dist/src/connection/websocket/AbstractWebsocketClientConnection.js.map +1 -0
- package/dist/src/connection/websocket/NodeWebsocketClientConnection.d.ts +7 -0
- package/dist/src/connection/websocket/NodeWebsocketClientConnection.js +39 -0
- package/dist/src/connection/websocket/NodeWebsocketClientConnection.js.map +1 -0
- package/dist/src/connection/websocket/WebsocketConnector.js +3 -3
- package/dist/src/connection/websocket/WebsocketConnector.js.map +1 -1
- package/dist/src/connection/websocket/WebsocketServerConnection.js +3 -3
- package/dist/src/connection/websocket/WebsocketServerConnection.js.map +1 -1
- package/dist/src/dht/DhtNode.d.ts +2 -2
- package/dist/src/dht/DhtNode.js +12 -16
- package/dist/src/dht/DhtNode.js.map +1 -1
- package/dist/src/dht/DhtNodeRpcRemote.js +1 -1
- package/dist/src/dht/DhtNodeRpcRemote.js.map +1 -1
- package/dist/src/dht/PeerManager.d.ts +4 -4
- package/dist/src/dht/PeerManager.js +33 -44
- package/dist/src/dht/PeerManager.js.map +1 -1
- package/dist/src/dht/contact/SortedContactList.d.ts +2 -1
- package/dist/src/dht/contact/SortedContactList.js +19 -17
- package/dist/src/dht/contact/SortedContactList.js.map +1 -1
- package/dist/src/dht/discovery/DiscoverySession.js +3 -1
- package/dist/src/dht/discovery/DiscoverySession.js.map +1 -1
- package/dist/src/dht/discovery/PeerDiscovery.d.ts +2 -2
- package/dist/src/dht/discovery/PeerDiscovery.js +6 -4
- package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
- package/dist/src/dht/discovery/RingDiscoverySession.js +3 -1
- package/dist/src/dht/discovery/RingDiscoverySession.js.map +1 -1
- package/dist/src/dht/recursive-operation/RecursiveOperationManager.js +1 -1
- package/dist/src/dht/recursive-operation/RecursiveOperationManager.js.map +1 -1
- package/dist/src/dht/recursive-operation/RecursiveOperationRpcRemote.js +1 -1
- package/dist/src/dht/recursive-operation/RecursiveOperationRpcRemote.js.map +1 -1
- package/dist/src/dht/routing/Router.d.ts +0 -1
- package/dist/src/dht/routing/Router.js +0 -1
- package/dist/src/dht/routing/Router.js.map +1 -1
- package/dist/src/dht/routing/RouterRpcLocal.d.ts +0 -1
- package/dist/src/dht/routing/RouterRpcLocal.js.map +1 -1
- package/dist/src/dht/routing/RouterRpcRemote.js +2 -2
- package/dist/src/dht/routing/RouterRpcRemote.js.map +1 -1
- package/dist/src/dht/routing/RoutingSession.js +2 -2
- package/dist/src/dht/routing/RoutingSession.js.map +1 -1
- package/dist/src/dht/store/LocalDataStore.js +2 -2
- package/dist/src/dht/store/LocalDataStore.js.map +1 -1
- 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 +2 -2
- package/dist/src/exports.js +3 -3
- package/dist/src/exports.js.map +1 -1
- package/karma.config.js +4 -1
- package/package.json +6 -6
- package/src/connection/ConnectionLockRpcLocal.ts +1 -1
- package/src/connection/ConnectionLockRpcRemote.ts +2 -2
- package/src/connection/{ConnectionLockHandler.ts → ConnectionLockStates.ts} +1 -1
- package/src/connection/ConnectionManager.ts +11 -12
- package/src/connection/ConnectorFacade.ts +1 -1
- package/src/connection/ManagedConnection.ts +8 -8
- package/src/connection/connectivityChecker.ts +3 -3
- package/src/connection/connectivityRequestHandler.ts +4 -4
- package/src/connection/webrtc/BrowserWebrtcConnection.ts +18 -0
- package/src/connection/websocket/{ClientWebsocket.ts → AbstractWebsocketClientConnection.ts} +57 -70
- package/src/connection/websocket/BrowserWebsocketClientConnection.ts +44 -0
- package/src/connection/websocket/NodeWebsocketClientConnection.ts +39 -0
- package/src/connection/websocket/WebsocketConnector.ts +3 -3
- package/src/connection/websocket/WebsocketServerConnection.ts +1 -1
- package/src/dht/DhtNode.ts +13 -16
- package/src/dht/DhtNodeRpcRemote.ts +1 -1
- package/src/dht/PeerManager.ts +36 -46
- package/src/dht/contact/SortedContactList.ts +22 -18
- package/src/dht/discovery/DiscoverySession.ts +3 -1
- package/src/dht/discovery/PeerDiscovery.ts +8 -6
- package/src/dht/discovery/RingDiscoverySession.ts +3 -1
- package/src/dht/recursive-operation/RecursiveOperationManager.ts +1 -1
- package/src/dht/recursive-operation/RecursiveOperationRpcRemote.ts +1 -1
- package/src/dht/routing/Router.ts +0 -2
- package/src/dht/routing/RouterRpcLocal.ts +0 -1
- package/src/dht/routing/RouterRpcRemote.ts +2 -2
- package/src/dht/routing/RoutingSession.ts +2 -2
- package/src/dht/store/LocalDataStore.ts +1 -1
- package/src/dht/store/StoreManager.ts +1 -1
- package/src/exports.ts +2 -2
- package/test/benchmark/WebsocketServerMemoryLeak.test.ts +2 -2
- package/test/integration/Find.test.ts +2 -2
- package/test/integration/ReplicateData.test.ts +3 -3
- package/test/integration/Store.test.ts +2 -2
- package/test/integration/StoreAndDelete.test.ts +2 -2
- package/test/integration/Websocket.test.ts +2 -2
- package/test/unit/PeerManager.test.ts +42 -11
- package/test/unit/Router.test.ts +0 -1
- package/test/utils/utils.ts +17 -37
- package/tsconfig.browser.json +2 -1
- package/tsconfig.jest.json +2 -1
- package/tsconfig.node.json +2 -1
- package/dist/src/connection/ConnectionLockHandler.js.map +0 -1
- package/dist/src/connection/websocket/ClientWebsocket.d.ts +0 -17
- package/dist/src/connection/websocket/ClientWebsocket.js.map +0 -1
- package/dist/src/helpers/MapWithTtl.d.ts +0 -14
- package/dist/src/helpers/MapWithTtl.js +0 -60
- package/dist/src/helpers/MapWithTtl.js.map +0 -1
- package/src/helpers/MapWithTtl.ts +0 -71
package/src/connection/websocket/{ClientWebsocket.ts → AbstractWebsocketClientConnection.ts}
RENAMED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import { Logger } from '@streamr/utils'
|
|
2
1
|
import EventEmitter from 'eventemitter3'
|
|
3
|
-
import { ICloseEvent, IMessageEvent, w3cwebsocket as Websocket } from 'websocket'
|
|
4
|
-
import { ConnectionEvents, ConnectionID, ConnectionType, IConnection } from '../IConnection'
|
|
5
2
|
import { createRandomConnectionId } from '../Connection'
|
|
3
|
+
import { ConnectionEvents, ConnectionID, ConnectionType, IConnection } from '../IConnection'
|
|
4
|
+
import { Logger } from '@streamr/utils'
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
export interface Socket {
|
|
7
|
+
binaryType: string
|
|
8
|
+
readyState: number
|
|
9
|
+
close(code?: number, reason?: string): void
|
|
10
|
+
send(data: string | Buffer | ArrayBuffer | ArrayBufferView): void
|
|
11
|
+
}
|
|
8
12
|
|
|
9
13
|
// https://kapeli.com/cheat_sheets/WebSocket_Status_Codes.docset/Contents/Resources/Documents/index
|
|
10
14
|
// Browsers send this automatically when closing a tab
|
|
@@ -12,78 +16,33 @@ export const GOING_AWAY = 1001
|
|
|
12
16
|
// The GOING_AWAY is a reserved code and we shouldn't send that from the application. Therefore
|
|
13
17
|
// we have a custom counterpart
|
|
14
18
|
export const CUSTOM_GOING_AWAY = 3001
|
|
19
|
+
// https://github.com/websockets/ws/blob/master/doc/ws.md#ready-state-constants
|
|
20
|
+
const OPEN = 1
|
|
15
21
|
|
|
16
|
-
const
|
|
22
|
+
const logger = new Logger(module)
|
|
17
23
|
|
|
18
|
-
export class
|
|
24
|
+
export abstract class AbstractWebsocketClientConnection extends EventEmitter<ConnectionEvents> implements IConnection {
|
|
19
25
|
|
|
20
26
|
public readonly connectionId: ConnectionID
|
|
21
|
-
|
|
27
|
+
protected abstract socket?: Socket
|
|
22
28
|
public connectionType = ConnectionType.WEBSOCKET_CLIENT
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
protected destroyed = false
|
|
30
|
+
|
|
26
31
|
constructor() {
|
|
27
32
|
super()
|
|
28
33
|
this.connectionId = createRandomConnectionId()
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
// TODO explicit default value for "selfSigned" or make it required
|
|
32
|
-
public connect(address: string, selfSigned?: boolean): void
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
this.socket.binaryType = BINARY_TYPE
|
|
36
|
-
this.socket.onerror = (error: Error) => {
|
|
37
|
-
if (!this.destroyed) {
|
|
38
|
-
logger.trace('WebSocket Client error: ' + error?.message, { error })
|
|
39
|
-
this.emit('error', error.name)
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
this.socket.onopen = () => {
|
|
44
|
-
if (!this.destroyed) {
|
|
45
|
-
logger.trace('WebSocket Client Connected')
|
|
46
|
-
if (this.socket && this.socket.readyState === this.socket.OPEN) {
|
|
47
|
-
this.emit('connected')
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
this.socket.onclose = (event: ICloseEvent) => {
|
|
53
|
-
if (!this.destroyed) {
|
|
54
|
-
logger.trace('Websocket Closed')
|
|
55
|
-
this.doDisconnect(event.code, event.reason)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
this.socket.onmessage = (message: IMessageEvent) => {
|
|
60
|
-
if (!this.destroyed) {
|
|
61
|
-
if (typeof message.data === 'string') {
|
|
62
|
-
logger.debug('Received string: \'' + message.data + '\'')
|
|
63
|
-
} else {
|
|
64
|
-
this.emit('data', new Uint8Array(message.data))
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
} else {
|
|
69
|
-
logger.debug('Tried to connect() a stopped connection')
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
private doDisconnect(code?: number, reason?: string) {
|
|
74
|
-
this.destroyed = true
|
|
75
|
-
this.stopListening()
|
|
76
|
-
this.socket = undefined
|
|
77
|
-
const gracefulLeave = (code === GOING_AWAY) || (code === CUSTOM_GOING_AWAY)
|
|
78
|
-
this.emit('disconnected', gracefulLeave, code, reason)
|
|
79
|
-
this.removeAllListeners()
|
|
80
|
-
}
|
|
37
|
+
public abstract connect(address: string, selfSigned?: boolean): void
|
|
38
|
+
|
|
39
|
+
protected abstract stopListening(): void
|
|
81
40
|
|
|
82
41
|
public send(data: Uint8Array): void {
|
|
83
42
|
if (!this.destroyed) {
|
|
84
|
-
if (this.socket && this.socket.readyState ===
|
|
43
|
+
if (this.socket && this.socket.readyState === OPEN) {
|
|
85
44
|
logger.trace(`Sending data with size ${data.byteLength}`)
|
|
86
|
-
this.socket?.send(data
|
|
45
|
+
this.socket?.send(data)
|
|
87
46
|
} else {
|
|
88
47
|
logger.debug('Tried to send data on a non-open connection')
|
|
89
48
|
}
|
|
@@ -103,15 +62,6 @@ export class ClientWebsocket extends EventEmitter<ConnectionEvents> implements I
|
|
|
103
62
|
}
|
|
104
63
|
}
|
|
105
64
|
|
|
106
|
-
private stopListening(): void {
|
|
107
|
-
if (this.socket) {
|
|
108
|
-
this.socket.onopen = undefined as unknown as (() => void)
|
|
109
|
-
this.socket.onclose = undefined as unknown as (() => void)
|
|
110
|
-
this.socket.onerror = undefined as unknown as (() => void)
|
|
111
|
-
this.socket.onmessage = undefined as unknown as (() => void)
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
65
|
public destroy(): void {
|
|
116
66
|
logger.trace('destroy() a connection')
|
|
117
67
|
if (!this.destroyed) {
|
|
@@ -126,4 +76,41 @@ export class ClientWebsocket extends EventEmitter<ConnectionEvents> implements I
|
|
|
126
76
|
logger.debug('Tried to destroy() a stopped connection')
|
|
127
77
|
}
|
|
128
78
|
}
|
|
79
|
+
|
|
80
|
+
protected onOpen(): void {
|
|
81
|
+
if (!this.destroyed) {
|
|
82
|
+
logger.trace('WebSocket Client Connected')
|
|
83
|
+
if (this.socket && this.socket.readyState === OPEN) {
|
|
84
|
+
this.emit('connected')
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
protected onMessage(message: Uint8Array): void {
|
|
90
|
+
this.emit('data', message)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
protected onClose(code: number, reason: string): void {
|
|
94
|
+
if (!this.destroyed) {
|
|
95
|
+
logger.trace('Websocket Closed')
|
|
96
|
+
this.doDisconnect(code, reason)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
protected onError(error: Error): void {
|
|
101
|
+
if (!this.destroyed) {
|
|
102
|
+
logger.trace('WebSocket Client error: ' + error?.message, { error })
|
|
103
|
+
this.emit('error', error.name)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
protected doDisconnect(code?: number, reason?: string): void {
|
|
108
|
+
this.destroyed = true
|
|
109
|
+
this.stopListening()
|
|
110
|
+
this.socket = undefined
|
|
111
|
+
const gracefulLeave = (code === GOING_AWAY) || (code === CUSTOM_GOING_AWAY)
|
|
112
|
+
this.emit('disconnected', gracefulLeave, code, reason)
|
|
113
|
+
this.removeAllListeners()
|
|
114
|
+
}
|
|
115
|
+
|
|
129
116
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Logger } from '@streamr/utils'
|
|
2
|
+
import { ICloseEvent, IMessageEvent, w3cwebsocket as Websocket } from 'websocket'
|
|
3
|
+
import { AbstractWebsocketClientConnection } from './AbstractWebsocketClientConnection'
|
|
4
|
+
|
|
5
|
+
const logger = new Logger(module)
|
|
6
|
+
|
|
7
|
+
const BINARY_TYPE = 'arraybuffer'
|
|
8
|
+
|
|
9
|
+
export class WebsocketClientConnection extends AbstractWebsocketClientConnection {
|
|
10
|
+
|
|
11
|
+
protected socket?: Websocket
|
|
12
|
+
|
|
13
|
+
// TODO explicit default value for "selfSigned" or make it required
|
|
14
|
+
public connect(address: string, selfSigned?: boolean): void {
|
|
15
|
+
if (!this.destroyed) {
|
|
16
|
+
this.socket = new Websocket(address, undefined, undefined, undefined, { rejectUnauthorized: !selfSigned })
|
|
17
|
+
this.socket.binaryType = BINARY_TYPE
|
|
18
|
+
this.socket.onerror = (error: Error) => this.onError(error)
|
|
19
|
+
this.socket.onopen = () => this.onOpen()
|
|
20
|
+
this.socket.onclose = (event: ICloseEvent) => this.onClose(event.code, event.reason)
|
|
21
|
+
this.socket.onmessage = (message: IMessageEvent) => {
|
|
22
|
+
if (!this.destroyed) {
|
|
23
|
+
if (typeof message.data === 'string') {
|
|
24
|
+
logger.debug('Received string data, only binary data is supported')
|
|
25
|
+
} else {
|
|
26
|
+
this.onMessage(new Uint8Array(message.data))
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
logger.debug('Tried to connect() a stopped connection')
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
protected stopListening(): void {
|
|
36
|
+
if (this.socket) {
|
|
37
|
+
this.socket.onopen = undefined as unknown as (() => void)
|
|
38
|
+
this.socket.onclose = undefined as unknown as (() => void)
|
|
39
|
+
this.socket.onerror = undefined as unknown as (() => void)
|
|
40
|
+
this.socket.onmessage = undefined as unknown as (() => void)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Logger, binaryToUtf8 } from '@streamr/utils'
|
|
2
|
+
import { WebSocket } from 'ws'
|
|
3
|
+
import { AbstractWebsocketClientConnection } from './AbstractWebsocketClientConnection'
|
|
4
|
+
|
|
5
|
+
const logger = new Logger(module)
|
|
6
|
+
|
|
7
|
+
const BINARY_TYPE = 'nodebuffer'
|
|
8
|
+
|
|
9
|
+
export class WebsocketClientConnection extends AbstractWebsocketClientConnection {
|
|
10
|
+
|
|
11
|
+
protected socket?: WebSocket
|
|
12
|
+
|
|
13
|
+
// TODO explicit default value for "selfSigned" or make it required
|
|
14
|
+
public connect(address: string, selfSigned?: boolean): void {
|
|
15
|
+
if (!this.destroyed) {
|
|
16
|
+
this.socket = new WebSocket(address, { rejectUnauthorized: !selfSigned })
|
|
17
|
+
this.socket.binaryType = BINARY_TYPE
|
|
18
|
+
this.socket.on('error', (error: Error) => this.onError(error))
|
|
19
|
+
this.socket.on('open', () => this.onOpen())
|
|
20
|
+
this.socket.on('close', (code: number, reason: Buffer) => this.onClose(code, binaryToUtf8(reason)))
|
|
21
|
+
this.socket.on('message', (message: Buffer, isBinary: boolean) => {
|
|
22
|
+
if (!this.destroyed) {
|
|
23
|
+
if (isBinary === false) {
|
|
24
|
+
logger.debug('Received string data, only binary data is supported')
|
|
25
|
+
} else {
|
|
26
|
+
this.onMessage(new Uint8Array(message))
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
} else {
|
|
31
|
+
logger.debug('Tried to connect() a stopped connection')
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
protected stopListening(): void {
|
|
36
|
+
this.socket?.removeAllListeners()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { WebsocketClientConnection } from './NodeWebsocketClientConnection'
|
|
2
2
|
import { IConnection, ConnectionType } from '../IConnection'
|
|
3
3
|
import { ITransport } from '../../transport/ITransport'
|
|
4
4
|
import { ListeningRpcCommunicator } from '../../transport/ListeningRpcCommunicator'
|
|
@@ -211,7 +211,7 @@ export class WebsocketConnector {
|
|
|
211
211
|
} catch (err) {
|
|
212
212
|
const error = `Failed to connect to entrypoint with id ${getNodeIdFromPeerDescriptor(entryPoint)} `
|
|
213
213
|
+ `and URL ${connectivityMethodToWebsocketUrl(entryPoint.websocket!)}`
|
|
214
|
-
logger.error(error, {
|
|
214
|
+
logger.error(error, { err })
|
|
215
215
|
shuffledEntrypoints.shift()
|
|
216
216
|
await wait(2000, this.abortController.signal)
|
|
217
217
|
}
|
|
@@ -234,7 +234,7 @@ export class WebsocketConnector {
|
|
|
234
234
|
if (this.localPeerDescriptor!.websocket && !targetPeerDescriptor.websocket) {
|
|
235
235
|
return this.requestConnectionFromPeer(this.localPeerDescriptor!, targetPeerDescriptor)
|
|
236
236
|
} else {
|
|
237
|
-
const socket = new
|
|
237
|
+
const socket = new WebsocketClientConnection()
|
|
238
238
|
|
|
239
239
|
const url = connectivityMethodToWebsocketUrl(targetPeerDescriptor.websocket!)
|
|
240
240
|
|
|
@@ -3,7 +3,7 @@ import { IConnection, ConnectionID, ConnectionEvents, ConnectionType } from '../
|
|
|
3
3
|
import WebSocket from 'ws'
|
|
4
4
|
import { Logger } from '@streamr/utils'
|
|
5
5
|
import { Url } from 'url'
|
|
6
|
-
import { CUSTOM_GOING_AWAY, GOING_AWAY } from './
|
|
6
|
+
import { CUSTOM_GOING_AWAY, GOING_AWAY } from './AbstractWebsocketClientConnection'
|
|
7
7
|
import { createRandomConnectionId } from '../Connection'
|
|
8
8
|
|
|
9
9
|
const logger = new Logger(module)
|
package/src/dht/DhtNode.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
import { EventEmitter } from 'eventemitter3'
|
|
9
9
|
import { sample } from 'lodash'
|
|
10
10
|
import { MarkRequired } from 'ts-essentials'
|
|
11
|
-
import { ConnectionManager, PortRange, TlsCertificate } from '../connection/ConnectionManager'
|
|
11
|
+
import { ConnectionLocker, ConnectionManager, PortRange, TlsCertificate } from '../connection/ConnectionManager'
|
|
12
12
|
import { DefaultConnectorFacade, DefaultConnectorFacadeConfig } from '../connection/ConnectorFacade'
|
|
13
13
|
import { IceServer } from '../connection/webrtc/WebrtcConnector'
|
|
14
14
|
import { isBrowserEnvironment } from '../helpers/browser/isBrowserEnvironment'
|
|
@@ -130,7 +130,7 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
130
130
|
private recursiveOperationManager?: RecursiveOperationManager
|
|
131
131
|
private peerDiscovery?: PeerDiscovery
|
|
132
132
|
private peerManager?: PeerManager
|
|
133
|
-
public
|
|
133
|
+
public connectionLocker?: ConnectionLocker
|
|
134
134
|
private region?: number
|
|
135
135
|
private started = false
|
|
136
136
|
private abortController = new AbortController()
|
|
@@ -198,7 +198,7 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
198
198
|
this.transport = this.config.transport
|
|
199
199
|
this.localPeerDescriptor = this.transport.getLocalPeerDescriptor()
|
|
200
200
|
if (this.config.transport instanceof ConnectionManager) {
|
|
201
|
-
this.
|
|
201
|
+
this.connectionLocker = this.config.transport
|
|
202
202
|
}
|
|
203
203
|
} else {
|
|
204
204
|
const connectorFacadeConfig: DefaultConnectorFacadeConfig = {
|
|
@@ -237,7 +237,7 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
237
237
|
metricsContext: this.config.metricsContext
|
|
238
238
|
})
|
|
239
239
|
await connectionManager.start()
|
|
240
|
-
this.
|
|
240
|
+
this.connectionLocker = connectionManager
|
|
241
241
|
this.transport = connectionManager
|
|
242
242
|
}
|
|
243
243
|
|
|
@@ -258,14 +258,13 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
258
258
|
joinTimeout: this.config.dhtJoinTimeout,
|
|
259
259
|
serviceId: this.config.serviceId,
|
|
260
260
|
parallelism: this.config.joinParallelism,
|
|
261
|
-
|
|
261
|
+
connectionLocker: this.connectionLocker,
|
|
262
262
|
peerManager: this.peerManager!
|
|
263
263
|
})
|
|
264
264
|
this.router = new Router({
|
|
265
265
|
rpcCommunicator: this.rpcCommunicator,
|
|
266
266
|
connections: this.peerManager!.connections,
|
|
267
267
|
localPeerDescriptor: this.localPeerDescriptor!,
|
|
268
|
-
addContact: (contact: PeerDescriptor, setActive?: boolean) => this.peerManager!.addContact([contact], setActive),
|
|
269
268
|
handleMessage: (message: Message) => this.handleMessageFromRouter(message),
|
|
270
269
|
})
|
|
271
270
|
this.recursiveOperationManager = new RecursiveOperationManager({
|
|
@@ -275,7 +274,7 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
275
274
|
connections: this.peerManager!.connections,
|
|
276
275
|
localPeerDescriptor: this.localPeerDescriptor!,
|
|
277
276
|
serviceId: this.config.serviceId,
|
|
278
|
-
addContact: (contact: PeerDescriptor) => this.peerManager!.addContact(
|
|
277
|
+
addContact: (contact: PeerDescriptor) => this.peerManager!.addContact(contact),
|
|
279
278
|
localDataStore: this.localDataStore
|
|
280
279
|
})
|
|
281
280
|
this.storeManager = new StoreManager({
|
|
@@ -311,9 +310,9 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
311
310
|
maxContactListSize: this.config.maxNeighborListSize,
|
|
312
311
|
localNodeId: this.getNodeId(),
|
|
313
312
|
localPeerDescriptor: this.localPeerDescriptor!,
|
|
314
|
-
|
|
313
|
+
connectionLocker: this.connectionLocker!,
|
|
315
314
|
peerDiscoveryQueryBatchSize: this.config.peerDiscoveryQueryBatchSize,
|
|
316
|
-
isLayer0: (this.
|
|
315
|
+
isLayer0: (this.connectionLocker !== undefined),
|
|
317
316
|
createDhtNodeRpcRemote: (peerDescriptor: PeerDescriptor) => this.createDhtNodeRpcRemote(peerDescriptor),
|
|
318
317
|
lockId: this.config.serviceId
|
|
319
318
|
})
|
|
@@ -376,7 +375,7 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
376
375
|
getClosestRingPeersTo: (ringIdRaw: RingIdRaw, limit: number) => {
|
|
377
376
|
return this.getClosestRingContactsTo(ringIdRaw, limit)
|
|
378
377
|
},
|
|
379
|
-
addContact: (contact: PeerDescriptor) => this.peerManager!.addContact(
|
|
378
|
+
addContact: (contact: PeerDescriptor) => this.peerManager!.addContact(contact),
|
|
380
379
|
removeContact: (nodeId: DhtAddress) => this.removeContact(nodeId)
|
|
381
380
|
})
|
|
382
381
|
this.rpcCommunicator!.registerRpcMethod(ClosestPeersRequest, ClosestPeersResponse, 'getClosestPeers',
|
|
@@ -418,8 +417,6 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
418
417
|
private handleMessageFromRouter(message: Message): void {
|
|
419
418
|
if (message.serviceId === this.config.serviceId) {
|
|
420
419
|
this.rpcCommunicator?.handleMessageFromPeer(message)
|
|
421
|
-
} else if (this.connectionManager?.handleIncomingMessage(message)) {
|
|
422
|
-
// message was handled by connectionManager
|
|
423
420
|
} else {
|
|
424
421
|
this.emit('message', message)
|
|
425
422
|
}
|
|
@@ -560,15 +557,15 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
560
557
|
}
|
|
561
558
|
|
|
562
559
|
public getLocalLockedConnectionCount(): number {
|
|
563
|
-
return this.
|
|
560
|
+
return this.connectionLocker!.getLocalLockedConnectionCount()
|
|
564
561
|
}
|
|
565
562
|
|
|
566
563
|
public getRemoteLockedConnectionCount(): number {
|
|
567
|
-
return this.
|
|
564
|
+
return this.connectionLocker!.getRemoteLockedConnectionCount()
|
|
568
565
|
}
|
|
569
566
|
|
|
570
567
|
public getWeakLockedConnectionCount(): number {
|
|
571
|
-
return this.
|
|
568
|
+
return this.connectionLocker!.getWeakLockedConnectionCount()
|
|
572
569
|
}
|
|
573
570
|
|
|
574
571
|
public async waitForNetworkConnectivity(): Promise<void> {
|
|
@@ -604,7 +601,7 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
604
601
|
await this.transport!.stop()
|
|
605
602
|
}
|
|
606
603
|
this.transport = undefined
|
|
607
|
-
this.
|
|
604
|
+
this.connectionLocker = undefined
|
|
608
605
|
this.removeAllListeners()
|
|
609
606
|
}
|
|
610
607
|
|
|
@@ -85,7 +85,7 @@ export class DhtNodeRpcRemote extends RpcRemote<DhtNodeRpcClient> implements KBu
|
|
|
85
85
|
return true
|
|
86
86
|
}
|
|
87
87
|
} catch (err) {
|
|
88
|
-
logger.trace(`ping failed on ${this.serviceId} to ${this.getNodeId()}
|
|
88
|
+
logger.trace(`ping failed on ${this.serviceId} to ${this.getNodeId()}`, { err })
|
|
89
89
|
}
|
|
90
90
|
return false
|
|
91
91
|
}
|
package/src/dht/PeerManager.ts
CHANGED
|
@@ -8,12 +8,12 @@ import {
|
|
|
8
8
|
import { DhtNodeRpcRemote } from './DhtNodeRpcRemote'
|
|
9
9
|
import { RandomContactList } from './contact/RandomContactList'
|
|
10
10
|
import { SortedContactList } from './contact/SortedContactList'
|
|
11
|
-
import {
|
|
11
|
+
import { ConnectionLocker } from '../connection/ConnectionManager'
|
|
12
12
|
import EventEmitter from 'eventemitter3'
|
|
13
13
|
import { DhtAddress, DhtAddressRaw, getNodeIdFromPeerDescriptor, getRawFromDhtAddress } from '../identifiers'
|
|
14
14
|
import { RingContactList, RingContacts } from './contact/RingContactList'
|
|
15
15
|
import { RingIdRaw, getRingIdRawFromPeerDescriptor } from './contact/ringIdentifiers'
|
|
16
|
-
import { LockID } from '../connection/
|
|
16
|
+
import { LockID } from '../connection/ConnectionLockStates'
|
|
17
17
|
|
|
18
18
|
const logger = new Logger(module)
|
|
19
19
|
|
|
@@ -23,7 +23,7 @@ interface PeerManagerConfig {
|
|
|
23
23
|
peerDiscoveryQueryBatchSize: number
|
|
24
24
|
localNodeId: DhtAddress
|
|
25
25
|
localPeerDescriptor: PeerDescriptor
|
|
26
|
-
|
|
26
|
+
connectionLocker?: ConnectionLocker
|
|
27
27
|
isLayer0: boolean
|
|
28
28
|
lockId: LockID
|
|
29
29
|
createDhtNodeRpcRemote: (peerDescriptor: PeerDescriptor) => DhtNodeRpcRemote
|
|
@@ -121,7 +121,7 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
121
121
|
sortingList.addContacts(oldContacts)
|
|
122
122
|
const sortedContacts = sortingList.getAllContacts()
|
|
123
123
|
const removableNodeId = sortedContacts[sortedContacts.length - 1].getNodeId()
|
|
124
|
-
this.config.
|
|
124
|
+
this.config.connectionLocker?.weakUnlockConnection(removableNodeId, this.config.lockId)
|
|
125
125
|
this.bucket.remove(getRawFromDhtAddress(removableNodeId))
|
|
126
126
|
this.bucket.add(newContact)
|
|
127
127
|
}
|
|
@@ -130,7 +130,7 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
130
130
|
if (this.stopped) {
|
|
131
131
|
return
|
|
132
132
|
}
|
|
133
|
-
this.config.
|
|
133
|
+
this.config.connectionLocker?.weakUnlockConnection(nodeId, this.config.lockId)
|
|
134
134
|
logger.trace(`Removed contact ${nodeId}`)
|
|
135
135
|
if (this.bucket.count() === 0) {
|
|
136
136
|
this.emit('kBucketEmpty')
|
|
@@ -145,7 +145,7 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
145
145
|
const peerDescriptor = contact.getPeerDescriptor()
|
|
146
146
|
const nodeId = getNodeIdFromPeerDescriptor(peerDescriptor)
|
|
147
147
|
// Important to lock here, before the ping result is known
|
|
148
|
-
this.config.
|
|
148
|
+
this.config.connectionLocker?.weakLockConnection(nodeId, this.config.lockId)
|
|
149
149
|
if (this.connections.has(contact.getNodeId())) {
|
|
150
150
|
logger.trace(`Added new contact ${nodeId}`)
|
|
151
151
|
} else { // open connection by pinging
|
|
@@ -155,13 +155,13 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
155
155
|
logger.trace(`Added new contact ${nodeId}`)
|
|
156
156
|
} else {
|
|
157
157
|
logger.trace('ping failed ' + nodeId)
|
|
158
|
-
this.config.
|
|
158
|
+
this.config.connectionLocker?.weakUnlockConnection(nodeId, this.config.lockId)
|
|
159
159
|
this.removeContact(nodeId)
|
|
160
160
|
this.addClosestContactToBucket()
|
|
161
161
|
}
|
|
162
162
|
return
|
|
163
163
|
}).catch((_e) => {
|
|
164
|
-
this.config.
|
|
164
|
+
this.config.connectionLocker?.weakUnlockConnection(nodeId, this.config.lockId)
|
|
165
165
|
this.removeContact(nodeId)
|
|
166
166
|
this.addClosestContactToBucket()
|
|
167
167
|
})
|
|
@@ -175,7 +175,7 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
175
175
|
}
|
|
176
176
|
const closest = this.getClosestActiveContactNotInBucket()
|
|
177
177
|
if (closest) {
|
|
178
|
-
this.addContact(
|
|
178
|
+
this.addContact(closest.getPeerDescriptor())
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
|
|
@@ -249,10 +249,11 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
249
249
|
referenceId,
|
|
250
250
|
allowToContainReferenceId: true,
|
|
251
251
|
emitEvents: false,
|
|
252
|
-
excludedNodeIds
|
|
252
|
+
excludedNodeIds,
|
|
253
|
+
maxSize: limit
|
|
253
254
|
})
|
|
254
255
|
this.bucket.toArray().forEach((contact) => closest.addContact(contact))
|
|
255
|
-
return closest.
|
|
256
|
+
return closest.getAllContacts()
|
|
256
257
|
}
|
|
257
258
|
|
|
258
259
|
// TODO reduce copy-paste?
|
|
@@ -261,11 +262,11 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
261
262
|
referenceId,
|
|
262
263
|
allowToContainReferenceId: true,
|
|
263
264
|
emitEvents: false,
|
|
264
|
-
excludedNodeIds
|
|
265
|
+
excludedNodeIds,
|
|
266
|
+
maxSize: limit
|
|
265
267
|
})
|
|
266
268
|
this.contacts.getAllContacts().map((contact) => closest.addContact(contact))
|
|
267
|
-
|
|
268
|
-
return closest.getClosestContacts(limit)
|
|
269
|
+
return closest.getAllContacts()
|
|
269
270
|
}
|
|
270
271
|
|
|
271
272
|
getClosestRingContactsTo(
|
|
@@ -280,13 +281,7 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
280
281
|
}
|
|
281
282
|
|
|
282
283
|
getContactCount(excludedNodeIds?: Set<DhtAddress>): number {
|
|
283
|
-
return this.contacts.
|
|
284
|
-
if (!excludedNodeIds) {
|
|
285
|
-
return true
|
|
286
|
-
} else {
|
|
287
|
-
return !excludedNodeIds.has(contact.getNodeId())
|
|
288
|
-
}
|
|
289
|
-
}).length
|
|
284
|
+
return this.contacts.getSize(excludedNodeIds)
|
|
290
285
|
}
|
|
291
286
|
|
|
292
287
|
getConnectionCount(): number {
|
|
@@ -305,35 +300,30 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
305
300
|
this.contacts.setActive(nodeId)
|
|
306
301
|
}
|
|
307
302
|
|
|
308
|
-
addContact(
|
|
303
|
+
addContact(peerDescriptor: PeerDescriptor): void {
|
|
309
304
|
if (this.stopped) {
|
|
310
305
|
return
|
|
311
306
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
const isInRingContacts = this.ringContacts.getContact(contact) !== undefined
|
|
307
|
+
const nodeId = getNodeIdFromPeerDescriptor(peerDescriptor)
|
|
308
|
+
if (nodeId !== this.config.localNodeId) {
|
|
309
|
+
logger.trace(`Adding new contact ${nodeId}`)
|
|
310
|
+
const remote = this.config.createDhtNodeRpcRemote(peerDescriptor)
|
|
311
|
+
const isInBucket = (this.bucket.get(peerDescriptor.nodeId) !== null)
|
|
312
|
+
const isInContacts = (this.contacts.getContact(nodeId) !== undefined)
|
|
313
|
+
const isInRingContacts = this.ringContacts.getContact(peerDescriptor) !== undefined
|
|
320
314
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
324
|
-
if (!isInBucket) {
|
|
325
|
-
this.bucket.add(remote)
|
|
326
|
-
}
|
|
327
|
-
if (!isInContacts) {
|
|
328
|
-
this.contacts.addContact(remote)
|
|
329
|
-
}
|
|
330
|
-
if (setActive) {
|
|
331
|
-
this.contacts.setActive(nodeId)
|
|
332
|
-
}
|
|
333
|
-
if (!isInRingContacts) {
|
|
334
|
-
this.ringContacts.addContact(remote)
|
|
335
|
-
}
|
|
315
|
+
if (isInBucket || isInContacts) {
|
|
316
|
+
this.randomPeers.addContact(remote)
|
|
336
317
|
}
|
|
337
|
-
|
|
318
|
+
if (!isInBucket) {
|
|
319
|
+
this.bucket.add(remote)
|
|
320
|
+
}
|
|
321
|
+
if (!isInContacts) {
|
|
322
|
+
this.contacts.addContact(remote)
|
|
323
|
+
}
|
|
324
|
+
if (!isInRingContacts) {
|
|
325
|
+
this.ringContacts.addContact(remote)
|
|
326
|
+
}
|
|
327
|
+
}
|
|
338
328
|
}
|
|
339
329
|
}
|
|
@@ -92,6 +92,10 @@ export class SortedContactList<C extends { getNodeId: () => DhtAddress }> extend
|
|
|
92
92
|
return this.contactsById.get(id)
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
has(id: DhtAddress): boolean {
|
|
96
|
+
return this.contactsById.has(id)
|
|
97
|
+
}
|
|
98
|
+
|
|
95
99
|
public setContacted(contactId: DhtAddress): void {
|
|
96
100
|
if (this.contactsById.has(contactId)) {
|
|
97
101
|
this.contactsById.get(contactId)!.contacted = true
|
|
@@ -105,25 +109,17 @@ export class SortedContactList<C extends { getNodeId: () => DhtAddress }> extend
|
|
|
105
109
|
}
|
|
106
110
|
|
|
107
111
|
public getClosestContacts(limit?: number): C[] {
|
|
108
|
-
const ret
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
ret.push(contact.contact)
|
|
113
|
-
}
|
|
114
|
-
})
|
|
115
|
-
if (limit === undefined) {
|
|
116
|
-
return ret
|
|
117
|
-
} else {
|
|
118
|
-
return ret.slice(0, limit)
|
|
119
|
-
}
|
|
112
|
+
const ret = this.getAllContacts()
|
|
113
|
+
return (limit === undefined)
|
|
114
|
+
? ret
|
|
115
|
+
: ret.slice(0, limit)
|
|
120
116
|
}
|
|
121
117
|
|
|
122
118
|
public getUncontactedContacts(num: number): C[] {
|
|
123
119
|
const ret: C[] = []
|
|
124
120
|
for (const contactId of this.contactIds) {
|
|
125
|
-
const contact = this.contactsById.get(contactId)
|
|
126
|
-
if (
|
|
121
|
+
const contact = this.contactsById.get(contactId)!
|
|
122
|
+
if (!contact.contacted) {
|
|
127
123
|
ret.push(contact.contact)
|
|
128
124
|
if (ret.length >= num) {
|
|
129
125
|
return ret
|
|
@@ -136,8 +132,8 @@ export class SortedContactList<C extends { getNodeId: () => DhtAddress }> extend
|
|
|
136
132
|
public getActiveContacts(limit?: number): C[] {
|
|
137
133
|
const ret: C[] = []
|
|
138
134
|
this.contactIds.forEach((contactId) => {
|
|
139
|
-
const contact = this.contactsById.get(contactId)
|
|
140
|
-
if (contact
|
|
135
|
+
const contact = this.contactsById.get(contactId)!
|
|
136
|
+
if (contact.active) {
|
|
141
137
|
ret.push(contact.contact)
|
|
142
138
|
}
|
|
143
139
|
})
|
|
@@ -187,8 +183,16 @@ export class SortedContactList<C extends { getNodeId: () => DhtAddress }> extend
|
|
|
187
183
|
return this.contactIds.map((nodeId) => this.contactsById.get(nodeId)!.contact)
|
|
188
184
|
}
|
|
189
185
|
|
|
190
|
-
public getSize(): number {
|
|
191
|
-
|
|
186
|
+
public getSize(excludedNodeIds?: Set<DhtAddress>): number {
|
|
187
|
+
let excludedCount = 0
|
|
188
|
+
if (excludedNodeIds !== undefined) {
|
|
189
|
+
for (const nodeId of excludedNodeIds) {
|
|
190
|
+
if (this.has(nodeId)) {
|
|
191
|
+
excludedCount++
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return this.contactIds.length - excludedCount
|
|
192
196
|
}
|
|
193
197
|
|
|
194
198
|
public clear(): void {
|