@streamr/dht 100.0.0-testnet-three.6 → 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 (215) hide show
  1. package/README.md +1 -1
  2. package/dist/package.json +12 -8
  3. package/dist/src/connection/ConnectionLockRpcLocal.d.ts +1 -1
  4. package/dist/src/connection/ConnectionLockRpcRemote.d.ts +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/{ConnectionLockHandler.d.ts → ConnectionLockStates.d.ts} +3 -3
  8. package/dist/src/connection/{ConnectionLockHandler.js → ConnectionLockStates.js} +17 -9
  9. package/dist/src/connection/ConnectionLockStates.js.map +1 -0
  10. package/dist/src/connection/ConnectionManager.d.ts +9 -7
  11. package/dist/src/connection/ConnectionManager.js +16 -18
  12. package/dist/src/connection/ConnectionManager.js.map +1 -1
  13. package/dist/src/connection/ConnectorFacade.js +1 -1
  14. package/dist/src/connection/ConnectorFacade.js.map +1 -1
  15. package/dist/src/connection/Handshaker.js +6 -13
  16. package/dist/src/connection/Handshaker.js.map +1 -1
  17. package/dist/src/connection/ManagedConnection.d.ts +2 -2
  18. package/dist/src/connection/ManagedConnection.js +8 -8
  19. package/dist/src/connection/ManagedConnection.js.map +1 -1
  20. package/dist/src/connection/connectivityChecker.d.ts +1 -1
  21. package/dist/src/connection/connectivityChecker.js +8 -8
  22. package/dist/src/connection/connectivityChecker.js.map +1 -1
  23. package/dist/src/connection/connectivityRequestHandler.d.ts +2 -2
  24. package/dist/src/connection/connectivityRequestHandler.js +10 -11
  25. package/dist/src/connection/connectivityRequestHandler.js.map +1 -1
  26. package/dist/src/connection/webrtc/WebrtcConnector.d.ts +1 -0
  27. package/dist/src/connection/webrtc/WebrtcConnector.js +13 -8
  28. package/dist/src/connection/webrtc/WebrtcConnector.js.map +1 -1
  29. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.d.ts +2 -0
  30. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js +4 -6
  31. package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js.map +1 -1
  32. package/dist/src/connection/websocket/AbstractWebsocketClientConnection.d.ts +28 -0
  33. package/dist/src/connection/websocket/{ClientWebsocket.js → AbstractWebsocketClientConnection.js} +42 -68
  34. package/dist/src/connection/websocket/AbstractWebsocketClientConnection.js.map +1 -0
  35. package/dist/src/connection/websocket/NodeWebsocketClientConnection.d.ts +7 -0
  36. package/dist/src/connection/websocket/NodeWebsocketClientConnection.js +39 -0
  37. package/dist/src/connection/websocket/NodeWebsocketClientConnection.js.map +1 -0
  38. package/dist/src/connection/websocket/WebsocketConnector.js +26 -23
  39. package/dist/src/connection/websocket/WebsocketConnector.js.map +1 -1
  40. package/dist/src/connection/websocket/WebsocketServer.js +25 -35
  41. package/dist/src/connection/websocket/WebsocketServer.js.map +1 -1
  42. package/dist/src/connection/websocket/{ServerWebsocket.d.ts → WebsocketServerConnection.d.ts} +4 -5
  43. package/dist/src/connection/websocket/{ServerWebsocket.js → WebsocketServerConnection.js} +18 -51
  44. package/dist/src/connection/websocket/WebsocketServerConnection.js.map +1 -0
  45. package/dist/src/dht/DhtNode.d.ts +15 -8
  46. package/dist/src/dht/DhtNode.js +62 -31
  47. package/dist/src/dht/DhtNode.js.map +1 -1
  48. package/dist/src/dht/DhtNodeRpcLocal.d.ts +5 -1
  49. package/dist/src/dht/DhtNodeRpcLocal.js +10 -0
  50. package/dist/src/dht/DhtNodeRpcLocal.js.map +1 -1
  51. package/dist/src/dht/DhtNodeRpcRemote.d.ts +3 -0
  52. package/dist/src/dht/DhtNodeRpcRemote.js +16 -1
  53. package/dist/src/dht/DhtNodeRpcRemote.js.map +1 -1
  54. package/dist/src/dht/ExternalApiRpcLocal.d.ts +2 -2
  55. package/dist/src/dht/ExternalApiRpcLocal.js +3 -3
  56. package/dist/src/dht/ExternalApiRpcLocal.js.map +1 -1
  57. package/dist/src/dht/ExternalApiRpcRemote.d.ts +1 -1
  58. package/dist/src/dht/ExternalApiRpcRemote.js +2 -2
  59. package/dist/src/dht/ExternalApiRpcRemote.js.map +1 -1
  60. package/dist/src/dht/PeerManager.d.ts +15 -3
  61. package/dist/src/dht/PeerManager.js +54 -40
  62. package/dist/src/dht/PeerManager.js.map +1 -1
  63. package/dist/src/dht/contact/RingContactList.d.ts +31 -0
  64. package/dist/src/dht/contact/RingContactList.js +133 -0
  65. package/dist/src/dht/contact/RingContactList.js.map +1 -0
  66. package/dist/src/dht/contact/SortedContactList.d.ts +2 -1
  67. package/dist/src/dht/contact/SortedContactList.js +19 -17
  68. package/dist/src/dht/contact/SortedContactList.js.map +1 -1
  69. package/dist/src/dht/contact/ringIdentifiers.d.ts +16 -0
  70. package/dist/src/dht/contact/ringIdentifiers.js +54 -0
  71. package/dist/src/dht/contact/ringIdentifiers.js.map +1 -0
  72. package/dist/src/dht/discovery/DiscoverySession.js +3 -1
  73. package/dist/src/dht/discovery/DiscoverySession.js.map +1 -1
  74. package/dist/src/dht/discovery/PeerDiscovery.d.ts +6 -2
  75. package/dist/src/dht/discovery/PeerDiscovery.js +41 -4
  76. package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
  77. package/dist/src/dht/discovery/RingDiscoverySession.d.ts +29 -0
  78. package/dist/src/dht/discovery/RingDiscoverySession.js +125 -0
  79. package/dist/src/dht/discovery/RingDiscoverySession.js.map +1 -0
  80. package/dist/src/dht/recursive-operation/RecursiveOperationManager.js +1 -1
  81. package/dist/src/dht/recursive-operation/RecursiveOperationManager.js.map +1 -1
  82. package/dist/src/dht/recursive-operation/RecursiveOperationRpcRemote.js +1 -1
  83. package/dist/src/dht/recursive-operation/RecursiveOperationRpcRemote.js.map +1 -1
  84. package/dist/src/dht/recursive-operation/RecursiveOperationSession.js +0 -1
  85. package/dist/src/dht/recursive-operation/RecursiveOperationSession.js.map +1 -1
  86. package/dist/src/dht/routing/Router.d.ts +0 -1
  87. package/dist/src/dht/routing/Router.js +0 -1
  88. package/dist/src/dht/routing/Router.js.map +1 -1
  89. package/dist/src/dht/routing/RouterRpcLocal.d.ts +0 -1
  90. package/dist/src/dht/routing/RouterRpcLocal.js.map +1 -1
  91. package/dist/src/dht/routing/RouterRpcRemote.js +2 -2
  92. package/dist/src/dht/routing/RouterRpcRemote.js.map +1 -1
  93. package/dist/src/dht/routing/RoutingSession.js +2 -2
  94. package/dist/src/dht/routing/RoutingSession.js.map +1 -1
  95. package/dist/src/dht/store/LocalDataStore.js +2 -2
  96. package/dist/src/dht/store/LocalDataStore.js.map +1 -1
  97. package/dist/src/dht/store/StoreManager.js +2 -2
  98. package/dist/src/dht/store/StoreManager.js.map +1 -1
  99. package/dist/src/exports.d.ts +3 -2
  100. package/dist/src/exports.js +3 -3
  101. package/dist/src/exports.js.map +1 -1
  102. package/dist/src/helpers/createPeerDescriptor.d.ts +1 -1
  103. package/dist/src/helpers/createPeerDescriptor.js +2 -1
  104. package/dist/src/helpers/createPeerDescriptor.js.map +1 -1
  105. package/dist/src/helpers/version.d.ts +6 -0
  106. package/dist/src/helpers/version.js +38 -0
  107. package/dist/src/helpers/version.js.map +1 -0
  108. package/dist/src/proto/packages/dht/protos/DhtRpc.client.d.ts +16 -6
  109. package/dist/src/proto/packages/dht/protos/DhtRpc.client.js +11 -4
  110. package/dist/src/proto/packages/dht/protos/DhtRpc.client.js.map +1 -1
  111. package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +98 -87
  112. package/dist/src/proto/packages/dht/protos/DhtRpc.js +45 -49
  113. package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -1
  114. package/dist/src/proto/packages/dht/protos/DhtRpc.server.d.ts +10 -4
  115. package/dist/src/transport/RoutingRpcCommunicator.js +0 -2
  116. package/dist/src/transport/RoutingRpcCommunicator.js.map +1 -1
  117. package/karma.config.js +4 -1
  118. package/package.json +12 -8
  119. package/protos/DhtRpc.proto +21 -21
  120. package/src/connection/ConnectionLockRpcLocal.ts +1 -1
  121. package/src/connection/ConnectionLockRpcRemote.ts +2 -2
  122. package/src/connection/{ConnectionLockHandler.ts → ConnectionLockStates.ts} +14 -6
  123. package/src/connection/ConnectionManager.ts +21 -22
  124. package/src/connection/ConnectorFacade.ts +1 -2
  125. package/src/connection/Handshaker.ts +7 -15
  126. package/src/connection/ManagedConnection.ts +8 -8
  127. package/src/connection/connectivityChecker.ts +9 -10
  128. package/src/connection/connectivityRequestHandler.ts +16 -16
  129. package/src/connection/webrtc/BrowserWebrtcConnection.ts +18 -0
  130. package/src/connection/webrtc/NodeWebrtcConnection.ts +1 -1
  131. package/src/connection/webrtc/WebrtcConnector.ts +14 -8
  132. package/src/connection/webrtc/WebrtcConnectorRpcLocal.ts +5 -5
  133. package/src/connection/websocket/{ClientWebsocket.ts → AbstractWebsocketClientConnection.ts} +57 -70
  134. package/src/connection/websocket/BrowserWebsocketClientConnection.ts +44 -0
  135. package/src/connection/websocket/NodeWebsocketClientConnection.ts +39 -0
  136. package/src/connection/websocket/WebsocketConnector.ts +27 -28
  137. package/src/connection/websocket/WebsocketServer.ts +27 -42
  138. package/src/connection/websocket/{ServerWebsocket.ts → WebsocketServerConnection.ts} +15 -56
  139. package/src/dht/DhtNode.ts +85 -50
  140. package/src/dht/DhtNodeRpcLocal.ts +16 -0
  141. package/src/dht/DhtNodeRpcRemote.ts +19 -1
  142. package/src/dht/ExternalApiRpcLocal.ts +5 -5
  143. package/src/dht/ExternalApiRpcRemote.ts +4 -4
  144. package/src/dht/PeerManager.ts +70 -44
  145. package/src/dht/contact/RingContactList.ts +151 -0
  146. package/src/dht/contact/SortedContactList.ts +22 -18
  147. package/src/dht/contact/ringIdentifiers.ts +62 -0
  148. package/src/dht/discovery/DiscoverySession.ts +3 -1
  149. package/src/dht/discovery/PeerDiscovery.ts +45 -6
  150. package/src/dht/discovery/RingDiscoverySession.ts +162 -0
  151. package/src/dht/recursive-operation/RecursiveOperationManager.ts +1 -1
  152. package/src/dht/recursive-operation/RecursiveOperationRpcRemote.ts +1 -1
  153. package/src/dht/recursive-operation/RecursiveOperationSession.ts +1 -3
  154. package/src/dht/routing/Router.ts +0 -2
  155. package/src/dht/routing/RouterRpcLocal.ts +0 -1
  156. package/src/dht/routing/RouterRpcRemote.ts +2 -2
  157. package/src/dht/routing/RoutingSession.ts +2 -2
  158. package/src/dht/store/LocalDataStore.ts +1 -1
  159. package/src/dht/store/StoreManager.ts +2 -2
  160. package/src/exports.ts +3 -2
  161. package/src/helpers/createPeerDescriptor.ts +2 -1
  162. package/src/helpers/version.ts +32 -0
  163. package/src/proto/packages/dht/protos/DhtRpc.client.ts +22 -9
  164. package/src/proto/packages/dht/protos/DhtRpc.server.ts +10 -4
  165. package/src/proto/packages/dht/protos/DhtRpc.ts +122 -100
  166. package/src/transport/RoutingRpcCommunicator.ts +1 -2
  167. package/test/benchmark/Find.test.ts +3 -4
  168. package/test/benchmark/KademliaCorrectness.test.ts +14 -8
  169. package/test/benchmark/RingCorrectness.test.ts +157 -0
  170. package/test/benchmark/WebsocketServerMemoryLeak.test.ts +2 -2
  171. package/test/benchmark/hybrid-network-simulation/RingContactList.test.ts +72 -0
  172. package/test/data/generateGroundTruthData.ts +2 -2
  173. package/test/end-to-end/memory-leak.test.ts +1 -2
  174. package/test/integration/ConnectionManager.test.ts +28 -10
  175. package/test/integration/ConnectivityChecking.test.ts +3 -15
  176. package/test/integration/DhtNodeExternalAPI.test.ts +6 -6
  177. package/test/integration/Find.test.ts +6 -6
  178. package/test/integration/Layer1-scale.test.ts +0 -1
  179. package/test/integration/ReplicateData.test.ts +4 -4
  180. package/test/integration/RouteMessage.test.ts +1 -6
  181. package/test/integration/RouterRpcRemote.test.ts +1 -3
  182. package/test/integration/SimultaneousConnections.test.ts +9 -10
  183. package/test/integration/Store.test.ts +4 -4
  184. package/test/integration/StoreAndDelete.test.ts +5 -5
  185. package/test/integration/StoreOnDhtWithThreeNodes.test.ts +5 -5
  186. package/test/integration/StoreOnDhtWithTwoNodes.test.ts +3 -3
  187. package/test/integration/WebrtcConnectionManagement.test.ts +3 -9
  188. package/test/integration/Websocket.test.ts +2 -2
  189. package/test/integration/WebsocketConnectionManagement.test.ts +1 -6
  190. package/test/integration/rpc-connections-over-webrpc.test.ts +1 -2
  191. package/test/unit/PeerManager.test.ts +44 -10
  192. package/test/unit/RecursiveOperationManager.test.ts +14 -8
  193. package/test/unit/RecursiveOperationSession.test.ts +1 -1
  194. package/test/unit/Router.test.ts +0 -3
  195. package/test/unit/RoutingSession.test.ts +1 -2
  196. package/test/unit/connectivityRequestHandler.test.ts +5 -9
  197. package/test/unit/createPeerDescriptor.test.ts +12 -6
  198. package/test/unit/version.test.ts +18 -0
  199. package/test/utils/utils.ts +60 -47
  200. package/tsconfig.browser.json +2 -1
  201. package/tsconfig.jest.json +4 -2
  202. package/tsconfig.node.json +4 -2
  203. package/dist/src/connection/ConnectionLockHandler.js.map +0 -1
  204. package/dist/src/connection/websocket/ClientWebsocket.d.ts +0 -17
  205. package/dist/src/connection/websocket/ClientWebsocket.js.map +0 -1
  206. package/dist/src/connection/websocket/ServerWebsocket.js.map +0 -1
  207. package/dist/src/helpers/MapWithTtl.d.ts +0 -14
  208. package/dist/src/helpers/MapWithTtl.js +0 -60
  209. package/dist/src/helpers/MapWithTtl.js.map +0 -1
  210. package/dist/src/helpers/versionCompatibility.d.ts +0 -2
  211. package/dist/src/helpers/versionCompatibility.js +0 -18
  212. package/dist/src/helpers/versionCompatibility.js.map +0 -1
  213. package/src/helpers/MapWithTtl.ts +0 -71
  214. package/src/helpers/versionCompatibility.ts +0 -13
  215. package/test/unit/versionCompatibility.test.ts +0 -16
@@ -35,7 +35,7 @@ export class ManagedConnection extends EventEmitter<Events> {
35
35
  public connectionType: ConnectionType
36
36
  private handshaker?: Handshaker
37
37
  private handshakeCompleted = false
38
- private lastUsed: number = Date.now()
38
+ private lastUsedTimestamp: number = Date.now()
39
39
  private stopped = false
40
40
  private bufferSentbyOtherConnection = false
41
41
  private closing = false
@@ -160,8 +160,8 @@ export class ManagedConnection extends EventEmitter<Events> {
160
160
  return getNodeIdFromPeerDescriptor(this.remotePeerDescriptor!)
161
161
  }
162
162
 
163
- public getLastUsed(): number {
164
- return this.lastUsed
163
+ public getLastUsedTimestamp(): number {
164
+ return this.lastUsedTimestamp
165
165
  }
166
166
 
167
167
  public setRemotePeerDescriptor(peerDescriptor: PeerDescriptor): void {
@@ -173,7 +173,7 @@ export class ManagedConnection extends EventEmitter<Events> {
173
173
  }
174
174
 
175
175
  private onHandshakeCompleted(peerDescriptor: PeerDescriptor) {
176
- this.lastUsed = Date.now()
176
+ this.lastUsedTimestamp = Date.now()
177
177
 
178
178
  this.setRemotePeerDescriptor(peerDescriptor)
179
179
  this.handshakeCompleted = true
@@ -193,7 +193,7 @@ export class ManagedConnection extends EventEmitter<Events> {
193
193
  this.implementation = impl
194
194
 
195
195
  impl.on('data', (bytes: Uint8Array) => {
196
- this.lastUsed = Date.now()
196
+ this.lastUsedTimestamp = Date.now()
197
197
  if (this.listenerCount('managedData') === 0) {
198
198
  this.inputBuffer.push(bytes)
199
199
  } else {
@@ -205,7 +205,7 @@ export class ManagedConnection extends EventEmitter<Events> {
205
205
  this.emit('error', name)
206
206
  })
207
207
  impl.on('connected', () => {
208
- this.lastUsed = Date.now()
208
+ this.lastUsedTimestamp = Date.now()
209
209
  logger.trace('connected emitted')
210
210
  this.emit('connected')
211
211
  })
@@ -231,7 +231,7 @@ export class ManagedConnection extends EventEmitter<Events> {
231
231
  if (this.closing) {
232
232
  throw new Err.SendFailed('ManagedConnection is closing')
233
233
  }
234
- this.lastUsed = Date.now()
234
+ this.lastUsedTimestamp = Date.now()
235
235
 
236
236
  if (!connect && !this.implementation) {
237
237
  throw new Err.ConnectionNotOpen('Connection not open when calling send() with connect flag as false')
@@ -263,7 +263,7 @@ export class ManagedConnection extends EventEmitter<Events> {
263
263
  }
264
264
 
265
265
  public sendNoWait(data: Uint8Array): void {
266
- this.lastUsed = Date.now()
266
+ this.lastUsedTimestamp = Date.now()
267
267
  if (this.implementation) {
268
268
  this.implementation.send(data)
269
269
  } else {
@@ -3,12 +3,12 @@ import { v4 } from 'uuid'
3
3
  import * as Err from '../helpers/errors'
4
4
  import {
5
5
  ConnectivityRequest, ConnectivityResponse,
6
- Message, MessageType, PeerDescriptor
6
+ Message, PeerDescriptor
7
7
  } from '../proto/packages/dht/protos/DhtRpc'
8
8
  import { ConnectionEvents, IConnection } from './IConnection'
9
- import { ClientWebsocket } from './websocket/ClientWebsocket'
9
+ import { WebsocketClientConnection } from './websocket/NodeWebsocketClientConnection'
10
10
  import { connectivityMethodToWebsocketUrl } from './websocket/WebsocketConnector'
11
- import { isCompatibleVersion } from '../helpers/versionCompatibility'
11
+ import { isMaybeSupportedVersion } from '../helpers/version'
12
12
 
13
13
  const logger = new Logger(module)
14
14
 
@@ -16,7 +16,7 @@ const logger = new Logger(module)
16
16
  export const connectAsync = async ({ url, selfSigned, timeoutMs = 1000 }:
17
17
  { url: string, selfSigned: boolean, timeoutMs?: number }
18
18
  ): Promise<IConnection> => {
19
- const socket = new ClientWebsocket()
19
+ const socket = new WebsocketClientConnection()
20
20
  let result: RunAndRaceEventsReturnType<ConnectionEvents>
21
21
  try {
22
22
  result = await runAndRaceEvents3<ConnectionEvents>([
@@ -37,8 +37,7 @@ const CONNECTIVITY_CHECKER_TIMEOUT = 5000
37
37
 
38
38
  export const sendConnectivityRequest = async (
39
39
  request: ConnectivityRequest,
40
- entryPoint: PeerDescriptor,
41
- localVersion: string
40
+ entryPoint: PeerDescriptor
42
41
  ): Promise<ConnectivityResponse> => {
43
42
  let outgoingConnection: IConnection
44
43
  const wsServerInfo = {
@@ -59,7 +58,7 @@ export const sendConnectivityRequest = async (
59
58
  // send connectivity request
60
59
  const msg: Message = {
61
60
  serviceId: CONNECTIVITY_CHECKER_SERVICE_ID,
62
- messageType: MessageType.CONNECTIVITY_REQUEST, messageId: v4(),
61
+ messageId: v4(),
63
62
  body: {
64
63
  oneofKind: 'connectivityRequest',
65
64
  connectivityRequest: request
@@ -83,16 +82,16 @@ export const sendConnectivityRequest = async (
83
82
  const remoteVersion = connectivityResponseMessage.version
84
83
  outgoingConnection!.off('data', listener)
85
84
  clearTimeout(timeoutId)
86
- if (isCompatibleVersion(localVersion, remoteVersion)) {
85
+ if (isMaybeSupportedVersion(remoteVersion)) {
87
86
  resolve(connectivityResponseMessage)
88
87
  } else {
89
- reject(`Invalid version: ${remoteVersion}`)
88
+ reject(`Unsupported version: ${remoteVersion}`)
90
89
  }
91
90
  } else {
92
91
  return
93
92
  }
94
93
  } catch (err) {
95
- logger.trace(`Could not parse message: ${err}`)
94
+ logger.trace('Could not parse message', { err })
96
95
  }
97
96
  }
98
97
  outgoingConnection!.on('data', listener)
@@ -1,21 +1,22 @@
1
1
  import { ipv4ToNumber, Logger } from '@streamr/utils'
2
2
  import { v4 } from 'uuid'
3
3
  import {
4
- ConnectivityRequest, ConnectivityResponse,
5
- Message, MessageType
4
+ ConnectivityRequest,
5
+ ConnectivityResponse,
6
+ Message
6
7
  } from '../proto/packages/dht/protos/DhtRpc'
7
8
  import { NatType } from './ConnectionManager'
8
9
  import { CONNECTIVITY_CHECKER_SERVICE_ID, connectAsync } from './connectivityChecker'
9
10
  import { IConnection } from './IConnection'
10
- import { ServerWebsocket } from './websocket/ServerWebsocket'
11
+ import { WebsocketServerConnection } from './websocket/WebsocketServerConnection'
11
12
  import { connectivityMethodToWebsocketUrl } from './websocket/WebsocketConnector'
12
- import { version as localVersion } from '../../package.json'
13
+ import { LOCAL_PROTOCOL_VERSION } from '../helpers/version'
13
14
 
14
15
  export const DISABLE_CONNECTIVITY_PROBE = 0
15
16
 
16
17
  const logger = new Logger(module)
17
18
 
18
- export const attachConnectivityRequestHandler = (connectionToListenTo: ServerWebsocket): void => {
19
+ export const attachConnectivityRequestHandler = (connectionToListenTo: WebsocketServerConnection): void => {
19
20
  connectionToListenTo.on('data', async (data: Uint8Array) => {
20
21
  logger.trace('server received data')
21
22
  try {
@@ -25,19 +26,19 @@ export const attachConnectivityRequestHandler = (connectionToListenTo: ServerWeb
25
26
  try {
26
27
  await handleIncomingConnectivityRequest(connectionToListenTo, message.body.connectivityRequest)
27
28
  logger.trace('handleIncomingConnectivityRequest ok')
28
- } catch (e) {
29
- logger.error('handleIncomingConnectivityRequest', { error: e })
29
+ } catch (err1) {
30
+ logger.error('handleIncomingConnectivityRequest', { err: err1 })
30
31
  }
31
32
  }
32
- } catch (err) {
33
- logger.trace(`Could not parse message: ${err}`)
33
+ } catch (err2) {
34
+ logger.trace('Could not parse message', { err: err2 })
34
35
  }
35
36
  })
36
37
  }
37
38
 
38
- const handleIncomingConnectivityRequest = async (connection: ServerWebsocket, connectivityRequest: ConnectivityRequest): Promise<void> => {
39
- const host = connectivityRequest.host ?? connection.getRemoteAddress()
40
- const ipAddress = connection.getRemoteIp()
39
+ const handleIncomingConnectivityRequest = async (connection: WebsocketServerConnection, connectivityRequest: ConnectivityRequest): Promise<void> => {
40
+ const host = connectivityRequest.host ?? connection.remoteIpAddress
41
+ const ipAddress = connection.remoteIpAddress
41
42
  let connectivityResponse: ConnectivityResponse
42
43
  if (connectivityRequest.port !== DISABLE_CONNECTIVITY_PROBE) {
43
44
  connectivityResponse = await connectivityProbe(connectivityRequest, ipAddress, host)
@@ -47,12 +48,11 @@ const handleIncomingConnectivityRequest = async (connection: ServerWebsocket, co
47
48
  host,
48
49
  natType: NatType.UNKNOWN,
49
50
  ipAddress: ipv4ToNumber(ipAddress),
50
- version: localVersion
51
+ version: LOCAL_PROTOCOL_VERSION
51
52
  }
52
53
  }
53
54
  const msg: Message = {
54
55
  serviceId: CONNECTIVITY_CHECKER_SERVICE_ID,
55
- messageType: MessageType.CONNECTIVITY_RESPONSE,
56
56
  messageId: v4(),
57
57
  body: {
58
58
  oneofKind: 'connectivityResponse',
@@ -84,7 +84,7 @@ const connectivityProbe = async (connectivityRequest: ConnectivityRequest, ipAdd
84
84
  natType: NatType.OPEN_INTERNET,
85
85
  websocket: { host, port: connectivityRequest.port, tls: connectivityRequest.tls },
86
86
  ipAddress: ipv4ToNumber(ipAddress),
87
- version: localVersion
87
+ version: LOCAL_PROTOCOL_VERSION
88
88
  }
89
89
  } catch (err) {
90
90
  logger.debug('error', { err })
@@ -92,7 +92,7 @@ const connectivityProbe = async (connectivityRequest: ConnectivityRequest, ipAdd
92
92
  host,
93
93
  natType: NatType.UNKNOWN,
94
94
  ipAddress: ipv4ToNumber(ipAddress),
95
- version: localVersion
95
+ version: LOCAL_PROTOCOL_VERSION
96
96
  }
97
97
  }
98
98
  if (outgoingConnection) {
@@ -5,6 +5,12 @@ import { Logger } from '@streamr/utils'
5
5
  import { IceServer } from './WebrtcConnector'
6
6
  import { createRandomConnectionId } from '../Connection'
7
7
 
8
+ enum DisconnectedRtcPeerConnectionStateEnum {
9
+ DISCONNECTED = 'disconnected',
10
+ FAILED = 'failed',
11
+ CLOSED = 'closed',
12
+ }
13
+
8
14
  const logger = new Logger(module)
9
15
 
10
16
  export const WEBRTC_CLEANUP = new class {
@@ -58,6 +64,8 @@ export class NodeWebrtcConnection extends EventEmitter<Events> implements IWebrt
58
64
  logger.trace(`conn.onGatheringStateChange: ${this.peerConnection?.iceGatheringState}`)
59
65
  }
60
66
 
67
+ this.peerConnection.onconnectionstatechange = () => this.onStateChange()
68
+
61
69
  if (isOffering) {
62
70
  this.peerConnection.onnegotiationneeded = async () => {
63
71
  try {
@@ -211,6 +219,7 @@ export class NodeWebrtcConnection extends EventEmitter<Events> implements IWebrt
211
219
  }
212
220
 
213
221
  if (this.peerConnection !== undefined) {
222
+ this.peerConnection.onconnectionstatechange = null
214
223
  this.peerConnection.onicecandidate = null
215
224
  this.peerConnection.onicegatheringstatechange = null
216
225
  this.peerConnection.onnegotiationneeded = null
@@ -223,6 +232,15 @@ export class NodeWebrtcConnection extends EventEmitter<Events> implements IWebrt
223
232
  this.emit('connected')
224
233
  }
225
234
 
235
+ private onStateChange(): void {
236
+ if (this.peerConnection!.connectionState === DisconnectedRtcPeerConnectionStateEnum.CLOSED
237
+ || this.peerConnection!.connectionState === DisconnectedRtcPeerConnectionStateEnum.DISCONNECTED
238
+ || this.peerConnection!.connectionState === DisconnectedRtcPeerConnectionStateEnum.FAILED
239
+ ) {
240
+ this.doClose(false)
241
+ }
242
+ }
243
+
226
244
  public setConnectionId(connectionId: ConnectionID): void {
227
245
  this.connectionId = connectionId
228
246
  }
@@ -26,7 +26,7 @@ export interface Params {
26
26
  bufferThresholdLow?: number
27
27
  connectingTimeout?: number
28
28
  maxMessageSize?: number
29
- iceServers?: IceServer[]
29
+ iceServers?: IceServer[] // TODO make this parameter required (empty array is a good fallback which can be set by the caller if needed)
30
30
  portRange?: PortRange
31
31
  }
32
32
 
@@ -75,6 +75,7 @@ export class WebrtcConnector {
75
75
  onNewConnection: (connection: ManagedConnection) => boolean
76
76
  ) {
77
77
  const localRpc = new WebrtcConnectorRpcLocal({
78
+ createConnection: (targetPeerDescriptor: PeerDescriptor) => this.createConnection(targetPeerDescriptor),
78
79
  connect: (targetPeerDescriptor: PeerDescriptor) => this.connect(targetPeerDescriptor),
79
80
  onNewConnection,
80
81
  ongoingConnectAttempts: this.ongoingConnectAttempts,
@@ -133,14 +134,7 @@ export class WebrtcConnector {
133
134
  return existingConnection
134
135
  }
135
136
 
136
- const connection = new NodeWebrtcConnection({
137
- remotePeerDescriptor: targetPeerDescriptor,
138
- iceServers: this.config.iceServers,
139
- bufferThresholdLow: this.config.bufferThresholdLow,
140
- bufferThresholdHigh: this.config.bufferThresholdHigh,
141
- connectingTimeout: this.config.connectionTimeout,
142
- portRange: this.config.portRange
143
- })
137
+ const connection = this.createConnection(targetPeerDescriptor)
144
138
 
145
139
  const localNodeId = getNodeIdFromPeerDescriptor(this.localPeerDescriptor!)
146
140
  const targetNodeId = getNodeIdFromPeerDescriptor(targetPeerDescriptor)
@@ -199,6 +193,18 @@ export class WebrtcConnector {
199
193
  return managedConnection
200
194
  }
201
195
 
196
+ private createConnection(targetPeerDescriptor: PeerDescriptor): NodeWebrtcConnection {
197
+ return new NodeWebrtcConnection({
198
+ remotePeerDescriptor: targetPeerDescriptor,
199
+ iceServers: this.config.iceServers,
200
+ bufferThresholdLow: this.config.bufferThresholdLow,
201
+ bufferThresholdHigh: this.config.bufferThresholdHigh,
202
+ connectingTimeout: this.config.connectionTimeout,
203
+ portRange: this.config.portRange
204
+ // TODO should we pass maxMessageSize?
205
+ })
206
+ }
207
+
202
208
  setLocalPeerDescriptor(peerDescriptor: PeerDescriptor): void {
203
209
  this.localPeerDescriptor = peerDescriptor
204
210
  }
@@ -18,13 +18,13 @@ import { ManagedWebrtcConnection } from '../ManagedWebrtcConnection'
18
18
  import { NodeWebrtcConnection } from './NodeWebrtcConnection'
19
19
  import { WebrtcConnectorRpcRemote } from './WebrtcConnectorRpcRemote'
20
20
  import { DhtAddress, getNodeIdFromPeerDescriptor } from '../../identifiers'
21
- import { version as localVersion } from '../../../package.json'
22
- import { isCompatibleVersion } from '../../helpers/versionCompatibility'
21
+ import { isMaybeSupportedVersion } from '../../helpers/version'
23
22
  import { ConnectionID } from '../IConnection'
24
23
 
25
24
  const logger = new Logger(module)
26
25
 
27
26
  interface WebrtcConnectorRpcLocalConfig {
27
+ createConnection: (targetPeerDescriptor: PeerDescriptor) => NodeWebrtcConnection
28
28
  connect: (targetPeerDescriptor: PeerDescriptor) => ManagedConnection
29
29
  onNewConnection: (connection: ManagedConnection) => boolean
30
30
  // TODO pass accessor methods instead of passing a mutable entity
@@ -60,7 +60,7 @@ export class WebrtcConnectorRpcLocal implements IWebrtcConnectorRpc {
60
60
  let connection = managedConnection?.getWebrtcConnection()
61
61
 
62
62
  if (!managedConnection) {
63
- connection = new NodeWebrtcConnection({ remotePeerDescriptor: remotePeer })
63
+ connection = this.config.createConnection(remotePeer)
64
64
  managedConnection = new ManagedWebrtcConnection(this.config.getLocalPeerDescriptor(), undefined, connection)
65
65
  managedConnection.setRemotePeerDescriptor(remotePeer)
66
66
  this.config.ongoingConnectAttempts.set(nodeId, managedConnection)
@@ -84,11 +84,11 @@ export class WebrtcConnectorRpcLocal implements IWebrtcConnectorRpc {
84
84
  connection!.setConnectionId(request.connectionId as ConnectionID)
85
85
  connection!.setRemoteDescription(request.description, 'offer')
86
86
 
87
- managedConnection.on('handshakeRequest', (_sourceDescriptor: PeerDescriptor, sourceVersion: string) => {
87
+ managedConnection.on('handshakeRequest', (_sourceDescriptor: PeerDescriptor, remoteVersion: string) => {
88
88
  if (this.config.ongoingConnectAttempts.has(nodeId)) {
89
89
  this.config.ongoingConnectAttempts.delete(nodeId)
90
90
  }
91
- if (!isCompatibleVersion(sourceVersion, localVersion)) {
91
+ if (!isMaybeSupportedVersion(remoteVersion)) {
92
92
  managedConnection!.rejectHandshake(HandshakeError.UNSUPPORTED_VERSION)
93
93
  } else {
94
94
  managedConnection!.acceptHandshake()
@@ -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
+ }