@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.
Files changed (119) hide show
  1. package/dist/package.json +6 -6
  2. package/dist/src/connection/ConnectionLockRpcLocal.d.ts +1 -1
  3. package/dist/src/connection/ConnectionLockRpcRemote.d.ts +1 -1
  4. package/dist/src/connection/ConnectionLockRpcRemote.js +1 -1
  5. package/dist/src/connection/ConnectionLockRpcRemote.js.map +1 -1
  6. package/dist/src/connection/{ConnectionLockHandler.d.ts → ConnectionLockStates.d.ts} +1 -1
  7. package/dist/src/connection/{ConnectionLockHandler.js → ConnectionLockStates.js} +4 -4
  8. package/dist/src/connection/ConnectionLockStates.js.map +1 -0
  9. package/dist/src/connection/ConnectionManager.d.ts +5 -3
  10. package/dist/src/connection/ConnectionManager.js +8 -11
  11. package/dist/src/connection/ConnectionManager.js.map +1 -1
  12. package/dist/src/connection/ConnectorFacade.js +1 -1
  13. package/dist/src/connection/ConnectorFacade.js.map +1 -1
  14. package/dist/src/connection/ManagedConnection.d.ts +2 -2
  15. package/dist/src/connection/ManagedConnection.js +8 -8
  16. package/dist/src/connection/ManagedConnection.js.map +1 -1
  17. package/dist/src/connection/connectivityChecker.js +3 -3
  18. package/dist/src/connection/connectivityChecker.js.map +1 -1
  19. package/dist/src/connection/connectivityRequestHandler.js +4 -4
  20. package/dist/src/connection/connectivityRequestHandler.js.map +1 -1
  21. package/dist/src/connection/websocket/AbstractWebsocketClientConnection.d.ts +28 -0
  22. package/dist/src/connection/websocket/{ClientWebsocket.js → AbstractWebsocketClientConnection.js} +42 -68
  23. package/dist/src/connection/websocket/AbstractWebsocketClientConnection.js.map +1 -0
  24. package/dist/src/connection/websocket/NodeWebsocketClientConnection.d.ts +7 -0
  25. package/dist/src/connection/websocket/NodeWebsocketClientConnection.js +39 -0
  26. package/dist/src/connection/websocket/NodeWebsocketClientConnection.js.map +1 -0
  27. package/dist/src/connection/websocket/WebsocketConnector.js +3 -3
  28. package/dist/src/connection/websocket/WebsocketConnector.js.map +1 -1
  29. package/dist/src/connection/websocket/WebsocketServerConnection.js +3 -3
  30. package/dist/src/connection/websocket/WebsocketServerConnection.js.map +1 -1
  31. package/dist/src/dht/DhtNode.d.ts +2 -2
  32. package/dist/src/dht/DhtNode.js +12 -16
  33. package/dist/src/dht/DhtNode.js.map +1 -1
  34. package/dist/src/dht/DhtNodeRpcRemote.js +1 -1
  35. package/dist/src/dht/DhtNodeRpcRemote.js.map +1 -1
  36. package/dist/src/dht/PeerManager.d.ts +4 -4
  37. package/dist/src/dht/PeerManager.js +33 -44
  38. package/dist/src/dht/PeerManager.js.map +1 -1
  39. package/dist/src/dht/contact/SortedContactList.d.ts +2 -1
  40. package/dist/src/dht/contact/SortedContactList.js +19 -17
  41. package/dist/src/dht/contact/SortedContactList.js.map +1 -1
  42. package/dist/src/dht/discovery/DiscoverySession.js +3 -1
  43. package/dist/src/dht/discovery/DiscoverySession.js.map +1 -1
  44. package/dist/src/dht/discovery/PeerDiscovery.d.ts +2 -2
  45. package/dist/src/dht/discovery/PeerDiscovery.js +6 -4
  46. package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
  47. package/dist/src/dht/discovery/RingDiscoverySession.js +3 -1
  48. package/dist/src/dht/discovery/RingDiscoverySession.js.map +1 -1
  49. package/dist/src/dht/recursive-operation/RecursiveOperationManager.js +1 -1
  50. package/dist/src/dht/recursive-operation/RecursiveOperationManager.js.map +1 -1
  51. package/dist/src/dht/recursive-operation/RecursiveOperationRpcRemote.js +1 -1
  52. package/dist/src/dht/recursive-operation/RecursiveOperationRpcRemote.js.map +1 -1
  53. package/dist/src/dht/routing/Router.d.ts +0 -1
  54. package/dist/src/dht/routing/Router.js +0 -1
  55. package/dist/src/dht/routing/Router.js.map +1 -1
  56. package/dist/src/dht/routing/RouterRpcLocal.d.ts +0 -1
  57. package/dist/src/dht/routing/RouterRpcLocal.js.map +1 -1
  58. package/dist/src/dht/routing/RouterRpcRemote.js +2 -2
  59. package/dist/src/dht/routing/RouterRpcRemote.js.map +1 -1
  60. package/dist/src/dht/routing/RoutingSession.js +2 -2
  61. package/dist/src/dht/routing/RoutingSession.js.map +1 -1
  62. package/dist/src/dht/store/LocalDataStore.js +2 -2
  63. package/dist/src/dht/store/LocalDataStore.js.map +1 -1
  64. package/dist/src/dht/store/StoreManager.js +1 -1
  65. package/dist/src/dht/store/StoreManager.js.map +1 -1
  66. package/dist/src/exports.d.ts +2 -2
  67. package/dist/src/exports.js +3 -3
  68. package/dist/src/exports.js.map +1 -1
  69. package/karma.config.js +4 -1
  70. package/package.json +6 -6
  71. package/src/connection/ConnectionLockRpcLocal.ts +1 -1
  72. package/src/connection/ConnectionLockRpcRemote.ts +2 -2
  73. package/src/connection/{ConnectionLockHandler.ts → ConnectionLockStates.ts} +1 -1
  74. package/src/connection/ConnectionManager.ts +11 -12
  75. package/src/connection/ConnectorFacade.ts +1 -1
  76. package/src/connection/ManagedConnection.ts +8 -8
  77. package/src/connection/connectivityChecker.ts +3 -3
  78. package/src/connection/connectivityRequestHandler.ts +4 -4
  79. package/src/connection/webrtc/BrowserWebrtcConnection.ts +18 -0
  80. package/src/connection/websocket/{ClientWebsocket.ts → AbstractWebsocketClientConnection.ts} +57 -70
  81. package/src/connection/websocket/BrowserWebsocketClientConnection.ts +44 -0
  82. package/src/connection/websocket/NodeWebsocketClientConnection.ts +39 -0
  83. package/src/connection/websocket/WebsocketConnector.ts +3 -3
  84. package/src/connection/websocket/WebsocketServerConnection.ts +1 -1
  85. package/src/dht/DhtNode.ts +13 -16
  86. package/src/dht/DhtNodeRpcRemote.ts +1 -1
  87. package/src/dht/PeerManager.ts +36 -46
  88. package/src/dht/contact/SortedContactList.ts +22 -18
  89. package/src/dht/discovery/DiscoverySession.ts +3 -1
  90. package/src/dht/discovery/PeerDiscovery.ts +8 -6
  91. package/src/dht/discovery/RingDiscoverySession.ts +3 -1
  92. package/src/dht/recursive-operation/RecursiveOperationManager.ts +1 -1
  93. package/src/dht/recursive-operation/RecursiveOperationRpcRemote.ts +1 -1
  94. package/src/dht/routing/Router.ts +0 -2
  95. package/src/dht/routing/RouterRpcLocal.ts +0 -1
  96. package/src/dht/routing/RouterRpcRemote.ts +2 -2
  97. package/src/dht/routing/RoutingSession.ts +2 -2
  98. package/src/dht/store/LocalDataStore.ts +1 -1
  99. package/src/dht/store/StoreManager.ts +1 -1
  100. package/src/exports.ts +2 -2
  101. package/test/benchmark/WebsocketServerMemoryLeak.test.ts +2 -2
  102. package/test/integration/Find.test.ts +2 -2
  103. package/test/integration/ReplicateData.test.ts +3 -3
  104. package/test/integration/Store.test.ts +2 -2
  105. package/test/integration/StoreAndDelete.test.ts +2 -2
  106. package/test/integration/Websocket.test.ts +2 -2
  107. package/test/unit/PeerManager.test.ts +42 -11
  108. package/test/unit/Router.test.ts +0 -1
  109. package/test/utils/utils.ts +17 -37
  110. package/tsconfig.browser.json +2 -1
  111. package/tsconfig.jest.json +2 -1
  112. package/tsconfig.node.json +2 -1
  113. package/dist/src/connection/ConnectionLockHandler.js.map +0 -1
  114. package/dist/src/connection/websocket/ClientWebsocket.d.ts +0 -17
  115. package/dist/src/connection/websocket/ClientWebsocket.js.map +0 -1
  116. package/dist/src/helpers/MapWithTtl.d.ts +0 -14
  117. package/dist/src/helpers/MapWithTtl.js +0 -60
  118. package/dist/src/helpers/MapWithTtl.js.map +0 -1
  119. package/src/helpers/MapWithTtl.ts +0 -71
@@ -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
- const logger = new Logger(module)
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 BINARY_TYPE = 'arraybuffer'
22
+ const logger = new Logger(module)
17
23
 
18
- export class ClientWebsocket extends EventEmitter<ConnectionEvents> implements IConnection {
24
+ export abstract class AbstractWebsocketClientConnection extends EventEmitter<ConnectionEvents> implements IConnection {
19
25
 
20
26
  public readonly connectionId: ConnectionID
21
- private socket?: Websocket
27
+ protected abstract socket?: Socket
22
28
  public connectionType = ConnectionType.WEBSOCKET_CLIENT
23
-
24
- private destroyed = false
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
- if (!this.destroyed) {
34
- this.socket = new Websocket(address, undefined, undefined, undefined, { rejectUnauthorized: !selfSigned })
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 === this.socket.OPEN) {
43
+ if (this.socket && this.socket.readyState === OPEN) {
85
44
  logger.trace(`Sending data with size ${data.byteLength}`)
86
- this.socket?.send(data.buffer)
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 { ClientWebsocket } from './ClientWebsocket'
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, { error: err })
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 ClientWebsocket()
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 './ClientWebsocket'
6
+ import { CUSTOM_GOING_AWAY, GOING_AWAY } from './AbstractWebsocketClientConnection'
7
7
  import { createRandomConnectionId } from '../Connection'
8
8
 
9
9
  const logger = new Logger(module)
@@ -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 connectionManager?: ConnectionManager
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.connectionManager = this.config.transport
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.connectionManager = connectionManager
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
- connectionManager: this.connectionManager,
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([contact]),
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
- connectionManager: this.connectionManager!,
313
+ connectionLocker: this.connectionLocker!,
315
314
  peerDiscoveryQueryBatchSize: this.config.peerDiscoveryQueryBatchSize,
316
- isLayer0: (this.connectionManager !== undefined),
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([contact]),
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.connectionManager!.getLocalLockedConnectionCount()
560
+ return this.connectionLocker!.getLocalLockedConnectionCount()
564
561
  }
565
562
 
566
563
  public getRemoteLockedConnectionCount(): number {
567
- return this.connectionManager!.getRemoteLockedConnectionCount()
564
+ return this.connectionLocker!.getRemoteLockedConnectionCount()
568
565
  }
569
566
 
570
567
  public getWeakLockedConnectionCount(): number {
571
- return this.connectionManager!.getWeakLockedConnectionCount()
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.connectionManager = undefined
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()}: ${err}`)
88
+ logger.trace(`ping failed on ${this.serviceId} to ${this.getNodeId()}`, { err })
89
89
  }
90
90
  return false
91
91
  }
@@ -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 { ConnectionManager } from '../connection/ConnectionManager'
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/ConnectionLockHandler'
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
- connectionManager: ConnectionManager
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.connectionManager?.weakUnlockConnection(removableNodeId, this.config.lockId)
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.connectionManager?.weakUnlockConnection(nodeId, this.config.lockId)
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.connectionManager?.weakLockConnection(nodeId, this.config.lockId)
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.connectionManager?.weakUnlockConnection(nodeId, this.config.lockId)
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.connectionManager?.weakUnlockConnection(nodeId, this.config.lockId)
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([closest.getPeerDescriptor()])
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.getClosestContacts(limit)
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
- // TODO should set the excludeSet and limit to SortedContactList constructor and remove these line
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.getAllContacts().filter((contact) => {
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(peerDescriptors: PeerDescriptor[], setActive?: boolean): void {
303
+ addContact(peerDescriptor: PeerDescriptor): void {
309
304
  if (this.stopped) {
310
305
  return
311
306
  }
312
- peerDescriptors.forEach((contact) => {
313
- const nodeId = getNodeIdFromPeerDescriptor(contact)
314
- if (nodeId !== this.config.localNodeId) {
315
- logger.trace(`Adding new contact ${nodeId}`)
316
- const remote = this.config.createDhtNodeRpcRemote(contact)
317
- const isInBucket = (this.bucket.get(contact.nodeId) !== null)
318
- const isInContacts = (this.contacts.getContact(nodeId) !== undefined)
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
- if (isInBucket || isInContacts) {
322
- this.randomPeers.addContact(remote)
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: C[] = []
109
- this.contactIds.forEach((contactId) => {
110
- const contact = this.contactsById.get(contactId)
111
- if (contact) {
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 (contact && !contact.contacted) {
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 && contact.active) {
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
- return this.contactIds.length
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 {