@streamr/dht 102.0.0-beta.0 → 102.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generated/packages/dht/protos/DhtRpc.d.ts +16 -8
- package/dist/generated/packages/dht/protos/DhtRpc.js +7 -5
- package/dist/generated/packages/dht/protos/DhtRpc.js.map +1 -1
- package/dist/package.json +15 -16
- package/dist/src/connection/ConnectionManager.js +18 -8
- package/dist/src/connection/ConnectionManager.js.map +1 -1
- package/dist/src/connection/Handshaker.d.ts +1 -1
- package/dist/src/connection/Handshaker.js +9 -5
- package/dist/src/connection/Handshaker.js.map +1 -1
- package/dist/src/connection/ManagedConnection.js +17 -7
- package/dist/src/connection/ManagedConnection.js.map +1 -1
- package/dist/src/connection/connectivityChecker.js +20 -10
- package/dist/src/connection/connectivityChecker.js.map +1 -1
- package/dist/src/connection/connectivityRequestHandler.js +3 -3
- package/dist/src/connection/connectivityRequestHandler.js.map +1 -1
- package/dist/src/connection/simulator/Simulator.js +3 -2
- package/dist/src/connection/simulator/Simulator.js.map +1 -1
- package/dist/src/connection/simulator/pings.d.ts +1 -1
- package/dist/src/connection/simulator/pings.js +3 -3
- package/dist/src/connection/simulator/pings.js.map +1 -1
- package/dist/src/connection/webrtc/NodeWebrtcConnection.js +0 -2
- package/dist/src/connection/webrtc/NodeWebrtcConnection.js.map +1 -1
- package/dist/src/connection/webrtc/WebrtcConnector.js +19 -9
- package/dist/src/connection/webrtc/WebrtcConnector.js.map +1 -1
- package/dist/src/connection/webrtc/iceServerAsString.js +1 -2
- package/dist/src/connection/webrtc/iceServerAsString.js.map +1 -1
- package/dist/src/connection/websocket/AbstractWebsocketClientConnection.d.ts +0 -2
- package/dist/src/connection/websocket/WebsocketClientConnectorRpcLocal.d.ts +0 -1
- package/dist/src/connection/websocket/WebsocketServerConnection.d.ts +0 -1
- package/dist/src/connection/websocket/WebsocketServerConnector.js +28 -18
- package/dist/src/connection/websocket/WebsocketServerConnector.js.map +1 -1
- package/dist/src/dht/DhtNode.d.ts +1 -0
- package/dist/src/dht/DhtNode.js +3 -2
- package/dist/src/dht/DhtNode.js.map +1 -1
- package/dist/src/dht/DhtNodeRpcLocal.d.ts +1 -1
- package/dist/src/dht/PeerManager.d.ts +2 -1
- package/dist/src/dht/PeerManager.js +2 -1
- package/dist/src/dht/PeerManager.js.map +1 -1
- package/dist/src/dht/contact/SortedContactList.js +1 -1
- package/dist/src/dht/contact/SortedContactList.js.map +1 -1
- package/dist/src/dht/discovery/DiscoverySession.d.ts +0 -1
- package/dist/src/dht/discovery/PeerDiscovery.d.ts +0 -1
- package/dist/src/dht/discovery/RingDiscoverySession.d.ts +0 -1
- package/dist/src/dht/recursive-operation/RecursiveOperationManager.d.ts +2 -2
- package/dist/src/dht/routing/DuplicateDetector.js.map +1 -1
- package/dist/src/dht/routing/RoutingSession.js +2 -2
- package/dist/src/dht/routing/RoutingSession.js.map +1 -1
- package/dist/src/dht/routing/RoutingTablesCache.d.ts +1 -1
- package/dist/src/dht/store/LocalDataStore.js +1 -1
- package/dist/src/dht/store/LocalDataStore.js.map +1 -1
- package/dist/src/dht/store/StoreManager.d.ts +1 -1
- package/dist/src/dht/store/StoreRpcLocal.d.ts +1 -1
- package/dist/src/helpers/AddressTools.js +2 -3
- package/dist/src/helpers/AddressTools.js.map +1 -1
- package/dist/src/helpers/debugHelpers.js +2 -2
- package/dist/src/helpers/debugHelpers.js.map +1 -1
- package/dist/src/helpers/protoClasses.d.ts +1 -1
- package/dist/src/helpers/protoClasses.js.map +1 -1
- package/dist/src/helpers/protoToString.js +1 -2
- package/dist/src/helpers/protoToString.js.map +1 -1
- package/dist/src/helpers/version.d.ts +1 -1
- package/dist/src/helpers/version.js +4 -4
- package/dist/src/helpers/version.js.map +1 -1
- package/eslint.config.mjs +12 -0
- package/jest.config.ts +12 -0
- package/package.json +15 -16
- package/protos/DhtRpc.proto +6 -4
- package/.eslintignore +0 -5
- package/.eslintrc +0 -3
- package/generated/google/protobuf/any.ts +0 -326
- package/generated/google/protobuf/empty.ts +0 -81
- package/generated/google/protobuf/timestamp.ts +0 -287
- package/generated/packages/dht/protos/DhtRpc.client.ts +0 -419
- package/generated/packages/dht/protos/DhtRpc.server.ts +0 -165
- package/generated/packages/dht/protos/DhtRpc.ts +0 -1266
- package/generated/packages/proto-rpc/protos/ProtoRpc.ts +0 -108
- package/jest.config.js +0 -5
- package/src/connection/Connection.ts +0 -28
- package/src/connection/ConnectionLockRpcLocal.ts +0 -78
- package/src/connection/ConnectionLockRpcRemote.ts +0 -64
- package/src/connection/ConnectionLockStates.ts +0 -131
- package/src/connection/ConnectionManager.ts +0 -661
- package/src/connection/ConnectionsView.ts +0 -8
- package/src/connection/ConnectorFacade.ts +0 -217
- package/src/connection/Handshaker.ts +0 -205
- package/src/connection/IConnection.ts +0 -40
- package/src/connection/ManagedConnection.ts +0 -113
- package/src/connection/OutputBuffer.ts +0 -28
- package/src/connection/PendingConnection.ts +0 -68
- package/src/connection/connectivityChecker.ts +0 -108
- package/src/connection/connectivityRequestHandler.ts +0 -116
- package/src/connection/simulator/Simulator.ts +0 -368
- package/src/connection/simulator/SimulatorConnection.ts +0 -137
- package/src/connection/simulator/SimulatorConnector.ts +0 -98
- package/src/connection/simulator/SimulatorTransport.ts +0 -15
- package/src/connection/simulator/pings.ts +0 -42
- package/src/connection/webrtc/BrowserWebrtcConnection.ts +0 -242
- package/src/connection/webrtc/IWebrtcConnection.ts +0 -24
- package/src/connection/webrtc/NodeWebrtcConnection.ts +0 -247
- package/src/connection/webrtc/WebrtcConnector.ts +0 -234
- package/src/connection/webrtc/WebrtcConnectorRpcLocal.ts +0 -108
- package/src/connection/webrtc/WebrtcConnectorRpcRemote.ts +0 -60
- package/src/connection/webrtc/iceServerAsString.ts +0 -15
- package/src/connection/websocket/AbstractWebsocketClientConnection.ts +0 -122
- package/src/connection/websocket/AutoCertifierClientFacade.ts +0 -89
- package/src/connection/websocket/BrowserWebsocketClientConnection.ts +0 -44
- package/src/connection/websocket/NodeWebsocketClientConnection.ts +0 -39
- package/src/connection/websocket/WebsocketClientConnector.ts +0 -119
- package/src/connection/websocket/WebsocketClientConnectorRpcLocal.ts +0 -38
- package/src/connection/websocket/WebsocketClientConnectorRpcRemote.ts +0 -19
- package/src/connection/websocket/WebsocketServer.ts +0 -164
- package/src/connection/websocket/WebsocketServerConnection.ts +0 -109
- package/src/connection/websocket/WebsocketServerConnector.ts +0 -286
- package/src/dht/DhtNode.ts +0 -678
- package/src/dht/DhtNodeRpcLocal.ts +0 -84
- package/src/dht/DhtNodeRpcRemote.ts +0 -107
- package/src/dht/ExternalApiRpcLocal.ts +0 -58
- package/src/dht/ExternalApiRpcRemote.ts +0 -41
- package/src/dht/PeerManager.ts +0 -303
- package/src/dht/contact/Contact.ts +0 -19
- package/src/dht/contact/ContactList.ts +0 -43
- package/src/dht/contact/RandomContactList.ts +0 -56
- package/src/dht/contact/RingContactList.ts +0 -143
- package/src/dht/contact/RpcRemote.ts +0 -72
- package/src/dht/contact/SortedContactList.ts +0 -173
- package/src/dht/contact/getClosestNodes.ts +0 -24
- package/src/dht/contact/ringIdentifiers.ts +0 -62
- package/src/dht/discovery/DiscoverySession.ts +0 -129
- package/src/dht/discovery/PeerDiscovery.ts +0 -244
- package/src/dht/discovery/RingDiscoverySession.ts +0 -148
- package/src/dht/recursive-operation/RecursiveOperationManager.ts +0 -251
- package/src/dht/recursive-operation/RecursiveOperationRpcLocal.ts +0 -34
- package/src/dht/recursive-operation/RecursiveOperationRpcRemote.ts +0 -43
- package/src/dht/recursive-operation/RecursiveOperationSession.ts +0 -231
- package/src/dht/recursive-operation/RecursiveOperationSessionRpcLocal.ts +0 -35
- package/src/dht/recursive-operation/RecursiveOperationSessionRpcRemote.ts +0 -30
- package/src/dht/routing/DuplicateDetector.ts +0 -34
- package/src/dht/routing/Router.ts +0 -246
- package/src/dht/routing/RouterRpcLocal.ts +0 -78
- package/src/dht/routing/RouterRpcRemote.ts +0 -80
- package/src/dht/routing/RoutingSession.ts +0 -243
- package/src/dht/routing/RoutingTablesCache.ts +0 -60
- package/src/dht/routing/getPreviousPeer.ts +0 -6
- package/src/dht/store/LocalDataStore.ts +0 -84
- package/src/dht/store/StoreManager.ts +0 -170
- package/src/dht/store/StoreRpcLocal.ts +0 -89
- package/src/dht/store/StoreRpcRemote.ts +0 -32
- package/src/exports.ts +0 -33
- package/src/helpers/AddressTools.ts +0 -28
- package/src/helpers/Connectivity.ts +0 -19
- package/src/helpers/browser/isBrowserEnvironment.ts +0 -1
- package/src/helpers/browser/isBrowserEnvironment_override.ts +0 -3
- package/src/helpers/createPeerDescriptor.ts +0 -57
- package/src/helpers/createPeerDescriptorSignaturePayload.ts +0 -28
- package/src/helpers/debugHelpers.ts +0 -9
- package/src/helpers/errors.ts +0 -49
- package/src/helpers/offering.ts +0 -15
- package/src/helpers/protoClasses.ts +0 -57
- package/src/helpers/protoToString.ts +0 -21
- package/src/helpers/version.ts +0 -32
- package/src/identifiers.ts +0 -29
- package/src/rpc-protocol/DhtCallContext.ts +0 -14
- package/src/rpc-protocol/DhtRpcOptions.ts +0 -10
- package/src/transport/ITransport.ts +0 -37
- package/src/transport/ListeningRpcCommunicator.ts +0 -32
- package/src/transport/RoutingRpcCommunicator.ts +0 -66
- package/src/types/ServiceID.ts +0 -1
- package/src/types/textencoding.d.ts +0 -6
- package/test/benchmark/Find.test.ts +0 -72
- package/test/benchmark/KademliaCorrectness.test.ts +0 -114
- package/test/benchmark/RingCorrectness.test.ts +0 -157
- package/test/benchmark/SortedContactListBenchmark.test.ts +0 -108
- package/test/benchmark/WebsocketServerMemoryLeak.test.ts +0 -41
- package/test/benchmark/hybrid-network-simulation/RingContactList.test.ts +0 -71
- package/test/end-to-end/GeoIpLayer0.test.ts +0 -55
- package/test/end-to-end/Layer0-Layer1.test.ts +0 -93
- package/test/end-to-end/Layer0.test.ts +0 -76
- package/test/end-to-end/Layer0MixedConnectionTypes.test.ts +0 -110
- package/test/end-to-end/Layer0Webrtc-Layer1.test.ts +0 -137
- package/test/end-to-end/Layer0Webrtc.test.ts +0 -85
- package/test/end-to-end/Layer1-Scale-WebSocket.test.ts +0 -82
- package/test/end-to-end/Layer1-Scale-Webrtc.test.ts +0 -76
- package/test/end-to-end/RecoveryFromFailedAutoCertification.test.ts +0 -52
- package/test/end-to-end/WebsocketConnectionRequest.test.ts +0 -69
- package/test/end-to-end/memory-leak.test.ts +0 -80
- package/test/integration/ConnectionLocking.test.ts +0 -182
- package/test/integration/ConnectionManager.test.ts +0 -528
- package/test/integration/ConnectivityChecking.test.ts +0 -53
- package/test/integration/DhtJoinPeerDiscovery.test.ts +0 -49
- package/test/integration/DhtNode.test.ts +0 -66
- package/test/integration/DhtNodeExternalAPI.test.ts +0 -48
- package/test/integration/DhtNodeRpcRemote.test.ts +0 -66
- package/test/integration/DhtRpc.test.ts +0 -121
- package/test/integration/Find.test.ts +0 -45
- package/test/integration/GeoIpConnectivityChecking.test.ts +0 -72
- package/test/integration/Layer1-scale.test.ts +0 -189
- package/test/integration/Mock-Layer1-Layer0.test.ts +0 -85
- package/test/integration/MultipleEntryPointJoining.test.ts +0 -105
- package/test/integration/ReplicateData.test.ts +0 -104
- package/test/integration/RouteMessage.test.ts +0 -230
- package/test/integration/RouterRpcRemote.test.ts +0 -77
- package/test/integration/SimultaneousConnections.test.ts +0 -316
- package/test/integration/Store.test.ts +0 -85
- package/test/integration/StoreAndDelete.test.ts +0 -77
- package/test/integration/StoreOnDhtWithThreeNodes.test.ts +0 -59
- package/test/integration/StoreOnDhtWithTwoNodes.test.ts +0 -51
- package/test/integration/StoreRpcRemote.test.ts +0 -54
- package/test/integration/WebrtcConnectionManagement.test.ts +0 -219
- package/test/integration/WebrtcConnectorRpc.test.ts +0 -125
- package/test/integration/Websocket.test.ts +0 -65
- package/test/integration/WebsocketClientConnectorRpc.test.ts +0 -69
- package/test/integration/WebsocketConnectionManagement.test.ts +0 -191
- package/test/integration/rpc-connections-over-webrtc.test.ts +0 -158
- package/test/kademlia-simulation/data/nodeids.json +0 -13002
- package/test/kademlia-simulation/data/orderedneighbors.json +0 -1001
- package/test/types/global.d.ts +0 -1
- package/test/unit/AddressTools.test.ts +0 -44
- package/test/unit/AutoCertifierClientFacade.test.ts +0 -58
- package/test/unit/ConnectionManager.test.ts +0 -65
- package/test/unit/ConnectivityHelpers.test.ts +0 -61
- package/test/unit/DiscoverySession.test.ts +0 -87
- package/test/unit/DuplicateDetector.test.ts +0 -31
- package/test/unit/Handshaker.test.ts +0 -169
- package/test/unit/ListeningRpcCommunicator.test.ts +0 -52
- package/test/unit/LocalDataStore.test.ts +0 -108
- package/test/unit/ManagedConnection.test.ts +0 -58
- package/test/unit/PeerManager.test.ts +0 -93
- package/test/unit/PendingConnection.test.ts +0 -57
- package/test/unit/ProtobufMessage.test.ts +0 -21
- package/test/unit/RandomContactList.test.ts +0 -58
- package/test/unit/RecursiveOperationManager.test.ts +0 -161
- package/test/unit/RecursiveOperationSession.test.ts +0 -68
- package/test/unit/Router.test.ts +0 -137
- package/test/unit/RoutingSession.test.ts +0 -79
- package/test/unit/SortedContactList.test.ts +0 -115
- package/test/unit/StoreManager.test.ts +0 -146
- package/test/unit/StoreRpcLocal.test.ts +0 -167
- package/test/unit/WebrtcConnection.test.ts +0 -29
- package/test/unit/WebrtcConnector.test.ts +0 -56
- package/test/unit/WebsocketClientConnector.test.ts +0 -101
- package/test/unit/WebsocketServer.test.ts +0 -66
- package/test/unit/WebsocketServerConnector.test.ts +0 -102
- package/test/unit/connectivityRequestHandler.test.ts +0 -104
- package/test/unit/createPeerDescriptor.test.ts +0 -69
- package/test/unit/customMatchers.test.ts +0 -16
- package/test/unit/getClosestNodes.test.ts +0 -30
- package/test/unit/version.test.ts +0 -18
- package/test/unit/webrtcReplaceInternalIpWithExternalIp.test.ts +0 -18
- package/test/utils/FakeConnectorFacade.ts +0 -41
- package/test/utils/FakeRpcCommunicator.ts +0 -23
- package/test/utils/FakeTransport.ts +0 -79
- package/test/utils/customMatchers.ts +0 -71
- package/test/utils/mock/MockConnection.ts +0 -26
- package/test/utils/mock/MockConnectionsView.ts +0 -18
- package/test/utils/mock/MockRouter.ts +0 -62
- package/test/utils/mock/MockRpcCommunicator.ts +0 -7
- package/test/utils/mock/MockTransport.ts +0 -26
- package/test/utils/mock/mockDataEntry.ts +0 -38
- package/test/utils/topology.ts +0 -80
- package/test/utils/utils.ts +0 -268
- package/tsconfig.browser.json +0 -17
- package/tsconfig.jest.json +0 -25
- package/tsconfig.json +0 -3
- package/tsconfig.node.json +0 -24
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { DhtAddress } from '../../identifiers'
|
|
2
|
-
import { ContactList } from './ContactList'
|
|
3
|
-
|
|
4
|
-
export class RandomContactList<C extends { getNodeId: () => DhtAddress }> extends ContactList<C> {
|
|
5
|
-
|
|
6
|
-
private randomness: number
|
|
7
|
-
|
|
8
|
-
constructor(
|
|
9
|
-
localNodeId: DhtAddress,
|
|
10
|
-
maxSize: number,
|
|
11
|
-
randomness = 0.20
|
|
12
|
-
) {
|
|
13
|
-
super(localNodeId, maxSize)
|
|
14
|
-
this.randomness = randomness
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
addContact(contact: C): void {
|
|
18
|
-
if (this.localNodeId === contact.getNodeId()) {
|
|
19
|
-
return
|
|
20
|
-
}
|
|
21
|
-
if (!this.contactsById.has(contact.getNodeId())) {
|
|
22
|
-
const roll = Math.random()
|
|
23
|
-
if (roll < this.randomness) {
|
|
24
|
-
if (this.getSize() === this.maxSize && this.getSize() > 0) {
|
|
25
|
-
const toRemove = this.contactIds[0]
|
|
26
|
-
this.removeContact(toRemove)
|
|
27
|
-
}
|
|
28
|
-
this.contactIds.push(contact.getNodeId())
|
|
29
|
-
this.contactsById.set(contact.getNodeId(), contact)
|
|
30
|
-
this.emit(
|
|
31
|
-
'contactAdded',
|
|
32
|
-
contact
|
|
33
|
-
)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
removeContact(id: DhtAddress): boolean {
|
|
39
|
-
if (this.contactsById.has(id)) {
|
|
40
|
-
const removed = this.contactsById.get(id)!
|
|
41
|
-
const index = this.contactIds.findIndex((nodeId) => (nodeId === id))
|
|
42
|
-
this.contactIds.splice(index, 1)
|
|
43
|
-
this.contactsById.delete(id)
|
|
44
|
-
this.emit('contactRemoved', removed)
|
|
45
|
-
return true
|
|
46
|
-
}
|
|
47
|
-
return false
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
public getContacts(limit?: number): C[] {
|
|
51
|
-
const items = (limit === undefined)
|
|
52
|
-
? this.contactIds
|
|
53
|
-
: this.contactIds.slice(0, Math.max(limit, 0))
|
|
54
|
-
return items.map((contactId) => this.contactsById.get(contactId)!)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { PeerDescriptor } from '../../../generated/packages/dht/protos/DhtRpc'
|
|
2
|
-
import { OrderedMap } from '@js-sdsl/ordered-map'
|
|
3
|
-
import { RingDistance, RingId, RingIdRaw, getLeftDistance, getRightDistance, getRingIdFromPeerDescriptor, getRingIdFromRaw } from './ringIdentifiers'
|
|
4
|
-
import { DhtAddress, toNodeId } from '../../identifiers'
|
|
5
|
-
import EventEmitter from 'eventemitter3'
|
|
6
|
-
import { Events } from './ContactList'
|
|
7
|
-
|
|
8
|
-
export interface RingContacts {
|
|
9
|
-
left: PeerDescriptor[]
|
|
10
|
-
right: PeerDescriptor[]
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export class RingContactList<C extends { getPeerDescriptor(): PeerDescriptor }> extends EventEmitter<Events<C>> {
|
|
14
|
-
|
|
15
|
-
private readonly numNeighborsPerSide = 5
|
|
16
|
-
private readonly referenceId: RingId
|
|
17
|
-
private readonly excludedIds: Set<DhtAddress>
|
|
18
|
-
private readonly leftNeighbors: OrderedMap<RingDistance, C>
|
|
19
|
-
private readonly rightNeighbors: OrderedMap<RingDistance, C>
|
|
20
|
-
|
|
21
|
-
constructor(rawReferenceId: RingIdRaw, excludedIds?: Set<DhtAddress>) {
|
|
22
|
-
super()
|
|
23
|
-
this.referenceId = getRingIdFromRaw(rawReferenceId)
|
|
24
|
-
this.excludedIds = excludedIds ?? new Set()
|
|
25
|
-
this.leftNeighbors = new OrderedMap<RingDistance, C>()
|
|
26
|
-
this.rightNeighbors = new OrderedMap<RingDistance, C>()
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
addContact(contact: C): void {
|
|
30
|
-
const id = getRingIdFromPeerDescriptor(contact.getPeerDescriptor())
|
|
31
|
-
if (id === this.referenceId || this.excludedIds.has(toNodeId(contact.getPeerDescriptor()))) {
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
let elementAdded = false
|
|
35
|
-
let elementRemoved = false
|
|
36
|
-
|
|
37
|
-
const leftDistance = getLeftDistance(this.referenceId, id)
|
|
38
|
-
const lastLeftNeighbor = this.leftNeighbors.back()
|
|
39
|
-
if (lastLeftNeighbor === undefined || leftDistance < lastLeftNeighbor[0]) {
|
|
40
|
-
this.leftNeighbors.setElement(leftDistance, contact)
|
|
41
|
-
elementAdded = true
|
|
42
|
-
if (this.leftNeighbors.size() > this.numNeighborsPerSide) {
|
|
43
|
-
this.leftNeighbors.eraseElementByIterator(this.leftNeighbors.rBegin())
|
|
44
|
-
elementRemoved = true
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const rightDistance = getRightDistance(this.referenceId, id)
|
|
49
|
-
const lastRightNeighbor = this.rightNeighbors.back()
|
|
50
|
-
if (lastRightNeighbor === undefined || rightDistance < lastRightNeighbor[0]) {
|
|
51
|
-
this.rightNeighbors.setElement(rightDistance, contact)
|
|
52
|
-
elementAdded = true
|
|
53
|
-
if (this.rightNeighbors.size() > this.numNeighborsPerSide) {
|
|
54
|
-
this.rightNeighbors.eraseElementByIterator(this.rightNeighbors.rBegin())
|
|
55
|
-
elementRemoved = true
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (this.hasEventListeners() && (elementAdded || elementRemoved)) {
|
|
60
|
-
if (elementAdded) {
|
|
61
|
-
this.emit('contactAdded', contact)
|
|
62
|
-
}
|
|
63
|
-
if (elementRemoved) {
|
|
64
|
-
this.emit('contactRemoved', contact)
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
removeContact(contact?: C): void {
|
|
70
|
-
if (contact === undefined) {
|
|
71
|
-
return
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const id = getRingIdFromPeerDescriptor(contact.getPeerDescriptor())
|
|
75
|
-
const leftDistance = getLeftDistance(this.referenceId, id)
|
|
76
|
-
const rightDistance = getRightDistance(this.referenceId, id)
|
|
77
|
-
|
|
78
|
-
let elementRemoved = false
|
|
79
|
-
if (this.leftNeighbors.eraseElementByKey(leftDistance)) {
|
|
80
|
-
elementRemoved = true
|
|
81
|
-
}
|
|
82
|
-
if (this.rightNeighbors.eraseElementByKey(rightDistance)) {
|
|
83
|
-
elementRemoved = true
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (this.hasEventListeners() && elementRemoved) {
|
|
87
|
-
this.emit('contactRemoved', contact)
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
getContact(peerDescriptor: PeerDescriptor): C | undefined {
|
|
92
|
-
const id = getRingIdFromPeerDescriptor(peerDescriptor)
|
|
93
|
-
const leftDistance = getLeftDistance(this.referenceId, id)
|
|
94
|
-
const rightDistance = getRightDistance(this.referenceId, id)
|
|
95
|
-
if (this.leftNeighbors.getElementByKey(leftDistance)) {
|
|
96
|
-
return this.leftNeighbors.getElementByKey(leftDistance)
|
|
97
|
-
}
|
|
98
|
-
if (this.rightNeighbors.getElementByKey(rightDistance)) {
|
|
99
|
-
return this.rightNeighbors.getElementByKey(rightDistance)
|
|
100
|
-
}
|
|
101
|
-
return undefined
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
getClosestContacts(limitPerSide?: number): { left: C[], right: C[] } {
|
|
105
|
-
const leftContacts: C[] = []
|
|
106
|
-
const rightContacts: C[] = []
|
|
107
|
-
|
|
108
|
-
let leftCount = 0
|
|
109
|
-
for (const item of this.leftNeighbors) {
|
|
110
|
-
if (limitPerSide != undefined && leftCount >= limitPerSide) {
|
|
111
|
-
break
|
|
112
|
-
}
|
|
113
|
-
leftContacts.push(item[1])
|
|
114
|
-
leftCount++
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
let rightCount = 0
|
|
118
|
-
for (const item of this.rightNeighbors) {
|
|
119
|
-
if (limitPerSide != undefined && rightCount >= limitPerSide) {
|
|
120
|
-
break
|
|
121
|
-
}
|
|
122
|
-
rightContacts.push(item[1])
|
|
123
|
-
rightCount++
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return { left: leftContacts, right: rightContacts }
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
getAllContacts(): C[] {
|
|
130
|
-
const ret: C[] = []
|
|
131
|
-
for (const item of this.leftNeighbors) {
|
|
132
|
-
ret.push(item[1])
|
|
133
|
-
}
|
|
134
|
-
for (const item of this.rightNeighbors) {
|
|
135
|
-
ret.push(item[1])
|
|
136
|
-
}
|
|
137
|
-
return ret
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
private hasEventListeners(): boolean {
|
|
141
|
-
return this.eventNames().length > 0
|
|
142
|
-
}
|
|
143
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import type { ServiceInfo } from '@protobuf-ts/runtime-rpc'
|
|
2
|
-
import { ClassType, ClientTransport, ProtoRpcClient, RpcCommunicator, toProtoRpcClient } from '@streamr/proto-rpc'
|
|
3
|
-
import { ConnectionType } from '../../connection/IConnection'
|
|
4
|
-
import { expectedConnectionType } from '../../helpers/Connectivity'
|
|
5
|
-
import { PeerDescriptor } from '../../../generated/packages/dht/protos/DhtRpc'
|
|
6
|
-
import { DhtRpcOptions } from '../../rpc-protocol/DhtRpcOptions'
|
|
7
|
-
import { DhtCallContext } from '../../rpc-protocol/DhtCallContext'
|
|
8
|
-
|
|
9
|
-
// Should connect directly to the server, timeout can be low
|
|
10
|
-
const WEBSOCKET_CLIENT_TIMEOUT = 5000
|
|
11
|
-
// Requires a WebsocketConnectionRequest to be routed to the client before the connection can be opened
|
|
12
|
-
// takes a little bit longer than WEBSOCKET_CLIENT
|
|
13
|
-
const WEBSOCKET_SERVER_TIMEOUT = 7500
|
|
14
|
-
// WebRTC connections require lots of signalling to open and might take a longer time.
|
|
15
|
-
const WEBRTC_TIMEOUT = 10000
|
|
16
|
-
// default timeout for existing connections
|
|
17
|
-
export const EXISTING_CONNECTION_TIMEOUT = 5000
|
|
18
|
-
|
|
19
|
-
const getTimeout = (localPeerDescriptor: PeerDescriptor, remotePeerDescriptor: PeerDescriptor): number => {
|
|
20
|
-
const connectionType = expectedConnectionType(localPeerDescriptor, remotePeerDescriptor)
|
|
21
|
-
if (connectionType === ConnectionType.WEBSOCKET_CLIENT) {
|
|
22
|
-
return WEBSOCKET_CLIENT_TIMEOUT
|
|
23
|
-
} else if (connectionType === ConnectionType.WEBSOCKET_SERVER) {
|
|
24
|
-
return WEBSOCKET_SERVER_TIMEOUT
|
|
25
|
-
} else if (connectionType === ConnectionType.WEBRTC) {
|
|
26
|
-
return WEBRTC_TIMEOUT
|
|
27
|
-
}
|
|
28
|
-
return WEBRTC_TIMEOUT
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export abstract class RpcRemote<T extends ServiceInfo & ClassType> {
|
|
32
|
-
|
|
33
|
-
private readonly localPeerDescriptor: PeerDescriptor
|
|
34
|
-
private readonly remotePeerDescriptor: PeerDescriptor
|
|
35
|
-
private readonly client: ProtoRpcClient<T>
|
|
36
|
-
private readonly timeout?: number
|
|
37
|
-
|
|
38
|
-
constructor(
|
|
39
|
-
localPeerDescriptor: PeerDescriptor,
|
|
40
|
-
remotePeerDescriptor: PeerDescriptor,
|
|
41
|
-
rpcCommunicator: RpcCommunicator<DhtCallContext>,
|
|
42
|
-
// eslint-disable-next-line @typescript-eslint/prefer-function-type
|
|
43
|
-
clientClass: { new (clientTransport: ClientTransport): T },
|
|
44
|
-
timeout?: number
|
|
45
|
-
) {
|
|
46
|
-
this.localPeerDescriptor = localPeerDescriptor
|
|
47
|
-
this.remotePeerDescriptor = remotePeerDescriptor
|
|
48
|
-
this.client = toProtoRpcClient(new clientClass(rpcCommunicator.getRpcClientTransport()))
|
|
49
|
-
this.timeout = timeout
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
getPeerDescriptor(): PeerDescriptor {
|
|
53
|
-
return this.remotePeerDescriptor
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
getLocalPeerDescriptor(): PeerDescriptor {
|
|
57
|
-
return this.localPeerDescriptor
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
getClient(): ProtoRpcClient<T> {
|
|
61
|
-
return this.client
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
formDhtRpcOptions(opts?: Omit<DhtRpcOptions, 'sourceDescriptor' | 'targetDescriptor'>): DhtRpcOptions {
|
|
65
|
-
return {
|
|
66
|
-
sourceDescriptor: this.localPeerDescriptor,
|
|
67
|
-
targetDescriptor: this.remotePeerDescriptor,
|
|
68
|
-
timeout: this.timeout ?? getTimeout(this.localPeerDescriptor, this.remotePeerDescriptor),
|
|
69
|
-
...opts
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import { Events } from './ContactList'
|
|
2
|
-
import { sortedIndexBy } from 'lodash'
|
|
3
|
-
import EventEmitter from 'eventemitter3'
|
|
4
|
-
import { getDistance } from '../PeerManager'
|
|
5
|
-
import { DhtAddress, toDhtAddressRaw } from '../../identifiers'
|
|
6
|
-
|
|
7
|
-
// add other getters in the future if needed
|
|
8
|
-
export type ReadonlySortedContactList<C extends { getNodeId: () => DhtAddress }> =
|
|
9
|
-
Pick<SortedContactList<C>, 'getClosestContacts' | 'getAllContactsInUndefinedOrder'>
|
|
10
|
-
|
|
11
|
-
export interface SortedContactListOptions {
|
|
12
|
-
referenceId: DhtAddress // all contacts in this list are in sorted by the distance to this ID
|
|
13
|
-
allowToContainReferenceId: boolean
|
|
14
|
-
maxSize?: number
|
|
15
|
-
// if set, the list can't contain any contacts which are futher away than this limit
|
|
16
|
-
nodeIdDistanceLimit?: DhtAddress
|
|
17
|
-
// if set, the list can't contain contacts with these ids
|
|
18
|
-
excludedNodeIds?: Set<DhtAddress>
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export class SortedContactList<C extends { getNodeId: () => DhtAddress }> extends EventEmitter<Events<C>> {
|
|
22
|
-
|
|
23
|
-
private options: SortedContactListOptions
|
|
24
|
-
private contactsById: Map<DhtAddress, C> = new Map()
|
|
25
|
-
private contactIds: DhtAddress[] = []
|
|
26
|
-
|
|
27
|
-
constructor(
|
|
28
|
-
options: SortedContactListOptions
|
|
29
|
-
) {
|
|
30
|
-
super()
|
|
31
|
-
this.options = options
|
|
32
|
-
this.compareIds = this.compareIds.bind(this)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
public getClosestContactId(): DhtAddress {
|
|
36
|
-
return this.contactIds[0]
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
public getContactIds(): DhtAddress[] {
|
|
40
|
-
return this.contactIds
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
public addContact(contact: C): void {
|
|
44
|
-
const contactId = contact.getNodeId()
|
|
45
|
-
if (this.options.excludedNodeIds !== undefined && this.options.excludedNodeIds.has(contactId)) {
|
|
46
|
-
return
|
|
47
|
-
}
|
|
48
|
-
if ((!this.options.allowToContainReferenceId && (this.options.referenceId === contactId)) ||
|
|
49
|
-
(this.options.nodeIdDistanceLimit !== undefined && this.compareIds(this.options.nodeIdDistanceLimit, contactId) < 0)) {
|
|
50
|
-
return
|
|
51
|
-
}
|
|
52
|
-
if (!this.contactsById.has(contactId)) {
|
|
53
|
-
if ((this.options.maxSize === undefined) || (this.contactIds.length < this.options.maxSize)) {
|
|
54
|
-
this.contactsById.set(contactId, contact)
|
|
55
|
-
const index = sortedIndexBy(this.contactIds, contactId, (id: DhtAddress) => { return this.distanceToReferenceId(id) })
|
|
56
|
-
this.contactIds.splice(index, 0, contactId)
|
|
57
|
-
if (this.hasEventListeners()) {
|
|
58
|
-
this.emit(
|
|
59
|
-
'contactAdded',
|
|
60
|
-
contact
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
} else if (this.compareIds(this.contactIds[this.options.maxSize - 1], contactId) > 0) {
|
|
64
|
-
const removedId = this.contactIds.pop()
|
|
65
|
-
const removedContact = this.contactsById.get(removedId!)!
|
|
66
|
-
this.contactsById.delete(removedId!)
|
|
67
|
-
this.contactsById.set(contactId, contact)
|
|
68
|
-
const index = sortedIndexBy(this.contactIds, contactId, (id: DhtAddress) => { return this.distanceToReferenceId(id) })
|
|
69
|
-
this.contactIds.splice(index, 0, contactId)
|
|
70
|
-
if (this.hasEventListeners()) {
|
|
71
|
-
this.emit(
|
|
72
|
-
'contactRemoved',
|
|
73
|
-
removedContact
|
|
74
|
-
)
|
|
75
|
-
this.emit(
|
|
76
|
-
'contactAdded',
|
|
77
|
-
contact
|
|
78
|
-
)
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
public addContacts(contacts: C[]): void {
|
|
85
|
-
contacts.forEach((contact) => this.addContact(contact))
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
public getContact(id: DhtAddress): C | undefined {
|
|
89
|
-
return this.contactsById.get(id)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
has(id: DhtAddress): boolean {
|
|
93
|
-
return this.contactsById.has(id)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/*
|
|
97
|
-
* Closest first then others in ascending distance order
|
|
98
|
-
*/
|
|
99
|
-
public getClosestContacts(limit?: number): C[] {
|
|
100
|
-
const limitedContactIds = (limit === undefined) ? this.contactIds : this.contactIds.slice(0, Math.max(limit, 0))
|
|
101
|
-
return limitedContactIds.map((nodeId) => this.contactsById.get(nodeId)!)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/*
|
|
105
|
-
* Furthest first then others in descending distance order
|
|
106
|
-
*/
|
|
107
|
-
getFurthestContacts(limit?: number): C[] {
|
|
108
|
-
const ret = [...this.getClosestContacts()].reverse()
|
|
109
|
-
return (limit === undefined)
|
|
110
|
-
? ret
|
|
111
|
-
: ret.slice(0, Math.max(limit, 0))
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
public compareIds(id1: DhtAddress, id2: DhtAddress): number {
|
|
115
|
-
const distance1 = this.distanceToReferenceId(id1)
|
|
116
|
-
const distance2 = this.distanceToReferenceId(id2)
|
|
117
|
-
return distance1 - distance2
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// TODO inline this method?
|
|
121
|
-
private distanceToReferenceId(id: DhtAddress): number {
|
|
122
|
-
// TODO maybe this class should store the referenceId also as DhtAddressRaw so that we don't need to convert it here?
|
|
123
|
-
return getDistance(toDhtAddressRaw(this.options.referenceId), toDhtAddressRaw(id))
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
public removeContact(id: DhtAddress): boolean {
|
|
127
|
-
if (this.contactsById.has(id)) {
|
|
128
|
-
const removed = this.contactsById.get(id)!
|
|
129
|
-
// TODO use sortedIndexBy?
|
|
130
|
-
const index = this.contactIds.findIndex((nodeId) => (nodeId === id))
|
|
131
|
-
this.contactIds.splice(index, 1)
|
|
132
|
-
this.contactsById.delete(id)
|
|
133
|
-
if (this.hasEventListeners()) {
|
|
134
|
-
this.emit(
|
|
135
|
-
'contactRemoved',
|
|
136
|
-
removed
|
|
137
|
-
)
|
|
138
|
-
}
|
|
139
|
-
return true
|
|
140
|
-
}
|
|
141
|
-
return false
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
public getAllContactsInUndefinedOrder(): Iterable<C> {
|
|
145
|
-
return this.contactsById.values()
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
public getSize(excludedNodeIds?: Set<DhtAddress>): number {
|
|
149
|
-
let excludedCount = 0
|
|
150
|
-
if (excludedNodeIds !== undefined) {
|
|
151
|
-
for (const nodeId of excludedNodeIds) {
|
|
152
|
-
if (this.has(nodeId)) {
|
|
153
|
-
excludedCount++
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return this.contactIds.length - excludedCount
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
public clear(): void {
|
|
161
|
-
this.contactsById.clear()
|
|
162
|
-
this.contactIds = []
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
public stop(): void {
|
|
166
|
-
this.removeAllListeners()
|
|
167
|
-
this.clear()
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
private hasEventListeners(): boolean {
|
|
171
|
-
return this.eventNames().length > 0
|
|
172
|
-
}
|
|
173
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { PeerDescriptor } from '../../exports'
|
|
2
|
-
import { DhtAddress } from '../../identifiers'
|
|
3
|
-
import { Contact } from './Contact'
|
|
4
|
-
import { SortedContactList } from './SortedContactList'
|
|
5
|
-
|
|
6
|
-
export const getClosestNodes = (
|
|
7
|
-
referenceId: DhtAddress,
|
|
8
|
-
contacts: Iterable<PeerDescriptor>,
|
|
9
|
-
opts?: {
|
|
10
|
-
maxCount?: number
|
|
11
|
-
excludedNodeIds?: Set<DhtAddress>
|
|
12
|
-
}
|
|
13
|
-
): PeerDescriptor[] => {
|
|
14
|
-
const list = new SortedContactList<Contact>({
|
|
15
|
-
referenceId,
|
|
16
|
-
allowToContainReferenceId: true,
|
|
17
|
-
excludedNodeIds: opts?.excludedNodeIds,
|
|
18
|
-
maxSize: opts?.maxCount
|
|
19
|
-
})
|
|
20
|
-
for (const contact of contacts) {
|
|
21
|
-
list.addContact(new Contact(contact))
|
|
22
|
-
}
|
|
23
|
-
return list.getClosestContacts().map((n) => n.getPeerDescriptor())
|
|
24
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { PeerDescriptor } from '../../../generated/packages/dht/protos/DhtRpc'
|
|
2
|
-
|
|
3
|
-
// Notice: you cannot convert RingId to RingIdRaw, because
|
|
4
|
-
// RingId is only an approximation of the actual value.
|
|
5
|
-
// That is why RingIdRaw is widely used in the codebase.
|
|
6
|
-
|
|
7
|
-
export type RingIdRaw = Uint8Array & { __ringIdRaw: never }
|
|
8
|
-
export type RingId = number & { __ringId: never }
|
|
9
|
-
export type RingDistance = number & { __ringDistance: never }
|
|
10
|
-
|
|
11
|
-
export const RING_SIZE = 2 ** 120 - 1 // 2^120 - 1
|
|
12
|
-
|
|
13
|
-
const binaryToBigInt = (binary: Uint8Array): bigint => {
|
|
14
|
-
return binary.reduce((acc, val) => (acc << BigInt(8)) | BigInt(val), BigInt(0))
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const getRingIdFromRaw = (raw: RingIdRaw): RingId => Number(binaryToBigInt(raw)) as RingId
|
|
18
|
-
|
|
19
|
-
export const getRingIdRawFromPeerDescriptor = (peerDescriptor: PeerDescriptor): RingIdRaw => {
|
|
20
|
-
const regionAsBuffer = Buffer.alloc(4)
|
|
21
|
-
regionAsBuffer.writeUInt32BE(peerDescriptor.region ?? 0, 0)
|
|
22
|
-
const ipAsbuffer = Buffer.alloc(4)
|
|
23
|
-
ipAsbuffer.writeUInt32BE(peerDescriptor.ipAddress ?? 0, 0)
|
|
24
|
-
|
|
25
|
-
const uniquePartAsBuffer = Buffer.from(peerDescriptor.nodeId.subarray(peerDescriptor.nodeId.length - 7, peerDescriptor.nodeId.length))
|
|
26
|
-
|
|
27
|
-
const arr = [
|
|
28
|
-
regionAsBuffer,
|
|
29
|
-
ipAsbuffer,
|
|
30
|
-
uniquePartAsBuffer
|
|
31
|
-
]
|
|
32
|
-
|
|
33
|
-
const buffer = Buffer.concat(arr)
|
|
34
|
-
return new Uint8Array(buffer) as RingIdRaw
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export const getRingIdFromPeerDescriptor = (peerDescriptor: PeerDescriptor): RingId => {
|
|
38
|
-
const raw = getRingIdRawFromPeerDescriptor(peerDescriptor)
|
|
39
|
-
return Number(binaryToBigInt(raw)) as RingId
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const getLeftDistance = (referenceId: RingId, id: RingId): RingDistance =>{
|
|
43
|
-
const diff = Math.abs(referenceId - id)
|
|
44
|
-
if (referenceId > id) {
|
|
45
|
-
// if id is smaller than referenceId, then the distance is the difference
|
|
46
|
-
return diff as RingDistance
|
|
47
|
-
} else {
|
|
48
|
-
// if id is bigger than referenceId, then the distance is the ringSize - difference
|
|
49
|
-
return RING_SIZE - diff as RingDistance
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export const getRightDistance = (referenceId: RingId, id: RingId): RingDistance => {
|
|
54
|
-
const diff = Math.abs(referenceId - id)
|
|
55
|
-
if (referenceId > id) {
|
|
56
|
-
// if id is smaller than referenceId, then the distance is the ringSize - difference
|
|
57
|
-
return RING_SIZE - diff as RingDistance
|
|
58
|
-
} else {
|
|
59
|
-
// if id is bigger than referenceId, then the distance is the difference
|
|
60
|
-
return diff as RingDistance
|
|
61
|
-
}
|
|
62
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { Gate, Logger, withTimeout } from '@streamr/utils'
|
|
2
|
-
import { v4 } from 'uuid'
|
|
3
|
-
import { DhtAddress, toNodeId, toDhtAddressRaw } from '../../identifiers'
|
|
4
|
-
import { PeerDescriptor } from '../../../generated/packages/dht/protos/DhtRpc'
|
|
5
|
-
import { DhtNodeRpcRemote } from '../DhtNodeRpcRemote'
|
|
6
|
-
import { PeerManager, getDistance } from '../PeerManager'
|
|
7
|
-
import { getClosestNodes } from '../contact/getClosestNodes'
|
|
8
|
-
|
|
9
|
-
const logger = new Logger(module)
|
|
10
|
-
|
|
11
|
-
interface DiscoverySessionOptions {
|
|
12
|
-
targetId: DhtAddress
|
|
13
|
-
parallelism: number
|
|
14
|
-
noProgressLimit: number
|
|
15
|
-
peerManager: PeerManager
|
|
16
|
-
// Note that contacted peers will be mutated by the DiscoverySession or other parallel sessions
|
|
17
|
-
contactedPeers: Set<DhtAddress>
|
|
18
|
-
abortSignal: AbortSignal
|
|
19
|
-
createDhtNodeRpcRemote: (peerDescriptor: PeerDescriptor) => DhtNodeRpcRemote
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export class DiscoverySession {
|
|
23
|
-
|
|
24
|
-
public readonly id = v4()
|
|
25
|
-
private noProgressCounter = 0
|
|
26
|
-
private ongoingRequests: Set<DhtAddress> = new Set()
|
|
27
|
-
private doneGate = new Gate(false)
|
|
28
|
-
private readonly options: DiscoverySessionOptions
|
|
29
|
-
|
|
30
|
-
constructor(options: DiscoverySessionOptions) {
|
|
31
|
-
this.options = options
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
private addContacts(contacts: PeerDescriptor[]): void {
|
|
35
|
-
if (this.options.abortSignal.aborted || this.doneGate.isOpen()) {
|
|
36
|
-
return
|
|
37
|
-
}
|
|
38
|
-
for (const contact of contacts) {
|
|
39
|
-
this.options.peerManager.addContact(contact)
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
private async fetchClosestNeighborsFromRemote(peerDescriptor: PeerDescriptor): Promise<PeerDescriptor[]> {
|
|
44
|
-
if (this.options.abortSignal.aborted || this.doneGate.isOpen()) {
|
|
45
|
-
return []
|
|
46
|
-
}
|
|
47
|
-
const nodeId = toNodeId(peerDescriptor)
|
|
48
|
-
logger.trace(`Getting closest neighbors from remote: ${nodeId}`)
|
|
49
|
-
this.options.contactedPeers.add(nodeId)
|
|
50
|
-
const remote = this.options.createDhtNodeRpcRemote(peerDescriptor)
|
|
51
|
-
const returnedContacts = await remote.getClosestPeers(this.options.targetId)
|
|
52
|
-
this.options.peerManager.setContactActive(nodeId)
|
|
53
|
-
return returnedContacts
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
private onRequestSucceeded(nodeId: DhtAddress, contacts: PeerDescriptor[]) {
|
|
57
|
-
if (!this.ongoingRequests.has(nodeId)) {
|
|
58
|
-
return
|
|
59
|
-
}
|
|
60
|
-
this.ongoingRequests.delete(nodeId)
|
|
61
|
-
const targetId = toDhtAddressRaw(this.options.targetId)
|
|
62
|
-
const oldClosestNeighbor = this.getClosestNeighbor()
|
|
63
|
-
const oldClosestDistance = getDistance(targetId, oldClosestNeighbor.nodeId)
|
|
64
|
-
this.addContacts(contacts)
|
|
65
|
-
const newClosestNeighbor = this.getClosestNeighbor()
|
|
66
|
-
const newClosestDistance = getDistance(targetId, newClosestNeighbor.nodeId)
|
|
67
|
-
if (newClosestDistance >= oldClosestDistance) {
|
|
68
|
-
this.noProgressCounter++
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
private getClosestNeighbor(): PeerDescriptor {
|
|
73
|
-
return getClosestNodes(
|
|
74
|
-
this.options.targetId,
|
|
75
|
-
this.options.peerManager.getNeighbors().map((n) => n.getPeerDescriptor()),
|
|
76
|
-
{ maxCount: 1 }
|
|
77
|
-
)[0]
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
private onRequestFailed(nodeId: DhtAddress) {
|
|
81
|
-
if (!this.ongoingRequests.has(nodeId)) {
|
|
82
|
-
return
|
|
83
|
-
}
|
|
84
|
-
this.ongoingRequests.delete(nodeId)
|
|
85
|
-
this.options.peerManager.removeContact(nodeId)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
private findMoreContacts(): void {
|
|
89
|
-
if (this.options.abortSignal.aborted || this.doneGate.isOpen()) {
|
|
90
|
-
return
|
|
91
|
-
}
|
|
92
|
-
const uncontacted = getClosestNodes(
|
|
93
|
-
this.options.targetId,
|
|
94
|
-
Array.from(this.options.peerManager.getNearbyContacts().getAllContactsInUndefinedOrder(), (c) => c.getPeerDescriptor()),
|
|
95
|
-
{
|
|
96
|
-
maxCount: this.options.parallelism,
|
|
97
|
-
excludedNodeIds: this.options.contactedPeers
|
|
98
|
-
}
|
|
99
|
-
)
|
|
100
|
-
if ((uncontacted.length === 0 && this.ongoingRequests.size === 0) || (this.noProgressCounter >= this.options.noProgressLimit)) {
|
|
101
|
-
this.doneGate.open()
|
|
102
|
-
return
|
|
103
|
-
}
|
|
104
|
-
for (const node of uncontacted) {
|
|
105
|
-
if (this.ongoingRequests.size >= this.options.parallelism) {
|
|
106
|
-
break
|
|
107
|
-
}
|
|
108
|
-
const nodeId = toNodeId(node)
|
|
109
|
-
this.ongoingRequests.add(nodeId)
|
|
110
|
-
// eslint-disable-next-line promise/catch-or-return
|
|
111
|
-
this.fetchClosestNeighborsFromRemote(node)
|
|
112
|
-
.then((contacts) => this.onRequestSucceeded(nodeId, contacts))
|
|
113
|
-
.catch(() => this.onRequestFailed(nodeId))
|
|
114
|
-
.finally(() => {
|
|
115
|
-
this.findMoreContacts()
|
|
116
|
-
})
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
public async findClosestNodes(timeout: number): Promise<void> {
|
|
121
|
-
if (this.options.peerManager.getNearbyContactCount(this.options.contactedPeers) === 0) {
|
|
122
|
-
return
|
|
123
|
-
}
|
|
124
|
-
setImmediate(() => {
|
|
125
|
-
this.findMoreContacts()
|
|
126
|
-
})
|
|
127
|
-
await withTimeout(this.doneGate.waitUntilOpen(), timeout, 'discovery session timed out', this.options.abortSignal)
|
|
128
|
-
}
|
|
129
|
-
}
|