@streamr/dht 100.2.5-beta.1 → 101.0.0-beta.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 (231) hide show
  1. package/dist/package.json +7 -7
  2. package/dist/src/connection/ConnectionLockRpcLocal.d.ts +3 -3
  3. package/dist/src/connection/ConnectionLockRpcLocal.js +8 -8
  4. package/dist/src/connection/ConnectionLockRpcLocal.js.map +1 -1
  5. package/dist/src/connection/ConnectionLockRpcRemote.js +1 -1
  6. package/dist/src/connection/ConnectionLockRpcRemote.js.map +1 -1
  7. package/dist/src/connection/ConnectionManager.d.ts +4 -6
  8. package/dist/src/connection/ConnectionManager.js +128 -103
  9. package/dist/src/connection/ConnectionManager.js.map +1 -1
  10. package/dist/src/connection/ConnectorFacade.d.ts +15 -14
  11. package/dist/src/connection/ConnectorFacade.js +70 -52
  12. package/dist/src/connection/ConnectorFacade.js.map +1 -1
  13. package/dist/src/connection/Handshaker.d.ts +9 -2
  14. package/dist/src/connection/Handshaker.js +117 -27
  15. package/dist/src/connection/Handshaker.js.map +1 -1
  16. package/dist/src/connection/ManagedConnection.d.ts +13 -38
  17. package/dist/src/connection/ManagedConnection.js +31 -252
  18. package/dist/src/connection/ManagedConnection.js.map +1 -1
  19. package/dist/src/connection/OutputBuffer.d.ts +9 -0
  20. package/dist/src/connection/OutputBuffer.js +26 -0
  21. package/dist/src/connection/OutputBuffer.js.map +1 -0
  22. package/dist/src/connection/PendingConnection.d.ts +19 -0
  23. package/dist/src/connection/PendingConnection.js +59 -0
  24. package/dist/src/connection/PendingConnection.js.map +1 -0
  25. package/dist/src/connection/connectivityChecker.js +3 -3
  26. package/dist/src/connection/connectivityChecker.js.map +1 -1
  27. package/dist/src/connection/connectivityRequestHandler.js +2 -2
  28. package/dist/src/connection/connectivityRequestHandler.js.map +1 -1
  29. package/dist/src/connection/simulator/Simulator.d.ts +1 -3
  30. package/dist/src/connection/simulator/Simulator.js +1 -4
  31. package/dist/src/connection/simulator/Simulator.js.map +1 -1
  32. package/dist/src/connection/simulator/SimulatorConnection.js +1 -2
  33. package/dist/src/connection/simulator/SimulatorConnection.js.map +1 -1
  34. package/dist/src/connection/simulator/SimulatorConnector.d.ts +3 -3
  35. package/dist/src/connection/simulator/SimulatorConnector.js +28 -21
  36. package/dist/src/connection/simulator/SimulatorConnector.js.map +1 -1
  37. package/dist/src/connection/webrtc/NodeWebrtcConnection.d.ts +1 -6
  38. package/dist/src/connection/webrtc/NodeWebrtcConnection.js +3 -20
  39. package/dist/src/connection/webrtc/NodeWebrtcConnection.js.map +1 -1
  40. package/dist/src/connection/webrtc/WebrtcConnector.d.ts +11 -6
  41. package/dist/src/connection/webrtc/WebrtcConnector.js +57 -42
  42. package/dist/src/connection/webrtc/WebrtcConnector.js.map +1 -1
  43. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.d.ts +8 -10
  44. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js +21 -44
  45. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js.map +1 -1
  46. package/dist/src/connection/websocket/AbstractWebsocketClientConnection.js +8 -2
  47. package/dist/src/connection/websocket/AbstractWebsocketClientConnection.js.map +1 -1
  48. package/dist/src/connection/websocket/AutoCertifierClientFacade.d.ts +3 -3
  49. package/dist/src/connection/websocket/AutoCertifierClientFacade.js +8 -8
  50. package/dist/src/connection/websocket/AutoCertifierClientFacade.js.map +1 -1
  51. package/dist/src/connection/websocket/NodeWebsocketClientConnection.js +1 -1
  52. package/dist/src/connection/websocket/NodeWebsocketClientConnection.js.map +1 -1
  53. package/dist/src/connection/websocket/WebsocketClientConnector.d.ts +26 -0
  54. package/dist/src/connection/websocket/WebsocketClientConnector.js +86 -0
  55. package/dist/src/connection/websocket/WebsocketClientConnector.js.map +1 -0
  56. package/dist/src/connection/websocket/WebsocketClientConnectorRpcLocal.d.ts +19 -0
  57. package/dist/src/connection/websocket/WebsocketClientConnectorRpcLocal.js +23 -0
  58. package/dist/src/connection/websocket/WebsocketClientConnectorRpcLocal.js.map +1 -0
  59. package/dist/src/connection/websocket/WebsocketClientConnectorRpcRemote.d.ts +5 -0
  60. package/dist/src/connection/websocket/{WebsocketConnectorRpcRemote.js → WebsocketClientConnectorRpcRemote.js} +4 -4
  61. package/dist/src/connection/websocket/WebsocketClientConnectorRpcRemote.js.map +1 -0
  62. package/dist/src/connection/websocket/WebsocketServer.d.ts +8 -5
  63. package/dist/src/connection/websocket/WebsocketServer.js +11 -11
  64. package/dist/src/connection/websocket/WebsocketServer.js.map +1 -1
  65. package/dist/src/connection/websocket/{WebsocketConnector.d.ts → WebsocketServerConnector.d.ts} +16 -21
  66. package/dist/src/connection/websocket/{WebsocketConnector.js → WebsocketServerConnector.js} +112 -160
  67. package/dist/src/connection/websocket/WebsocketServerConnector.js.map +1 -0
  68. package/dist/src/dht/DhtNode.d.ts +4 -4
  69. package/dist/src/dht/DhtNode.js +85 -84
  70. package/dist/src/dht/DhtNode.js.map +1 -1
  71. package/dist/src/dht/DhtNodeRpcLocal.d.ts +3 -3
  72. package/dist/src/dht/DhtNodeRpcLocal.js +9 -9
  73. package/dist/src/dht/DhtNodeRpcLocal.js.map +1 -1
  74. package/dist/src/dht/ExternalApiRpcLocal.d.ts +3 -3
  75. package/dist/src/dht/ExternalApiRpcLocal.js +5 -5
  76. package/dist/src/dht/ExternalApiRpcLocal.js.map +1 -1
  77. package/dist/src/dht/ExternalApiRpcRemote.js +2 -2
  78. package/dist/src/dht/ExternalApiRpcRemote.js.map +1 -1
  79. package/dist/src/dht/PeerManager.d.ts +4 -4
  80. package/dist/src/dht/PeerManager.js +22 -22
  81. package/dist/src/dht/PeerManager.js.map +1 -1
  82. package/dist/src/dht/contact/SortedContactList.d.ts +3 -3
  83. package/dist/src/dht/contact/SortedContactList.js +9 -9
  84. package/dist/src/dht/contact/SortedContactList.js.map +1 -1
  85. package/dist/src/dht/discovery/DiscoverySession.d.ts +3 -3
  86. package/dist/src/dht/discovery/DiscoverySession.js +21 -21
  87. package/dist/src/dht/discovery/DiscoverySession.js.map +1 -1
  88. package/dist/src/dht/discovery/PeerDiscovery.d.ts +3 -3
  89. package/dist/src/dht/discovery/PeerDiscovery.js +46 -44
  90. package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
  91. package/dist/src/dht/discovery/RingDiscoverySession.d.ts +3 -3
  92. package/dist/src/dht/discovery/RingDiscoverySession.js +19 -19
  93. package/dist/src/dht/discovery/RingDiscoverySession.js.map +1 -1
  94. package/dist/src/dht/recursive-operation/RecursiveOperationManager.d.ts +3 -3
  95. package/dist/src/dht/recursive-operation/RecursiveOperationManager.js +33 -33
  96. package/dist/src/dht/recursive-operation/RecursiveOperationManager.js.map +1 -1
  97. package/dist/src/dht/recursive-operation/RecursiveOperationRpcLocal.d.ts +3 -3
  98. package/dist/src/dht/recursive-operation/RecursiveOperationRpcLocal.js +8 -8
  99. package/dist/src/dht/recursive-operation/RecursiveOperationRpcLocal.js.map +1 -1
  100. package/dist/src/dht/recursive-operation/RecursiveOperationSession.d.ts +4 -4
  101. package/dist/src/dht/recursive-operation/RecursiveOperationSession.js +24 -24
  102. package/dist/src/dht/recursive-operation/RecursiveOperationSession.js.map +1 -1
  103. package/dist/src/dht/recursive-operation/RecursiveOperationSessionRpcLocal.d.ts +4 -4
  104. package/dist/src/dht/recursive-operation/RecursiveOperationSessionRpcLocal.js +5 -5
  105. package/dist/src/dht/recursive-operation/RecursiveOperationSessionRpcLocal.js.map +1 -1
  106. package/dist/src/dht/routing/Router.d.ts +3 -3
  107. package/dist/src/dht/routing/Router.js +20 -20
  108. package/dist/src/dht/routing/Router.js.map +1 -1
  109. package/dist/src/dht/routing/RouterRpcLocal.d.ts +3 -3
  110. package/dist/src/dht/routing/RouterRpcLocal.js +16 -16
  111. package/dist/src/dht/routing/RouterRpcLocal.js.map +1 -1
  112. package/dist/src/dht/routing/RoutingSession.d.ts +3 -3
  113. package/dist/src/dht/routing/RoutingSession.js +24 -24
  114. package/dist/src/dht/routing/RoutingSession.js.map +1 -1
  115. package/dist/src/dht/store/StoreManager.d.ts +3 -3
  116. package/dist/src/dht/store/StoreManager.js +25 -25
  117. package/dist/src/dht/store/StoreManager.js.map +1 -1
  118. package/dist/src/dht/store/StoreRpcLocal.d.ts +3 -3
  119. package/dist/src/dht/store/StoreRpcLocal.js +12 -12
  120. package/dist/src/dht/store/StoreRpcLocal.js.map +1 -1
  121. package/dist/src/exports.d.ts +3 -0
  122. package/dist/src/exports.js +5 -1
  123. package/dist/src/exports.js.map +1 -1
  124. package/dist/src/proto/google/protobuf/any.d.ts +5 -8
  125. package/dist/src/proto/google/protobuf/any.js.map +1 -1
  126. package/dist/src/proto/google/protobuf/empty.d.ts +1 -0
  127. package/dist/src/proto/google/protobuf/empty.js.map +1 -1
  128. package/dist/src/proto/google/protobuf/timestamp.d.ts +1 -10
  129. package/dist/src/proto/google/protobuf/timestamp.js.map +1 -1
  130. package/dist/src/proto/packages/dht/protos/DhtRpc.client.d.ts +4 -4
  131. package/dist/src/proto/packages/dht/protos/DhtRpc.client.js +8 -8
  132. package/dist/src/proto/packages/dht/protos/DhtRpc.client.js.map +1 -1
  133. package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +3 -3
  134. package/dist/src/proto/packages/dht/protos/DhtRpc.js +4 -4
  135. package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -1
  136. package/dist/src/proto/packages/dht/protos/DhtRpc.server.d.ts +2 -2
  137. package/dist/src/proto/packages/proto-rpc/protos/ProtoRpc.js +1 -1
  138. package/dist/src/transport/ListeningRpcCommunicator.d.ts +2 -2
  139. package/dist/src/transport/ListeningRpcCommunicator.js +2 -2
  140. package/dist/src/transport/ListeningRpcCommunicator.js.map +1 -1
  141. package/dist/src/transport/RoutingRpcCommunicator.d.ts +2 -2
  142. package/dist/src/transport/RoutingRpcCommunicator.js +2 -2
  143. package/dist/src/transport/RoutingRpcCommunicator.js.map +1 -1
  144. package/package.json +7 -7
  145. package/protos/DhtRpc.proto +1 -1
  146. package/src/connection/ConnectionLockRpcLocal.ts +9 -9
  147. package/src/connection/ConnectionLockRpcRemote.ts +1 -1
  148. package/src/connection/ConnectionManager.ts +153 -111
  149. package/src/connection/ConnectorFacade.ts +84 -61
  150. package/src/connection/Handshaker.ts +131 -27
  151. package/src/connection/ManagedConnection.ts +41 -304
  152. package/src/connection/OutputBuffer.ts +28 -0
  153. package/src/connection/PendingConnection.ts +68 -0
  154. package/src/connection/connectivityChecker.ts +2 -2
  155. package/src/connection/connectivityRequestHandler.ts +1 -1
  156. package/src/connection/simulator/Simulator.ts +1 -5
  157. package/src/connection/simulator/SimulatorConnection.ts +1 -2
  158. package/src/connection/simulator/SimulatorConnector.ts +34 -33
  159. package/src/connection/webrtc/BrowserWebrtcConnection.ts +0 -6
  160. package/src/connection/webrtc/NodeWebrtcConnection.ts +3 -24
  161. package/src/connection/webrtc/WebrtcConnector.ts +73 -62
  162. package/src/connection/webrtc/WebrtcConnectorRpcLocal.ts +26 -56
  163. package/src/connection/websocket/AbstractWebsocketClientConnection.ts +8 -2
  164. package/src/connection/websocket/AutoCertifierClientFacade.ts +11 -11
  165. package/src/connection/websocket/NodeWebsocketClientConnection.ts +1 -1
  166. package/src/connection/websocket/WebsocketClientConnector.ts +119 -0
  167. package/src/connection/websocket/WebsocketClientConnectorRpcLocal.ts +39 -0
  168. package/src/connection/websocket/{WebsocketConnectorRpcRemote.ts → WebsocketClientConnectorRpcRemote.ts} +2 -2
  169. package/src/connection/websocket/WebsocketServer.ts +18 -14
  170. package/src/connection/websocket/{WebsocketConnector.ts → WebsocketServerConnector.ts} +128 -205
  171. package/src/dht/DhtNode.ts +90 -89
  172. package/src/dht/DhtNodeRpcLocal.ts +11 -11
  173. package/src/dht/ExternalApiRpcLocal.ts +6 -6
  174. package/src/dht/ExternalApiRpcRemote.ts +2 -2
  175. package/src/dht/PeerManager.ts +24 -24
  176. package/src/dht/contact/SortedContactList.ts +10 -10
  177. package/src/dht/discovery/DiscoverySession.ts +24 -24
  178. package/src/dht/discovery/PeerDiscovery.ts +47 -45
  179. package/src/dht/discovery/RingDiscoverySession.ts +23 -23
  180. package/src/dht/recursive-operation/RecursiveOperationManager.ts +36 -36
  181. package/src/dht/recursive-operation/RecursiveOperationRpcLocal.ts +9 -9
  182. package/src/dht/recursive-operation/RecursiveOperationSession.ts +25 -25
  183. package/src/dht/recursive-operation/RecursiveOperationSessionRpcLocal.ts +7 -7
  184. package/src/dht/routing/Router.ts +21 -21
  185. package/src/dht/routing/RouterRpcLocal.ts +17 -17
  186. package/src/dht/routing/RoutingSession.ts +26 -26
  187. package/src/dht/store/StoreManager.ts +27 -27
  188. package/src/dht/store/StoreRpcLocal.ts +13 -13
  189. package/src/exports.ts +3 -0
  190. package/src/proto/google/protobuf/any.ts +6 -9
  191. package/src/proto/google/protobuf/empty.ts +2 -1
  192. package/src/proto/google/protobuf/timestamp.ts +2 -11
  193. package/src/proto/packages/dht/protos/DhtRpc.client.ts +9 -9
  194. package/src/proto/packages/dht/protos/DhtRpc.server.ts +3 -3
  195. package/src/proto/packages/dht/protos/DhtRpc.ts +4 -4
  196. package/src/proto/packages/proto-rpc/protos/ProtoRpc.ts +1 -1
  197. package/src/transport/ListeningRpcCommunicator.ts +3 -3
  198. package/src/transport/RoutingRpcCommunicator.ts +3 -3
  199. package/test/end-to-end/Layer0Webrtc.test.ts +0 -10
  200. package/test/integration/ConnectionManager.test.ts +3 -2
  201. package/test/integration/GeoIpConnectivityChecking.test.ts +1 -1
  202. package/test/integration/SimultaneousConnections.test.ts +2 -2
  203. package/test/integration/WebrtcConnectionManagement.test.ts +2 -10
  204. package/test/integration/{WebsocketConnectorRpc.test.ts → WebsocketClientConnectorRpc.test.ts} +9 -9
  205. package/test/integration/WebsocketConnectionManagement.test.ts +11 -29
  206. package/test/unit/ConnectionManager.test.ts +64 -0
  207. package/test/unit/DiscoverySession.test.ts +1 -1
  208. package/test/unit/Handshaker.test.ts +169 -0
  209. package/test/unit/ManagedConnection.test.ts +58 -0
  210. package/test/unit/PendingConnection.test.ts +57 -0
  211. package/test/unit/WebrtcConnector.test.ts +56 -0
  212. package/test/unit/{WebsocketConnector.test.ts → WebsocketClientConnector.test.ts} +56 -11
  213. package/test/unit/WebsocketServerConnector.test.ts +102 -0
  214. package/test/utils/FakeConnectorFacade.ts +41 -0
  215. package/test/utils/mock/MockConnection.ts +26 -0
  216. package/test/utils/utils.ts +2 -2
  217. package/dist/src/connection/IConnectionSource.d.ts +0 -4
  218. package/dist/src/connection/IConnectionSource.js +0 -3
  219. package/dist/src/connection/IConnectionSource.js.map +0 -1
  220. package/dist/src/connection/webrtc/ManagedWebrtcConnection.d.ts +0 -7
  221. package/dist/src/connection/webrtc/ManagedWebrtcConnection.js +0 -20
  222. package/dist/src/connection/webrtc/ManagedWebrtcConnection.js.map +0 -1
  223. package/dist/src/connection/websocket/WebsocketConnector.js.map +0 -1
  224. package/dist/src/connection/websocket/WebsocketConnectorRpcLocal.d.ts +0 -19
  225. package/dist/src/connection/websocket/WebsocketConnectorRpcLocal.js +0 -23
  226. package/dist/src/connection/websocket/WebsocketConnectorRpcLocal.js.map +0 -1
  227. package/dist/src/connection/websocket/WebsocketConnectorRpcRemote.d.ts +0 -5
  228. package/dist/src/connection/websocket/WebsocketConnectorRpcRemote.js.map +0 -1
  229. package/src/connection/IConnectionSource.ts +0 -6
  230. package/src/connection/webrtc/ManagedWebrtcConnection.ts +0 -27
  231. package/src/connection/websocket/WebsocketConnectorRpcLocal.ts +0 -39
@@ -19,14 +19,16 @@ import { ConnectionLockStates, LockID } from './ConnectionLockStates'
19
19
  import { ConnectorFacade } from './ConnectorFacade'
20
20
  import { ManagedConnection, Events as ManagedConnectionEvents } from './ManagedConnection'
21
21
  import { ConnectionLockRpcRemote } from './ConnectionLockRpcRemote'
22
- import { WEBRTC_CLEANUP } from './webrtc/NodeWebrtcConnection'
23
22
  import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
24
23
  import { ConnectionLockRpcLocal } from './ConnectionLockRpcLocal'
25
24
  import { DhtAddress, areEqualPeerDescriptors, getNodeIdFromPeerDescriptor } from '../identifiers'
26
25
  import { getOfferer } from '../helpers/offering'
27
26
  import { ConnectionsView } from './ConnectionsView'
27
+ import { OutputBuffer } from './OutputBuffer'
28
+ import { IConnection } from './IConnection'
29
+ import { PendingConnection } from './PendingConnection'
28
30
 
29
- export interface ConnectionManagerConfig {
31
+ export interface ConnectionManagerOptions {
30
32
  maxConnections?: number
31
33
  metricsContext: MetricsContext
32
34
  createConnectorFacade: () => ConnectorFacade
@@ -75,6 +77,24 @@ export interface TlsCertificate {
75
77
  certFileName: string
76
78
  }
77
79
 
80
+ interface ConnectingEndpoint {
81
+ connected: false
82
+ // TODO: Handle PendingConnections in ConnectorFacade only? ConnectionManager knows buffer and reacts to events from below.
83
+ // Difficulties arise from duplicate connection handling. Sometimes a connected connection is replaced as duplicate in which case
84
+ // a managed connection has to be replaced in the ConnectionManager.
85
+ connection: PendingConnection
86
+ // Could the buffer be in the PendingConnection or encapsulated endpoint?
87
+ buffer: OutputBuffer
88
+ }
89
+
90
+ interface ConnectedEndpoint {
91
+ connected: true
92
+ connection: ManagedConnection
93
+ }
94
+
95
+ // TODO: Could encapsulate all endpoint logic to its own module
96
+ type Endpoint = ConnectedEndpoint | ConnectingEndpoint
97
+
78
98
  const INTERNAL_SERVICE_ID = 'system/connection-manager'
79
99
 
80
100
  // Form an string representation from a peer description which can be undefined. This output
@@ -96,25 +116,25 @@ export const getNodeIdOrUnknownFromPeerDescriptor = (peerDescriptor: PeerDescrip
96
116
 
97
117
  export class ConnectionManager extends EventEmitter<TransportEvents> implements ITransport, ConnectionsView, ConnectionLocker {
98
118
 
99
- private config: ConnectionManagerConfig
119
+ private options: ConnectionManagerOptions
100
120
  private readonly metricsContext: MetricsContext
101
- // TODO use config option or named constant?
121
+ // TODO use options option or named constant?
102
122
  private readonly duplicateMessageDetector: DuplicateDetector = new DuplicateDetector(10000)
103
123
  private readonly metrics: ConnectionManagerMetrics
104
124
  private locks = new ConnectionLockStates()
105
- private connections: Map<DhtAddress, ManagedConnection> = new Map()
125
+ private endpoints: Map<DhtAddress, Endpoint> = new Map()
106
126
  private readonly connectorFacade: ConnectorFacade
107
127
  private rpcCommunicator?: RoutingRpcCommunicator
108
128
  private disconnectorIntervalRef?: NodeJS.Timeout
109
129
  private state = ConnectionManagerState.IDLE
110
130
 
111
- constructor(config: ConnectionManagerConfig) {
131
+ constructor(options: ConnectionManagerOptions) {
112
132
  super()
113
- this.config = config
133
+ this.options = options
114
134
  this.onData = this.onData.bind(this)
115
135
  this.send = this.send.bind(this)
116
136
  this.onNewConnection = this.onNewConnection.bind(this)
117
- this.metricsContext = this.config.metricsContext ?? new MetricsContext()
137
+ this.metricsContext = this.options.metricsContext ?? new MetricsContext()
118
138
  this.metrics = {
119
139
  sendMessagesPerSecond: new RateMetric(),
120
140
  sendBytesPerSecond: new RateMetric(),
@@ -124,10 +144,10 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
124
144
  connectionTotalFailureCount: new CountMetric()
125
145
  }
126
146
  this.metricsContext.addMetrics('node', this.metrics)
127
- this.connectorFacade = this.config.createConnectorFacade()
147
+ this.connectorFacade = this.options.createConnectorFacade()
128
148
  this.send = this.send.bind(this)
129
149
  this.rpcCommunicator = new RoutingRpcCommunicator(INTERNAL_SERVICE_ID, this.send, {
130
- rpcRequestTimeout: 10000 // TODO use config option or named constant?
150
+ rpcRequestTimeout: 10000 // TODO use options option or named constant?
131
151
  })
132
152
  const lockRpcLocal = new ConnectionLockRpcLocal({
133
153
  addRemoteLocked: (id: DhtAddress, lockId: LockID) => this.locks.addRemoteLocked(id, lockId),
@@ -151,21 +171,24 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
151
171
  * which hasn't been used within maxIdleTime.
152
172
  */
153
173
  public garbageCollectConnections(maxConnections: number, maxIdleTime: number): void {
154
- if (this.connections.size <= maxConnections) {
174
+ if (this.endpoints.size <= maxConnections) {
155
175
  return
156
176
  }
157
177
  const disconnectionCandidates = new SortedContactList<ManagedConnection>({
158
178
  referenceId: getNodeIdFromPeerDescriptor(this.getLocalPeerDescriptor()),
159
- maxSize: 100000, // TODO use config option or named constant?
179
+ maxSize: 100000, // TODO use options option or named constant?
160
180
  allowToContainReferenceId: false
161
181
  })
162
- this.connections.forEach((connection) => {
163
- if (!this.locks.isLocked(connection.getNodeId()) && Date.now() - connection.getLastUsedTimestamp() > maxIdleTime) {
164
- logger.trace('disconnecting in timeout interval: ' + getNodeIdOrUnknownFromPeerDescriptor(connection.getPeerDescriptor()))
165
- disconnectionCandidates.addContact(connection)
182
+ this.endpoints.forEach((endpoint) => {
183
+ if (endpoint.connected) {
184
+ const connection = endpoint.connection
185
+ if (!this.locks.isLocked(connection.getNodeId()) && Date.now() - connection.getLastUsedTimestamp() > maxIdleTime) {
186
+ logger.trace('disconnecting in timeout interval: ' + getNodeIdOrUnknownFromPeerDescriptor(connection.getPeerDescriptor()))
187
+ disconnectionCandidates.addContact(connection)
188
+ }
166
189
  }
167
190
  })
168
- const disconnectables = disconnectionCandidates.getFurthestContacts(this.connections.size - maxConnections)
191
+ const disconnectables = disconnectionCandidates.getFurthestContacts(this.endpoints.size - maxConnections)
169
192
  for (const disconnectable of disconnectables) {
170
193
  const peerDescriptor = disconnectable.getPeerDescriptor()!
171
194
  logger.trace('garbageCollecting ' + getNodeIdFromPeerDescriptor(peerDescriptor))
@@ -180,7 +203,7 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
180
203
  this.state = ConnectionManagerState.RUNNING
181
204
  logger.trace(`Starting ConnectionManager...`)
182
205
  await this.connectorFacade.start(
183
- (connection: ManagedConnection) => this.onNewConnection(connection),
206
+ (connection: PendingConnection) => this.onNewConnection(connection),
184
207
  (nodeId: DhtAddress) => this.hasConnection(nodeId),
185
208
  this
186
209
  )
@@ -188,8 +211,8 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
188
211
  this.disconnectorIntervalRef = setInterval(() => {
189
212
  logger.trace('disconnectorInterval')
190
213
  const LAST_USED_LIMIT = 20000
191
- this.garbageCollectConnections(this.config.maxConnections ?? 80, LAST_USED_LIMIT)
192
- }, 5000) // TODO use config option or named constant?
214
+ this.garbageCollectConnections(this.options.maxConnections ?? 80, LAST_USED_LIMIT)
215
+ }, 5000) // TODO use options option or named constant?
193
216
  }
194
217
 
195
218
  public async stop(): Promise<void> {
@@ -203,23 +226,25 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
203
226
  }
204
227
  await this.connectorFacade.stop()
205
228
 
206
- await Promise.all(Array.from(this.connections.values()).map(async (peer) => {
207
- if (peer.isHandshakeCompleted()) {
229
+ await Promise.all(Array.from(this.endpoints.values()).map(async (endpoint) => {
230
+ if (endpoint.connected) {
208
231
  try {
209
- await this.gracefullyDisconnectAsync(peer.getPeerDescriptor()!, DisconnectMode.LEAVING)
232
+ await this.gracefullyDisconnectAsync(endpoint.connection.getPeerDescriptor()!, DisconnectMode.LEAVING)
210
233
  } catch (e) {
211
234
  logger.error(e)
212
235
  }
213
236
  } else {
237
+ const connection = endpoint.connection
214
238
  logger.trace('handshake of connection not completed, force-closing')
215
- // TODO use config option or named constant?
216
- const eventReceived = waitForEvent3<ManagedConnectionEvents>(peer, 'disconnected', 2000)
239
+ // TODO use options option or named constant?
240
+ const eventReceived = waitForEvent3(connection as any, 'disconnected', 2000)
217
241
  // TODO should we have some handling for this floating promise?
218
- peer.close(true)
242
+ connection.close(true)
219
243
  try {
220
244
  await eventReceived
221
245
  logger.trace('resolving after receiving disconnected event from non-handshaked connection')
222
246
  } catch (e) {
247
+ endpoint.buffer.reject()
223
248
  logger.trace('force-closing non-handshaked connection timed out ' + e)
224
249
  }
225
250
  }
@@ -230,10 +255,6 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
230
255
  this.duplicateMessageDetector.clear()
231
256
  this.locks.clear()
232
257
  this.removeAllListeners()
233
- // TODO would it make sense to move this call to WebrtcConnector#stop()?
234
- // - but note that we should call this only after connections have been closed
235
- // (i.e the this.gracefullyDisconnectAsync() calls above)
236
- WEBRTC_CLEANUP.cleanUp()
237
258
  }
238
259
 
239
260
  public getLocalLockedConnectionCount(): number {
@@ -262,7 +283,7 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
262
283
  ...message,
263
284
  sourceDescriptor: this.getLocalPeerDescriptor()
264
285
  }
265
- let connection = this.connections.get(nodeId)
286
+ let connection = this.endpoints.get(nodeId)?.connection
266
287
  if (!connection && opts.connect) {
267
288
  connection = this.connectorFacade.createConnection(peerDescriptor)
268
289
  this.onNewConnection(connection)
@@ -272,7 +293,12 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
272
293
  const binary = Message.toBinary(message)
273
294
  this.metrics.sendBytesPerSecond.record(binary.byteLength)
274
295
  this.metrics.sendMessagesPerSecond.record(1)
275
- return connection.send(binary, opts.connect)
296
+
297
+ if (this.endpoints.get(nodeId)!.connected) {
298
+ return (connection as ManagedConnection).send(binary)
299
+ } else {
300
+ return (this.endpoints.get(nodeId)! as ConnectingEndpoint).buffer.push(binary)
301
+ }
276
302
  }
277
303
 
278
304
  private isConnectionToSelf(peerDescriptor: PeerDescriptor): boolean {
@@ -289,10 +315,6 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
289
315
  }
290
316
  }
291
317
 
292
- public getConnection(nodeId: DhtAddress): ManagedConnection | undefined {
293
- return this.connections.get(nodeId)
294
- }
295
-
296
318
  public getLocalPeerDescriptor(): PeerDescriptor {
297
319
  return this.connectorFacade.getLocalPeerDescriptor()!
298
320
  }
@@ -358,32 +380,47 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
358
380
  }
359
381
  }
360
382
 
361
- private onConnected(connection: ManagedConnection) {
362
- const peerDescriptor = connection.getPeerDescriptor()!
383
+ private onConnected(peerDescriptor: PeerDescriptor, connection: IConnection) {
384
+ const managedConnection = new ManagedConnection(peerDescriptor, connection)
385
+ managedConnection.on('managedData', this.onData)
386
+ managedConnection.once('disconnected', (gracefulLeave: boolean) => this.onDisconnected(peerDescriptor, gracefulLeave))
387
+
388
+ const nodeId = getNodeIdFromPeerDescriptor(peerDescriptor)
389
+ const endpoint = this.endpoints.get(nodeId)! as ConnectingEndpoint
390
+ const outputBuffer = endpoint.buffer
391
+ const pendingConnection = endpoint.connection
392
+ const buffer = outputBuffer.getBuffer()
393
+ while (buffer.length > 0) {
394
+ logger.trace('emptying buffer')
395
+ managedConnection.send(buffer.shift()!)
396
+ }
397
+ outputBuffer.resolve()
398
+ pendingConnection.destroy()
399
+ this.endpoints.set(nodeId, {
400
+ connected: true,
401
+ connection: managedConnection
402
+ })
363
403
  this.emit('connected', peerDescriptor)
364
- logger.trace(getNodeIdFromPeerDescriptor(peerDescriptor) + ' onConnected() ' + connection.connectionType)
365
404
  this.onConnectionCountChange()
366
405
  }
367
406
 
368
- private onDisconnected(connection: ManagedConnection, gracefulLeave: boolean) {
369
- const nodeId = getNodeIdFromPeerDescriptor(connection.getPeerDescriptor()!)
407
+ private onDisconnected(peerDescriptor: PeerDescriptor, gracefulLeave: boolean) {
408
+ const nodeId = getNodeIdFromPeerDescriptor(peerDescriptor)
370
409
  logger.trace(nodeId + ' onDisconnected() gracefulLeave: ' + gracefulLeave)
371
- const storedConnection = this.connections.get(nodeId)
372
- if (storedConnection && (storedConnection.connectionId === connection.connectionId)) {
410
+ const endpoint = this.endpoints.get(nodeId)
411
+ if (endpoint) {
373
412
  this.locks.clearAllLocks(nodeId)
374
- this.connections.delete(nodeId)
413
+ if (endpoint.connected === false) {
414
+ endpoint.buffer.reject()
415
+ }
416
+ this.endpoints.delete(nodeId)
375
417
  logger.trace(nodeId + ' deleted connection in onDisconnected() gracefulLeave: ' + gracefulLeave)
376
- this.emit('disconnected', connection.getPeerDescriptor()!, gracefulLeave)
418
+ this.emit('disconnected', peerDescriptor, gracefulLeave)
377
419
  this.onConnectionCountChange()
378
- } else {
379
- logger.trace(nodeId + ' onDisconnected() did nothing, no such connection in connectionManager')
380
- if (storedConnection) {
381
- logger.trace(nodeId + ' connectionIds do not match ' + storedConnection.connectionId + ' ' + connection.connectionId.toString())
382
- }
383
420
  }
384
421
  }
385
422
 
386
- private onNewConnection(connection: ManagedConnection): boolean {
423
+ private onNewConnection(connection: PendingConnection): boolean {
387
424
  if (this.state === ConnectionManagerState.STOPPED) {
388
425
  return false
389
426
  }
@@ -391,44 +428,44 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
391
428
  if (!this.acceptNewConnection(connection)) {
392
429
  return false
393
430
  }
394
- connection.on('managedData', this.onData)
395
- connection.on('disconnected', (gracefulLeave: boolean) => {
396
- this.onDisconnected(connection, gracefulLeave)
397
- })
398
- if (connection.isHandshakeCompleted()) {
399
- this.onConnected(connection)
400
- } else {
401
- connection.once('handshakeCompleted', () => {
402
- this.onConnected(connection)
403
- })
404
- }
431
+ connection.once('connected', (peerDescriptor: PeerDescriptor, connection: IConnection) => this.onConnected(peerDescriptor, connection))
432
+ connection.once('disconnected', (gracefulLeave: boolean) => this.onDisconnected(connection.getPeerDescriptor(), gracefulLeave))
405
433
  return true
406
434
  }
407
435
 
408
- private acceptNewConnection(newConnection: ManagedConnection): boolean {
409
- const nodeId = getNodeIdFromPeerDescriptor(newConnection.getPeerDescriptor()!)
410
- logger.trace(nodeId + ' acceptIncomingConnection()')
411
- if (this.connections.has(nodeId)) {
436
+ private acceptNewConnection(newConnection: PendingConnection): boolean {
437
+ const nodeId = getNodeIdFromPeerDescriptor(newConnection.getPeerDescriptor())
438
+ logger.trace(nodeId + ' acceptNewConnection()')
439
+ if (this.endpoints.has(nodeId)) {
412
440
  if (getOfferer(getNodeIdFromPeerDescriptor(this.getLocalPeerDescriptor()), nodeId) === 'remote') {
413
- logger.trace(nodeId + ' acceptIncomingConnection() replace current connection')
414
- // replace the current connection
415
- const oldConnection = this.connections.get(nodeId)!
416
- logger.trace('replaced: ' + nodeId)
417
- const buffer = oldConnection.stealOutputBuffer()
418
-
419
- for (const data of buffer) {
420
- newConnection.sendNoWait(data)
441
+ let buffer: OutputBuffer | undefined
442
+ const endpoint = this.endpoints.get(nodeId)!
443
+ // This is a rare occurance but it does happen from time to time.
444
+ // Could be related to WS client connections not realizing that they have been disconnected.
445
+ // Makes refactoring duplicate connection handling to the connectors very difficult.
446
+ if (this.endpoints.get(nodeId)!.connected) {
447
+ logger.debug('replacing connected connection', { nodeId })
448
+ buffer = new OutputBuffer()
449
+ } else {
450
+ buffer = (endpoint as ConnectingEndpoint).buffer
421
451
  }
452
+ const oldConnection = endpoint.connection
453
+ logger.trace('replaced: ' + nodeId)
422
454
 
423
- oldConnection.reportBufferSentByOtherConnection()
424
- oldConnection.replacedByOtherConnection = true
455
+ oldConnection.replaceAsDuplicate()
456
+ this.endpoints.set(nodeId, { connected: false, connection: newConnection, buffer: buffer })
457
+ return true
425
458
  } else {
426
459
  return false
427
460
  }
428
461
  }
429
462
 
430
- logger.trace(nodeId + ' added to connections at acceptIncomingConnection')
431
- this.connections.set(nodeId, newConnection)
463
+ logger.trace(nodeId + ' added to connections at acceptNewConnection')
464
+ this.endpoints.set(nodeId, {
465
+ connected: false,
466
+ buffer: new OutputBuffer(),
467
+ connection: newConnection
468
+ })
432
469
 
433
470
  return true
434
471
  }
@@ -437,12 +474,11 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
437
474
  const nodeId = getNodeIdFromPeerDescriptor(peerDescriptor)
438
475
  logger.trace(nodeId + ' ' + 'closeConnection() ' + reason)
439
476
  this.locks.clearAllLocks(nodeId)
440
- if (this.connections.has(nodeId)) {
441
- const connectionToClose = this.connections.get(nodeId)!
477
+ if (this.endpoints.has(nodeId)) {
478
+ const connectionToClose = this.endpoints.get(nodeId)!.connection
442
479
  await connectionToClose.close(gracefulLeave)
443
-
444
480
  } else {
445
- logger.trace(nodeId + ' ' + 'closeConnection() this.connections did not have the id')
481
+ logger.trace(nodeId + ' ' + 'closeConnection() this.endpoints did not have the id')
446
482
  this.emit('disconnected', peerDescriptor, false)
447
483
  }
448
484
  }
@@ -476,7 +512,7 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
476
512
  this.rpcCommunicator!,
477
513
  ConnectionLockRpcClient
478
514
  )
479
- if (this.connections.has(nodeId)) {
515
+ if (this.endpoints.has(nodeId)) {
480
516
  rpcRemote.unlockRequest(lockId)
481
517
  }
482
518
  }
@@ -496,35 +532,40 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
496
532
  }
497
533
 
498
534
  private async gracefullyDisconnectAsync(targetDescriptor: PeerDescriptor, disconnectMode: DisconnectMode): Promise<void> {
535
+ const endpoint = this.endpoints.get(getNodeIdFromPeerDescriptor(targetDescriptor))
499
536
 
500
- const connection = this.connections.get(getNodeIdFromPeerDescriptor(targetDescriptor))
501
-
502
- if (!connection) {
537
+ if (!endpoint) {
503
538
  logger.debug('gracefullyDisconnectedAsync() tried on a non-existing connection')
504
539
  return
505
540
  }
506
541
 
507
- const promise = new Promise<void>((resolve, _reject) => {
508
- // TODO use config option or named constant?
509
- // eslint-disable-next-line promise/catch-or-return
510
- waitForEvent3<ManagedConnectionEvents>(connection, 'disconnected', 2000).then(() => {
511
- logger.trace('disconnected event received in gracefullyDisconnectAsync()')
512
- })
513
- .catch((e) => {
514
- logger.trace('force-closing connection after timeout ' + e)
515
- // TODO should we have some handling for this floating promise?
516
- connection.close(true)
542
+ if (endpoint.connected) {
543
+ const connection = endpoint.connection
544
+ const promise = new Promise<void>((resolve, _reject) => {
545
+ // TODO use options option or named constant?
546
+ // eslint-disable-next-line promise/catch-or-return
547
+ waitForEvent3<ManagedConnectionEvents>(connection, 'disconnected', 2000).then(() => {
548
+ logger.trace('disconnected event received in gracefullyDisconnectAsync()')
517
549
  })
518
- .finally(() => {
519
- logger.trace('resolving after receiving disconnected event')
520
- resolve()
521
- })
522
- })
523
-
524
- await Promise.all([
525
- promise,
526
- this.doGracefullyDisconnectAsync(targetDescriptor, disconnectMode)
527
- ])
550
+ .catch((e) => {
551
+ logger.trace('force-closing connection after timeout ' + e)
552
+ // TODO should we have some handling for this floating promise?
553
+ connection.close(true)
554
+ })
555
+ .finally(() => {
556
+ logger.trace('resolving after receiving disconnected event')
557
+ resolve()
558
+ })
559
+ })
560
+
561
+ await Promise.all([
562
+ promise,
563
+ this.doGracefullyDisconnectAsync(targetDescriptor, disconnectMode)
564
+ ])
565
+ } else {
566
+ endpoint.connection.close(true)
567
+ }
568
+
528
569
  }
529
570
 
530
571
  private async doGracefullyDisconnectAsync(targetDescriptor: PeerDescriptor, disconnectMode: DisconnectMode): Promise<void> {
@@ -544,14 +585,15 @@ export class ConnectionManager extends EventEmitter<TransportEvents> implements
544
585
  }
545
586
 
546
587
  public getConnections(): PeerDescriptor[] {
547
- return Array.from(this.connections.values())
588
+ return Array.from(this.endpoints.values())
589
+ .map((endpoint) => endpoint)
548
590
  // TODO is this filtering needed? (if it is, should we do the same filtering e.g.
549
- // in getConnection() or in other methods which access this.connections directly?)
550
- .filter((managedConnection: ManagedConnection) => managedConnection.isHandshakeCompleted())
551
- .map((managedConnection: ManagedConnection) => managedConnection.getPeerDescriptor()!)
591
+ // in getConnection() or in other methods which access this.endpoints directly?)
592
+ .filter((endpoint) => endpoint.connected)
593
+ .map((endpoint) => endpoint.connection.getPeerDescriptor()!)
552
594
  }
553
595
 
554
596
  private onConnectionCountChange() {
555
- this.metrics.connectionAverageCount.record(this.connections.size)
597
+ this.metrics.connectionAverageCount.record(this.endpoints.size)
556
598
  }
557
599
  }