@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.
- package/README.md +1 -1
- package/dist/package.json +12 -8
- package/dist/src/connection/ConnectionLockRpcLocal.d.ts +1 -1
- package/dist/src/connection/ConnectionLockRpcRemote.d.ts +1 -1
- package/dist/src/connection/ConnectionLockRpcRemote.js +1 -1
- package/dist/src/connection/ConnectionLockRpcRemote.js.map +1 -1
- package/dist/src/connection/{ConnectionLockHandler.d.ts → ConnectionLockStates.d.ts} +3 -3
- package/dist/src/connection/{ConnectionLockHandler.js → ConnectionLockStates.js} +17 -9
- package/dist/src/connection/ConnectionLockStates.js.map +1 -0
- package/dist/src/connection/ConnectionManager.d.ts +9 -7
- package/dist/src/connection/ConnectionManager.js +16 -18
- package/dist/src/connection/ConnectionManager.js.map +1 -1
- package/dist/src/connection/ConnectorFacade.js +1 -1
- package/dist/src/connection/ConnectorFacade.js.map +1 -1
- package/dist/src/connection/Handshaker.js +6 -13
- package/dist/src/connection/Handshaker.js.map +1 -1
- package/dist/src/connection/ManagedConnection.d.ts +2 -2
- package/dist/src/connection/ManagedConnection.js +8 -8
- package/dist/src/connection/ManagedConnection.js.map +1 -1
- package/dist/src/connection/connectivityChecker.d.ts +1 -1
- package/dist/src/connection/connectivityChecker.js +8 -8
- package/dist/src/connection/connectivityChecker.js.map +1 -1
- package/dist/src/connection/connectivityRequestHandler.d.ts +2 -2
- package/dist/src/connection/connectivityRequestHandler.js +10 -11
- package/dist/src/connection/connectivityRequestHandler.js.map +1 -1
- package/dist/src/connection/webrtc/WebrtcConnector.d.ts +1 -0
- package/dist/src/connection/webrtc/WebrtcConnector.js +13 -8
- package/dist/src/connection/webrtc/WebrtcConnector.js.map +1 -1
- package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.d.ts +2 -0
- package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js +4 -6
- package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js.map +1 -1
- package/dist/src/connection/websocket/AbstractWebsocketClientConnection.d.ts +28 -0
- package/dist/src/connection/websocket/{ClientWebsocket.js → AbstractWebsocketClientConnection.js} +42 -68
- package/dist/src/connection/websocket/AbstractWebsocketClientConnection.js.map +1 -0
- package/dist/src/connection/websocket/NodeWebsocketClientConnection.d.ts +7 -0
- package/dist/src/connection/websocket/NodeWebsocketClientConnection.js +39 -0
- package/dist/src/connection/websocket/NodeWebsocketClientConnection.js.map +1 -0
- package/dist/src/connection/websocket/WebsocketConnector.js +26 -23
- package/dist/src/connection/websocket/WebsocketConnector.js.map +1 -1
- package/dist/src/connection/websocket/WebsocketServer.js +25 -35
- package/dist/src/connection/websocket/WebsocketServer.js.map +1 -1
- package/dist/src/connection/websocket/{ServerWebsocket.d.ts → WebsocketServerConnection.d.ts} +4 -5
- package/dist/src/connection/websocket/{ServerWebsocket.js → WebsocketServerConnection.js} +18 -51
- package/dist/src/connection/websocket/WebsocketServerConnection.js.map +1 -0
- package/dist/src/dht/DhtNode.d.ts +15 -8
- package/dist/src/dht/DhtNode.js +62 -31
- package/dist/src/dht/DhtNode.js.map +1 -1
- package/dist/src/dht/DhtNodeRpcLocal.d.ts +5 -1
- package/dist/src/dht/DhtNodeRpcLocal.js +10 -0
- package/dist/src/dht/DhtNodeRpcLocal.js.map +1 -1
- package/dist/src/dht/DhtNodeRpcRemote.d.ts +3 -0
- package/dist/src/dht/DhtNodeRpcRemote.js +16 -1
- package/dist/src/dht/DhtNodeRpcRemote.js.map +1 -1
- package/dist/src/dht/ExternalApiRpcLocal.d.ts +2 -2
- package/dist/src/dht/ExternalApiRpcLocal.js +3 -3
- package/dist/src/dht/ExternalApiRpcLocal.js.map +1 -1
- package/dist/src/dht/ExternalApiRpcRemote.d.ts +1 -1
- package/dist/src/dht/ExternalApiRpcRemote.js +2 -2
- package/dist/src/dht/ExternalApiRpcRemote.js.map +1 -1
- package/dist/src/dht/PeerManager.d.ts +15 -3
- package/dist/src/dht/PeerManager.js +54 -40
- package/dist/src/dht/PeerManager.js.map +1 -1
- package/dist/src/dht/contact/RingContactList.d.ts +31 -0
- package/dist/src/dht/contact/RingContactList.js +133 -0
- package/dist/src/dht/contact/RingContactList.js.map +1 -0
- package/dist/src/dht/contact/SortedContactList.d.ts +2 -1
- package/dist/src/dht/contact/SortedContactList.js +19 -17
- package/dist/src/dht/contact/SortedContactList.js.map +1 -1
- package/dist/src/dht/contact/ringIdentifiers.d.ts +16 -0
- package/dist/src/dht/contact/ringIdentifiers.js +54 -0
- package/dist/src/dht/contact/ringIdentifiers.js.map +1 -0
- package/dist/src/dht/discovery/DiscoverySession.js +3 -1
- package/dist/src/dht/discovery/DiscoverySession.js.map +1 -1
- package/dist/src/dht/discovery/PeerDiscovery.d.ts +6 -2
- package/dist/src/dht/discovery/PeerDiscovery.js +41 -4
- package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
- package/dist/src/dht/discovery/RingDiscoverySession.d.ts +29 -0
- package/dist/src/dht/discovery/RingDiscoverySession.js +125 -0
- package/dist/src/dht/discovery/RingDiscoverySession.js.map +1 -0
- package/dist/src/dht/recursive-operation/RecursiveOperationManager.js +1 -1
- package/dist/src/dht/recursive-operation/RecursiveOperationManager.js.map +1 -1
- package/dist/src/dht/recursive-operation/RecursiveOperationRpcRemote.js +1 -1
- package/dist/src/dht/recursive-operation/RecursiveOperationRpcRemote.js.map +1 -1
- package/dist/src/dht/recursive-operation/RecursiveOperationSession.js +0 -1
- package/dist/src/dht/recursive-operation/RecursiveOperationSession.js.map +1 -1
- package/dist/src/dht/routing/Router.d.ts +0 -1
- package/dist/src/dht/routing/Router.js +0 -1
- package/dist/src/dht/routing/Router.js.map +1 -1
- package/dist/src/dht/routing/RouterRpcLocal.d.ts +0 -1
- package/dist/src/dht/routing/RouterRpcLocal.js.map +1 -1
- package/dist/src/dht/routing/RouterRpcRemote.js +2 -2
- package/dist/src/dht/routing/RouterRpcRemote.js.map +1 -1
- package/dist/src/dht/routing/RoutingSession.js +2 -2
- package/dist/src/dht/routing/RoutingSession.js.map +1 -1
- package/dist/src/dht/store/LocalDataStore.js +2 -2
- package/dist/src/dht/store/LocalDataStore.js.map +1 -1
- package/dist/src/dht/store/StoreManager.js +2 -2
- package/dist/src/dht/store/StoreManager.js.map +1 -1
- package/dist/src/exports.d.ts +3 -2
- package/dist/src/exports.js +3 -3
- package/dist/src/exports.js.map +1 -1
- package/dist/src/helpers/createPeerDescriptor.d.ts +1 -1
- package/dist/src/helpers/createPeerDescriptor.js +2 -1
- package/dist/src/helpers/createPeerDescriptor.js.map +1 -1
- package/dist/src/helpers/version.d.ts +6 -0
- package/dist/src/helpers/version.js +38 -0
- package/dist/src/helpers/version.js.map +1 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.d.ts +16 -6
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.js +11 -4
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.js.map +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +98 -87
- package/dist/src/proto/packages/dht/protos/DhtRpc.js +45 -49
- package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.server.d.ts +10 -4
- package/dist/src/transport/RoutingRpcCommunicator.js +0 -2
- package/dist/src/transport/RoutingRpcCommunicator.js.map +1 -1
- package/karma.config.js +4 -1
- package/package.json +12 -8
- package/protos/DhtRpc.proto +21 -21
- package/src/connection/ConnectionLockRpcLocal.ts +1 -1
- package/src/connection/ConnectionLockRpcRemote.ts +2 -2
- package/src/connection/{ConnectionLockHandler.ts → ConnectionLockStates.ts} +14 -6
- package/src/connection/ConnectionManager.ts +21 -22
- package/src/connection/ConnectorFacade.ts +1 -2
- package/src/connection/Handshaker.ts +7 -15
- package/src/connection/ManagedConnection.ts +8 -8
- package/src/connection/connectivityChecker.ts +9 -10
- package/src/connection/connectivityRequestHandler.ts +16 -16
- package/src/connection/webrtc/BrowserWebrtcConnection.ts +18 -0
- package/src/connection/webrtc/NodeWebrtcConnection.ts +1 -1
- package/src/connection/webrtc/WebrtcConnector.ts +14 -8
- package/src/connection/webrtc/WebrtcConnectorRpcLocal.ts +5 -5
- package/src/connection/websocket/{ClientWebsocket.ts → AbstractWebsocketClientConnection.ts} +57 -70
- package/src/connection/websocket/BrowserWebsocketClientConnection.ts +44 -0
- package/src/connection/websocket/NodeWebsocketClientConnection.ts +39 -0
- package/src/connection/websocket/WebsocketConnector.ts +27 -28
- package/src/connection/websocket/WebsocketServer.ts +27 -42
- package/src/connection/websocket/{ServerWebsocket.ts → WebsocketServerConnection.ts} +15 -56
- package/src/dht/DhtNode.ts +85 -50
- package/src/dht/DhtNodeRpcLocal.ts +16 -0
- package/src/dht/DhtNodeRpcRemote.ts +19 -1
- package/src/dht/ExternalApiRpcLocal.ts +5 -5
- package/src/dht/ExternalApiRpcRemote.ts +4 -4
- package/src/dht/PeerManager.ts +70 -44
- package/src/dht/contact/RingContactList.ts +151 -0
- package/src/dht/contact/SortedContactList.ts +22 -18
- package/src/dht/contact/ringIdentifiers.ts +62 -0
- package/src/dht/discovery/DiscoverySession.ts +3 -1
- package/src/dht/discovery/PeerDiscovery.ts +45 -6
- package/src/dht/discovery/RingDiscoverySession.ts +162 -0
- package/src/dht/recursive-operation/RecursiveOperationManager.ts +1 -1
- package/src/dht/recursive-operation/RecursiveOperationRpcRemote.ts +1 -1
- package/src/dht/recursive-operation/RecursiveOperationSession.ts +1 -3
- package/src/dht/routing/Router.ts +0 -2
- package/src/dht/routing/RouterRpcLocal.ts +0 -1
- package/src/dht/routing/RouterRpcRemote.ts +2 -2
- package/src/dht/routing/RoutingSession.ts +2 -2
- package/src/dht/store/LocalDataStore.ts +1 -1
- package/src/dht/store/StoreManager.ts +2 -2
- package/src/exports.ts +3 -2
- package/src/helpers/createPeerDescriptor.ts +2 -1
- package/src/helpers/version.ts +32 -0
- package/src/proto/packages/dht/protos/DhtRpc.client.ts +22 -9
- package/src/proto/packages/dht/protos/DhtRpc.server.ts +10 -4
- package/src/proto/packages/dht/protos/DhtRpc.ts +122 -100
- package/src/transport/RoutingRpcCommunicator.ts +1 -2
- package/test/benchmark/Find.test.ts +3 -4
- package/test/benchmark/KademliaCorrectness.test.ts +14 -8
- package/test/benchmark/RingCorrectness.test.ts +157 -0
- package/test/benchmark/WebsocketServerMemoryLeak.test.ts +2 -2
- package/test/benchmark/hybrid-network-simulation/RingContactList.test.ts +72 -0
- package/test/data/generateGroundTruthData.ts +2 -2
- package/test/end-to-end/memory-leak.test.ts +1 -2
- package/test/integration/ConnectionManager.test.ts +28 -10
- package/test/integration/ConnectivityChecking.test.ts +3 -15
- package/test/integration/DhtNodeExternalAPI.test.ts +6 -6
- package/test/integration/Find.test.ts +6 -6
- package/test/integration/Layer1-scale.test.ts +0 -1
- package/test/integration/ReplicateData.test.ts +4 -4
- package/test/integration/RouteMessage.test.ts +1 -6
- package/test/integration/RouterRpcRemote.test.ts +1 -3
- package/test/integration/SimultaneousConnections.test.ts +9 -10
- package/test/integration/Store.test.ts +4 -4
- package/test/integration/StoreAndDelete.test.ts +5 -5
- package/test/integration/StoreOnDhtWithThreeNodes.test.ts +5 -5
- package/test/integration/StoreOnDhtWithTwoNodes.test.ts +3 -3
- package/test/integration/WebrtcConnectionManagement.test.ts +3 -9
- package/test/integration/Websocket.test.ts +2 -2
- package/test/integration/WebsocketConnectionManagement.test.ts +1 -6
- package/test/integration/rpc-connections-over-webrpc.test.ts +1 -2
- package/test/unit/PeerManager.test.ts +44 -10
- package/test/unit/RecursiveOperationManager.test.ts +14 -8
- package/test/unit/RecursiveOperationSession.test.ts +1 -1
- package/test/unit/Router.test.ts +0 -3
- package/test/unit/RoutingSession.test.ts +1 -2
- package/test/unit/connectivityRequestHandler.test.ts +5 -9
- package/test/unit/createPeerDescriptor.test.ts +12 -6
- package/test/unit/version.test.ts +18 -0
- package/test/utils/utils.ts +60 -47
- package/tsconfig.browser.json +2 -1
- package/tsconfig.jest.json +4 -2
- package/tsconfig.node.json +4 -2
- package/dist/src/connection/ConnectionLockHandler.js.map +0 -1
- package/dist/src/connection/websocket/ClientWebsocket.d.ts +0 -17
- package/dist/src/connection/websocket/ClientWebsocket.js.map +0 -1
- package/dist/src/connection/websocket/ServerWebsocket.js.map +0 -1
- package/dist/src/helpers/MapWithTtl.d.ts +0 -14
- package/dist/src/helpers/MapWithTtl.js +0 -60
- package/dist/src/helpers/MapWithTtl.js.map +0 -1
- package/dist/src/helpers/versionCompatibility.d.ts +0 -2
- package/dist/src/helpers/versionCompatibility.js +0 -18
- package/dist/src/helpers/versionCompatibility.js.map +0 -1
- package/src/helpers/MapWithTtl.ts +0 -71
- package/src/helpers/versionCompatibility.ts +0 -13
- package/test/unit/versionCompatibility.test.ts +0 -16
package/src/dht/PeerManager.ts
CHANGED
|
@@ -8,9 +8,12 @@ import {
|
|
|
8
8
|
import { DhtNodeRpcRemote } from './DhtNodeRpcRemote'
|
|
9
9
|
import { RandomContactList } from './contact/RandomContactList'
|
|
10
10
|
import { SortedContactList } from './contact/SortedContactList'
|
|
11
|
-
import {
|
|
11
|
+
import { ConnectionLocker } from '../connection/ConnectionManager'
|
|
12
12
|
import EventEmitter from 'eventemitter3'
|
|
13
13
|
import { DhtAddress, DhtAddressRaw, getNodeIdFromPeerDescriptor, getRawFromDhtAddress } from '../identifiers'
|
|
14
|
+
import { RingContactList, RingContacts } from './contact/RingContactList'
|
|
15
|
+
import { RingIdRaw, getRingIdRawFromPeerDescriptor } from './contact/ringIdentifiers'
|
|
16
|
+
import { LockID } from '../connection/ConnectionLockStates'
|
|
14
17
|
|
|
15
18
|
const logger = new Logger(module)
|
|
16
19
|
|
|
@@ -19,8 +22,10 @@ interface PeerManagerConfig {
|
|
|
19
22
|
maxContactListSize: number
|
|
20
23
|
peerDiscoveryQueryBatchSize: number
|
|
21
24
|
localNodeId: DhtAddress
|
|
22
|
-
|
|
25
|
+
localPeerDescriptor: PeerDescriptor
|
|
26
|
+
connectionLocker?: ConnectionLocker
|
|
23
27
|
isLayer0: boolean
|
|
28
|
+
lockId: LockID
|
|
24
29
|
createDhtNodeRpcRemote: (peerDescriptor: PeerDescriptor) => DhtNodeRpcRemote
|
|
25
30
|
}
|
|
26
31
|
|
|
@@ -29,6 +34,8 @@ export interface PeerManagerEvents {
|
|
|
29
34
|
contactRemoved: (peerDescriptor: PeerDescriptor, closestPeers: PeerDescriptor[]) => void
|
|
30
35
|
randomContactAdded: (peerDescriptor: PeerDescriptor, closestPeers: PeerDescriptor[]) => void
|
|
31
36
|
randomContactRemoved: (peerDescriptor: PeerDescriptor, closestPeers: PeerDescriptor[]) => void
|
|
37
|
+
ringContactAdded: (peerDescriptor: PeerDescriptor, closestPeers: RingContacts) => void
|
|
38
|
+
ringContactRemoved: (peerDescriptor: PeerDescriptor, closestPeers: RingContacts) => void
|
|
32
39
|
kBucketEmpty: () => void
|
|
33
40
|
}
|
|
34
41
|
|
|
@@ -51,6 +58,7 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
51
58
|
// All nodes that we know about
|
|
52
59
|
private contacts: SortedContactList<DhtNodeRpcRemote>
|
|
53
60
|
private randomPeers: RandomContactList<DhtNodeRpcRemote>
|
|
61
|
+
private ringContacts: RingContactList<DhtNodeRpcRemote>
|
|
54
62
|
private stopped: boolean = false
|
|
55
63
|
private readonly config: PeerManagerConfig
|
|
56
64
|
|
|
@@ -62,6 +70,13 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
62
70
|
numberOfNodesPerKBucket: this.config.numberOfNodesPerKBucket,
|
|
63
71
|
numberOfNodesToPing: this.config.numberOfNodesPerKBucket
|
|
64
72
|
})
|
|
73
|
+
this.ringContacts = new RingContactList<DhtNodeRpcRemote>(getRingIdRawFromPeerDescriptor(this.config.localPeerDescriptor), true)
|
|
74
|
+
this.ringContacts.on('ringContactAdded', (peerDescriptor: PeerDescriptor, closestPeers: RingContacts) => {
|
|
75
|
+
this.emit('ringContactAdded', peerDescriptor, closestPeers)
|
|
76
|
+
})
|
|
77
|
+
this.ringContacts.on('ringContactRemoved', (peerDescriptor: PeerDescriptor, closestPeers: RingContacts) => {
|
|
78
|
+
this.emit('ringContactRemoved', peerDescriptor, closestPeers)
|
|
79
|
+
})
|
|
65
80
|
this.bucket.on('ping', (oldContacts: DhtNodeRpcRemote[], newContact: DhtNodeRpcRemote) => this.onKBucketPing(oldContacts, newContact))
|
|
66
81
|
this.bucket.on('removed', (contact: DhtNodeRpcRemote) => this.onKBucketRemoved(getNodeIdFromPeerDescriptor(contact.getPeerDescriptor())))
|
|
67
82
|
this.bucket.on('added', (contact: DhtNodeRpcRemote) => this.onKBucketAdded(contact))
|
|
@@ -69,7 +84,7 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
69
84
|
// TODO: Update contact info to the connection manager and reconnect
|
|
70
85
|
})
|
|
71
86
|
this.contacts = new SortedContactList({
|
|
72
|
-
referenceId: this.config.localNodeId,
|
|
87
|
+
referenceId: this.config.localNodeId,
|
|
73
88
|
maxSize: this.config.maxContactListSize,
|
|
74
89
|
allowToContainReferenceId: false,
|
|
75
90
|
emitEvents: true
|
|
@@ -98,7 +113,7 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
98
113
|
return
|
|
99
114
|
}
|
|
100
115
|
const sortingList: SortedContactList<DhtNodeRpcRemote> = new SortedContactList({
|
|
101
|
-
referenceId: this.config.localNodeId,
|
|
116
|
+
referenceId: this.config.localNodeId,
|
|
102
117
|
maxSize: 100, // TODO use config option or named constant?
|
|
103
118
|
allowToContainReferenceId: false,
|
|
104
119
|
emitEvents: false
|
|
@@ -106,7 +121,7 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
106
121
|
sortingList.addContacts(oldContacts)
|
|
107
122
|
const sortedContacts = sortingList.getAllContacts()
|
|
108
123
|
const removableNodeId = sortedContacts[sortedContacts.length - 1].getNodeId()
|
|
109
|
-
this.config.
|
|
124
|
+
this.config.connectionLocker?.weakUnlockConnection(removableNodeId, this.config.lockId)
|
|
110
125
|
this.bucket.remove(getRawFromDhtAddress(removableNodeId))
|
|
111
126
|
this.bucket.add(newContact)
|
|
112
127
|
}
|
|
@@ -115,7 +130,7 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
115
130
|
if (this.stopped) {
|
|
116
131
|
return
|
|
117
132
|
}
|
|
118
|
-
this.config.
|
|
133
|
+
this.config.connectionLocker?.weakUnlockConnection(nodeId, this.config.lockId)
|
|
119
134
|
logger.trace(`Removed contact ${nodeId}`)
|
|
120
135
|
if (this.bucket.count() === 0) {
|
|
121
136
|
this.emit('kBucketEmpty')
|
|
@@ -130,7 +145,7 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
130
145
|
const peerDescriptor = contact.getPeerDescriptor()
|
|
131
146
|
const nodeId = getNodeIdFromPeerDescriptor(peerDescriptor)
|
|
132
147
|
// Important to lock here, before the ping result is known
|
|
133
|
-
this.config.
|
|
148
|
+
this.config.connectionLocker?.weakLockConnection(nodeId, this.config.lockId)
|
|
134
149
|
if (this.connections.has(contact.getNodeId())) {
|
|
135
150
|
logger.trace(`Added new contact ${nodeId}`)
|
|
136
151
|
} else { // open connection by pinging
|
|
@@ -140,13 +155,13 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
140
155
|
logger.trace(`Added new contact ${nodeId}`)
|
|
141
156
|
} else {
|
|
142
157
|
logger.trace('ping failed ' + nodeId)
|
|
143
|
-
this.config.
|
|
158
|
+
this.config.connectionLocker?.weakUnlockConnection(nodeId, this.config.lockId)
|
|
144
159
|
this.removeContact(nodeId)
|
|
145
160
|
this.addClosestContactToBucket()
|
|
146
161
|
}
|
|
147
162
|
return
|
|
148
163
|
}).catch((_e) => {
|
|
149
|
-
this.config.
|
|
164
|
+
this.config.connectionLocker?.weakUnlockConnection(nodeId, this.config.lockId)
|
|
150
165
|
this.removeContact(nodeId)
|
|
151
166
|
this.addClosestContactToBucket()
|
|
152
167
|
})
|
|
@@ -160,7 +175,7 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
160
175
|
}
|
|
161
176
|
const closest = this.getClosestActiveContactNotInBucket()
|
|
162
177
|
if (closest) {
|
|
163
|
-
this.addContact(
|
|
178
|
+
this.addContact(closest.getPeerDescriptor())
|
|
164
179
|
}
|
|
165
180
|
}
|
|
166
181
|
|
|
@@ -207,6 +222,7 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
207
222
|
return
|
|
208
223
|
}
|
|
209
224
|
logger.trace(`Removing contact ${nodeId}`)
|
|
225
|
+
this.ringContacts.removeContact(this.contacts.getContact(nodeId)?.contact)
|
|
210
226
|
this.bucket.remove(getRawFromDhtAddress(nodeId))
|
|
211
227
|
this.contacts.removeContact(nodeId)
|
|
212
228
|
this.randomPeers.removeContact(nodeId)
|
|
@@ -219,6 +235,10 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
219
235
|
this.bucket.remove(rpcRemote.id)
|
|
220
236
|
})
|
|
221
237
|
this.bucket.removeAllListeners()
|
|
238
|
+
this.ringContacts.getAllContacts().forEach((rpcRemote) => {
|
|
239
|
+
rpcRemote.leaveNotice()
|
|
240
|
+
this.ringContacts.removeContact(rpcRemote)
|
|
241
|
+
})
|
|
222
242
|
this.contacts.stop()
|
|
223
243
|
this.randomPeers.stop()
|
|
224
244
|
this.connections.clear()
|
|
@@ -229,10 +249,11 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
229
249
|
referenceId,
|
|
230
250
|
allowToContainReferenceId: true,
|
|
231
251
|
emitEvents: false,
|
|
232
|
-
excludedNodeIds
|
|
233
|
-
|
|
252
|
+
excludedNodeIds,
|
|
253
|
+
maxSize: limit
|
|
254
|
+
})
|
|
234
255
|
this.bucket.toArray().forEach((contact) => closest.addContact(contact))
|
|
235
|
-
return closest.
|
|
256
|
+
return closest.getAllContacts()
|
|
236
257
|
}
|
|
237
258
|
|
|
238
259
|
// TODO reduce copy-paste?
|
|
@@ -241,21 +262,26 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
241
262
|
referenceId,
|
|
242
263
|
allowToContainReferenceId: true,
|
|
243
264
|
emitEvents: false,
|
|
244
|
-
excludedNodeIds
|
|
265
|
+
excludedNodeIds,
|
|
266
|
+
maxSize: limit
|
|
245
267
|
})
|
|
246
268
|
this.contacts.getAllContacts().map((contact) => closest.addContact(contact))
|
|
247
|
-
|
|
248
|
-
|
|
269
|
+
return closest.getAllContacts()
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
getClosestRingContactsTo(
|
|
273
|
+
ringIdRaw: RingIdRaw,
|
|
274
|
+
limit?: number,
|
|
275
|
+
excludedIds?: Set<DhtAddress>
|
|
276
|
+
): { left: DhtNodeRpcRemote[], right: DhtNodeRpcRemote[] } {
|
|
277
|
+
const closest = new RingContactList<DhtNodeRpcRemote>(ringIdRaw, false, excludedIds)
|
|
278
|
+
this.contacts.getAllContacts().map((contact) => closest.addContact(contact))
|
|
279
|
+
this.ringContacts.getAllContacts().map((contact) => closest.addContact(contact))
|
|
280
|
+
return closest.getClosestContacts(limit ?? 8)
|
|
249
281
|
}
|
|
250
282
|
|
|
251
283
|
getContactCount(excludedNodeIds?: Set<DhtAddress>): number {
|
|
252
|
-
return this.contacts.
|
|
253
|
-
if (!excludedNodeIds) {
|
|
254
|
-
return true
|
|
255
|
-
} else {
|
|
256
|
-
return !excludedNodeIds.has(contact.getNodeId())
|
|
257
|
-
}
|
|
258
|
-
}).length
|
|
284
|
+
return this.contacts.getSize(excludedNodeIds)
|
|
259
285
|
}
|
|
260
286
|
|
|
261
287
|
getConnectionCount(): number {
|
|
@@ -274,30 +300,30 @@ export class PeerManager extends EventEmitter<PeerManagerEvents> {
|
|
|
274
300
|
this.contacts.setActive(nodeId)
|
|
275
301
|
}
|
|
276
302
|
|
|
277
|
-
addContact(
|
|
303
|
+
addContact(peerDescriptor: PeerDescriptor): void {
|
|
278
304
|
if (this.stopped) {
|
|
279
305
|
return
|
|
280
306
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
if (!isInBucket) {
|
|
292
|
-
this.bucket.add(remote)
|
|
293
|
-
}
|
|
294
|
-
if (!isInContacts) {
|
|
295
|
-
this.contacts.addContact(remote)
|
|
296
|
-
}
|
|
297
|
-
if (setActive) {
|
|
298
|
-
this.contacts.setActive(nodeId)
|
|
299
|
-
}
|
|
307
|
+
const nodeId = getNodeIdFromPeerDescriptor(peerDescriptor)
|
|
308
|
+
if (nodeId !== this.config.localNodeId) {
|
|
309
|
+
logger.trace(`Adding new contact ${nodeId}`)
|
|
310
|
+
const remote = this.config.createDhtNodeRpcRemote(peerDescriptor)
|
|
311
|
+
const isInBucket = (this.bucket.get(peerDescriptor.nodeId) !== null)
|
|
312
|
+
const isInContacts = (this.contacts.getContact(nodeId) !== undefined)
|
|
313
|
+
const isInRingContacts = this.ringContacts.getContact(peerDescriptor) !== undefined
|
|
314
|
+
|
|
315
|
+
if (isInBucket || isInContacts) {
|
|
316
|
+
this.randomPeers.addContact(remote)
|
|
300
317
|
}
|
|
301
|
-
|
|
318
|
+
if (!isInBucket) {
|
|
319
|
+
this.bucket.add(remote)
|
|
320
|
+
}
|
|
321
|
+
if (!isInContacts) {
|
|
322
|
+
this.contacts.addContact(remote)
|
|
323
|
+
}
|
|
324
|
+
if (!isInRingContacts) {
|
|
325
|
+
this.ringContacts.addContact(remote)
|
|
326
|
+
}
|
|
327
|
+
}
|
|
302
328
|
}
|
|
303
329
|
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { PeerDescriptor } from '../../proto/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, getNodeIdFromPeerDescriptor } from '../../identifiers'
|
|
5
|
+
import EventEmitter from 'eventemitter3'
|
|
6
|
+
|
|
7
|
+
export interface RingContacts {
|
|
8
|
+
left: PeerDescriptor[]
|
|
9
|
+
right: PeerDescriptor[]
|
|
10
|
+
}
|
|
11
|
+
export interface RingContactListEvents {
|
|
12
|
+
ringContactAdded: (peerDescriptor: PeerDescriptor, closestPeers: RingContacts) => void
|
|
13
|
+
ringContactRemoved: (peerDescriptor: PeerDescriptor, closestPeers: RingContacts) => void
|
|
14
|
+
}
|
|
15
|
+
export class RingContactList<C extends { getPeerDescriptor(): PeerDescriptor }> extends EventEmitter<RingContactListEvents> {
|
|
16
|
+
|
|
17
|
+
private readonly numNeighborsPerSide = 5
|
|
18
|
+
private readonly referenceId: RingId
|
|
19
|
+
private readonly excludedIds: Set<DhtAddress>
|
|
20
|
+
private readonly leftNeighbors: OrderedMap<RingDistance, C>
|
|
21
|
+
private readonly rightNeighbors: OrderedMap<RingDistance, C>
|
|
22
|
+
private readonly emitEvents: boolean
|
|
23
|
+
|
|
24
|
+
constructor(rawReferenceId: RingIdRaw, emitEvents: boolean, excludedIds?: Set<DhtAddress>) {
|
|
25
|
+
super()
|
|
26
|
+
this.referenceId = getRingIdFromRaw(rawReferenceId)
|
|
27
|
+
this.emitEvents = emitEvents
|
|
28
|
+
this.excludedIds = excludedIds ?? new Set()
|
|
29
|
+
this.leftNeighbors = new OrderedMap<RingDistance, C>()
|
|
30
|
+
this.rightNeighbors = new OrderedMap<RingDistance, C>()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
addContact(contact: C): void {
|
|
34
|
+
const id = getRingIdFromPeerDescriptor(contact.getPeerDescriptor())
|
|
35
|
+
if (id === this.referenceId || this.excludedIds.has(getNodeIdFromPeerDescriptor(contact.getPeerDescriptor()))) {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
let elementAdded = false
|
|
39
|
+
let elementRemoved = false
|
|
40
|
+
|
|
41
|
+
const leftDistance = getLeftDistance(this.referenceId, id)
|
|
42
|
+
const lastLeftNeighbor = this.leftNeighbors.back()
|
|
43
|
+
if (lastLeftNeighbor === undefined || leftDistance < lastLeftNeighbor[0]) {
|
|
44
|
+
this.leftNeighbors.setElement(leftDistance, contact)
|
|
45
|
+
elementAdded = true
|
|
46
|
+
if (this.leftNeighbors.size() > this.numNeighborsPerSide) {
|
|
47
|
+
this.leftNeighbors.eraseElementByIterator(this.leftNeighbors.rBegin())
|
|
48
|
+
elementRemoved = true
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const rightDistance = getRightDistance(this.referenceId, id)
|
|
53
|
+
const lastRightNeighbor = this.rightNeighbors.back()
|
|
54
|
+
if (lastRightNeighbor === undefined || rightDistance < lastRightNeighbor[0]) {
|
|
55
|
+
this.rightNeighbors.setElement(rightDistance, contact)
|
|
56
|
+
elementAdded = true
|
|
57
|
+
if (this.rightNeighbors.size() > this.numNeighborsPerSide) {
|
|
58
|
+
this.rightNeighbors.eraseElementByIterator(this.rightNeighbors.rBegin())
|
|
59
|
+
elementRemoved = true
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (this.emitEvents && (elementAdded || elementRemoved)) {
|
|
64
|
+
const closestContacts = this.getClosestContacts()
|
|
65
|
+
const closestDescriptors = {
|
|
66
|
+
left: closestContacts.left.map((c) => c.getPeerDescriptor()),
|
|
67
|
+
right: closestContacts.right.map((c) => c.getPeerDescriptor())
|
|
68
|
+
}
|
|
69
|
+
if (elementAdded) {
|
|
70
|
+
this.emit('ringContactAdded', contact.getPeerDescriptor(), closestDescriptors)
|
|
71
|
+
}
|
|
72
|
+
if (elementRemoved) {
|
|
73
|
+
this.emit('ringContactRemoved', contact.getPeerDescriptor(), closestDescriptors)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
removeContact(contact?: C): void {
|
|
79
|
+
if (contact === undefined) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const id = getRingIdFromPeerDescriptor(contact.getPeerDescriptor())
|
|
84
|
+
const leftDistance = getLeftDistance(this.referenceId, id)
|
|
85
|
+
const rightDistance = getRightDistance(this.referenceId, id)
|
|
86
|
+
|
|
87
|
+
let elementRemoved = false
|
|
88
|
+
if (this.leftNeighbors.eraseElementByKey(leftDistance)) {
|
|
89
|
+
elementRemoved = true
|
|
90
|
+
}
|
|
91
|
+
if (this.rightNeighbors.eraseElementByKey(rightDistance)) {
|
|
92
|
+
elementRemoved = true
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (this.emitEvents && elementRemoved) {
|
|
96
|
+
const closestContacts = this.getClosestContacts()
|
|
97
|
+
const closestDescriptors = { left: closestContacts.left.map((c) => c.getPeerDescriptor()),
|
|
98
|
+
right: closestContacts.right.map((c) => c.getPeerDescriptor()) }
|
|
99
|
+
this.emit('ringContactRemoved', contact.getPeerDescriptor(), closestDescriptors)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getContact(peerDescriptor: PeerDescriptor): C | undefined {
|
|
104
|
+
const id = getRingIdFromPeerDescriptor(peerDescriptor)
|
|
105
|
+
const leftDistance = getLeftDistance(this.referenceId, id)
|
|
106
|
+
const rightDistance = getRightDistance(this.referenceId, id)
|
|
107
|
+
if (this.leftNeighbors.getElementByKey(leftDistance)) {
|
|
108
|
+
return this.leftNeighbors.getElementByKey(leftDistance)
|
|
109
|
+
}
|
|
110
|
+
if (this.rightNeighbors.getElementByKey(rightDistance)) {
|
|
111
|
+
return this.rightNeighbors.getElementByKey(rightDistance)
|
|
112
|
+
}
|
|
113
|
+
return undefined
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
getClosestContacts(limitPerSide?: number): { left: C[], right: C[] } {
|
|
117
|
+
const leftContacts: C[] = []
|
|
118
|
+
const rightContacts: C[] = []
|
|
119
|
+
|
|
120
|
+
let leftCount = 0
|
|
121
|
+
for (const item of this.leftNeighbors) {
|
|
122
|
+
if (limitPerSide != undefined && leftCount >= limitPerSide) {
|
|
123
|
+
break
|
|
124
|
+
}
|
|
125
|
+
leftContacts.push(item[1])
|
|
126
|
+
leftCount++
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
let rightCount = 0
|
|
130
|
+
for (const item of this.rightNeighbors) {
|
|
131
|
+
if (limitPerSide != undefined && rightCount >= limitPerSide) {
|
|
132
|
+
break
|
|
133
|
+
}
|
|
134
|
+
rightContacts.push(item[1])
|
|
135
|
+
rightCount++
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return { left: leftContacts, right: rightContacts }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
getAllContacts(): C[] {
|
|
142
|
+
const ret: C[] = []
|
|
143
|
+
for (const item of this.leftNeighbors) {
|
|
144
|
+
ret.push(item[1])
|
|
145
|
+
}
|
|
146
|
+
for (const item of this.rightNeighbors) {
|
|
147
|
+
ret.push(item[1])
|
|
148
|
+
}
|
|
149
|
+
return ret
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -92,6 +92,10 @@ export class SortedContactList<C extends { getNodeId: () => DhtAddress }> extend
|
|
|
92
92
|
return this.contactsById.get(id)
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
has(id: DhtAddress): boolean {
|
|
96
|
+
return this.contactsById.has(id)
|
|
97
|
+
}
|
|
98
|
+
|
|
95
99
|
public setContacted(contactId: DhtAddress): void {
|
|
96
100
|
if (this.contactsById.has(contactId)) {
|
|
97
101
|
this.contactsById.get(contactId)!.contacted = true
|
|
@@ -105,25 +109,17 @@ export class SortedContactList<C extends { getNodeId: () => DhtAddress }> extend
|
|
|
105
109
|
}
|
|
106
110
|
|
|
107
111
|
public getClosestContacts(limit?: number): C[] {
|
|
108
|
-
const ret
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
ret.push(contact.contact)
|
|
113
|
-
}
|
|
114
|
-
})
|
|
115
|
-
if (limit === undefined) {
|
|
116
|
-
return ret
|
|
117
|
-
} else {
|
|
118
|
-
return ret.slice(0, limit)
|
|
119
|
-
}
|
|
112
|
+
const ret = this.getAllContacts()
|
|
113
|
+
return (limit === undefined)
|
|
114
|
+
? ret
|
|
115
|
+
: ret.slice(0, limit)
|
|
120
116
|
}
|
|
121
117
|
|
|
122
118
|
public getUncontactedContacts(num: number): C[] {
|
|
123
119
|
const ret: C[] = []
|
|
124
120
|
for (const contactId of this.contactIds) {
|
|
125
|
-
const contact = this.contactsById.get(contactId)
|
|
126
|
-
if (
|
|
121
|
+
const contact = this.contactsById.get(contactId)!
|
|
122
|
+
if (!contact.contacted) {
|
|
127
123
|
ret.push(contact.contact)
|
|
128
124
|
if (ret.length >= num) {
|
|
129
125
|
return ret
|
|
@@ -136,8 +132,8 @@ export class SortedContactList<C extends { getNodeId: () => DhtAddress }> extend
|
|
|
136
132
|
public getActiveContacts(limit?: number): C[] {
|
|
137
133
|
const ret: C[] = []
|
|
138
134
|
this.contactIds.forEach((contactId) => {
|
|
139
|
-
const contact = this.contactsById.get(contactId)
|
|
140
|
-
if (contact
|
|
135
|
+
const contact = this.contactsById.get(contactId)!
|
|
136
|
+
if (contact.active) {
|
|
141
137
|
ret.push(contact.contact)
|
|
142
138
|
}
|
|
143
139
|
})
|
|
@@ -187,8 +183,16 @@ export class SortedContactList<C extends { getNodeId: () => DhtAddress }> extend
|
|
|
187
183
|
return this.contactIds.map((nodeId) => this.contactsById.get(nodeId)!.contact)
|
|
188
184
|
}
|
|
189
185
|
|
|
190
|
-
public getSize(): number {
|
|
191
|
-
|
|
186
|
+
public getSize(excludedNodeIds?: Set<DhtAddress>): number {
|
|
187
|
+
let excludedCount = 0
|
|
188
|
+
if (excludedNodeIds !== undefined) {
|
|
189
|
+
for (const nodeId of excludedNodeIds) {
|
|
190
|
+
if (this.has(nodeId)) {
|
|
191
|
+
excludedCount++
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return this.contactIds.length - excludedCount
|
|
192
196
|
}
|
|
193
197
|
|
|
194
198
|
public clear(): void {
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { PeerDescriptor } from '../../proto/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
|
+
}
|
|
@@ -38,7 +38,9 @@ export class DiscoverySession {
|
|
|
38
38
|
if (this.stopped) {
|
|
39
39
|
return
|
|
40
40
|
}
|
|
41
|
-
|
|
41
|
+
for (const contact of contacts) {
|
|
42
|
+
this.config.peerManager.addContact(contact)
|
|
43
|
+
}
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
private async getClosestPeersFromContact(contact: DhtNodeRpcRemote): Promise<PeerDescriptor[]> {
|
|
@@ -2,10 +2,12 @@ import { DiscoverySession } from './DiscoverySession'
|
|
|
2
2
|
import { DhtNodeRpcRemote } from '../DhtNodeRpcRemote'
|
|
3
3
|
import { PeerDescriptor } from '../../proto/packages/dht/protos/DhtRpc'
|
|
4
4
|
import { Logger, scheduleAtInterval, setAbortableTimeout } from '@streamr/utils'
|
|
5
|
-
import {
|
|
5
|
+
import { ConnectionLocker } from '../../connection/ConnectionManager'
|
|
6
6
|
import { PeerManager } from '../PeerManager'
|
|
7
7
|
import { DhtAddress, areEqualPeerDescriptors, getDhtAddressFromRaw, getNodeIdFromPeerDescriptor, getRawFromDhtAddress } from '../../identifiers'
|
|
8
8
|
import { ServiceID } from '../../types/ServiceID'
|
|
9
|
+
import { RingDiscoverySession } from './RingDiscoverySession'
|
|
10
|
+
import { RingIdRaw, getRingIdRawFromPeerDescriptor } from '../contact/ringIdentifiers'
|
|
9
11
|
|
|
10
12
|
interface PeerDiscoveryConfig {
|
|
11
13
|
localPeerDescriptor: PeerDescriptor
|
|
@@ -14,7 +16,7 @@ interface PeerDiscoveryConfig {
|
|
|
14
16
|
serviceId: ServiceID
|
|
15
17
|
parallelism: number
|
|
16
18
|
joinTimeout: number
|
|
17
|
-
|
|
19
|
+
connectionLocker?: ConnectionLocker
|
|
18
20
|
peerManager: PeerManager
|
|
19
21
|
}
|
|
20
22
|
|
|
@@ -29,6 +31,8 @@ const logger = new Logger(module)
|
|
|
29
31
|
export class PeerDiscovery {
|
|
30
32
|
|
|
31
33
|
private ongoingDiscoverySessions: Map<string, DiscoverySession> = new Map()
|
|
34
|
+
private ongoingRingDiscoverySessions: Map<string, RingDiscoverySession> = new Map()
|
|
35
|
+
|
|
32
36
|
private rejoinOngoing = false
|
|
33
37
|
private joinCalled = false
|
|
34
38
|
private readonly abortController: AbortController
|
|
@@ -74,18 +78,24 @@ export class PeerDiscovery {
|
|
|
74
78
|
if (areEqualPeerDescriptors(entryPointDescriptor, this.config.localPeerDescriptor)) {
|
|
75
79
|
return
|
|
76
80
|
}
|
|
77
|
-
this.config.
|
|
78
|
-
this.config.peerManager.addContact(
|
|
81
|
+
this.config.connectionLocker?.lockConnection(entryPointDescriptor, `${this.config.serviceId}::joinDht`)
|
|
82
|
+
this.config.peerManager.addContact(entryPointDescriptor)
|
|
79
83
|
const targetId = getNodeIdFromPeerDescriptor(this.config.localPeerDescriptor)
|
|
80
84
|
const sessions = [this.createSession(targetId, contactedPeers)]
|
|
81
85
|
if (additionalDistantJoin.enabled) {
|
|
82
86
|
sessions.push(this.createSession(createDistantDhtAddress(targetId), additionalDistantJoin.contactedPeers))
|
|
83
87
|
}
|
|
84
88
|
await this.runSessions(sessions, entryPointDescriptor, retry)
|
|
85
|
-
this.config.
|
|
89
|
+
this.config.connectionLocker?.unlockConnection(entryPointDescriptor, `${this.config.serviceId}::joinDht`)
|
|
86
90
|
|
|
87
91
|
}
|
|
88
92
|
|
|
93
|
+
async joinRing(): Promise<void> {
|
|
94
|
+
const contactedPeers = new Set<DhtAddress>()
|
|
95
|
+
const sessions = [this.createRingSession(getRingIdRawFromPeerDescriptor(this.config.localPeerDescriptor), contactedPeers)]
|
|
96
|
+
await this.runRingSessions(sessions)
|
|
97
|
+
}
|
|
98
|
+
|
|
89
99
|
private createSession(targetId: DhtAddress, contactedPeers: Set<DhtAddress>): DiscoverySession {
|
|
90
100
|
const sessionOptions = {
|
|
91
101
|
targetId,
|
|
@@ -97,6 +107,17 @@ export class PeerDiscovery {
|
|
|
97
107
|
return new DiscoverySession(sessionOptions)
|
|
98
108
|
}
|
|
99
109
|
|
|
110
|
+
private createRingSession(targetId: RingIdRaw, contactedPeers: Set<DhtAddress>): RingDiscoverySession {
|
|
111
|
+
const sessionOptions = {
|
|
112
|
+
targetId,
|
|
113
|
+
parallelism: this.config.parallelism,
|
|
114
|
+
noProgressLimit: this.config.joinNoProgressLimit,
|
|
115
|
+
peerManager: this.config.peerManager,
|
|
116
|
+
contactedPeers
|
|
117
|
+
}
|
|
118
|
+
return new RingDiscoverySession(sessionOptions)
|
|
119
|
+
}
|
|
120
|
+
|
|
100
121
|
private async runSessions(sessions: DiscoverySession[], entryPointDescriptor: PeerDescriptor, retry: boolean): Promise<void> {
|
|
101
122
|
try {
|
|
102
123
|
for (const session of sessions) {
|
|
@@ -121,6 +142,19 @@ export class PeerDiscovery {
|
|
|
121
142
|
}
|
|
122
143
|
}
|
|
123
144
|
|
|
145
|
+
private async runRingSessions(sessions: RingDiscoverySession[]): Promise<void> {
|
|
146
|
+
try {
|
|
147
|
+
for (const session of sessions) {
|
|
148
|
+
this.ongoingRingDiscoverySessions.set(session.id, session)
|
|
149
|
+
await session.findClosestNodes(this.config.joinTimeout)
|
|
150
|
+
}
|
|
151
|
+
} catch (_e) {
|
|
152
|
+
logger.debug(`Ring join on ${this.config.serviceId} timed out`)
|
|
153
|
+
} finally {
|
|
154
|
+
sessions.forEach((session) => this.ongoingDiscoverySessions.delete(session.id))
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
124
158
|
public async rejoinDht(entryPoint: PeerDescriptor): Promise<void> {
|
|
125
159
|
if (this.isStopped() || this.rejoinOngoing) {
|
|
126
160
|
return
|
|
@@ -162,7 +196,9 @@ export class PeerDiscovery {
|
|
|
162
196
|
await Promise.allSettled(
|
|
163
197
|
nodes.map(async (peer: DhtNodeRpcRemote) => {
|
|
164
198
|
const contacts = await peer.getClosestPeers(localNodeId)
|
|
165
|
-
|
|
199
|
+
for (const contact of contacts) {
|
|
200
|
+
this.config.peerManager.addContact(contact)
|
|
201
|
+
}
|
|
166
202
|
})
|
|
167
203
|
)
|
|
168
204
|
}
|
|
@@ -184,5 +220,8 @@ export class PeerDiscovery {
|
|
|
184
220
|
this.ongoingDiscoverySessions.forEach((session) => {
|
|
185
221
|
session.stop()
|
|
186
222
|
})
|
|
223
|
+
this.ongoingRingDiscoverySessions.forEach((session) => {
|
|
224
|
+
session.stop()
|
|
225
|
+
})
|
|
187
226
|
}
|
|
188
227
|
}
|