@streamr/dht 102.0.0-beta.1 → 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/google/protobuf/any.d.ts +180 -0
- package/dist/generated/google/protobuf/any.js +155 -0
- package/dist/generated/google/protobuf/any.js.map +1 -0
- package/dist/generated/google/protobuf/empty.d.ts +31 -0
- package/dist/generated/google/protobuf/empty.js +32 -0
- package/dist/generated/google/protobuf/empty.js.map +1 -0
- package/dist/generated/google/protobuf/timestamp.d.ts +155 -0
- package/dist/generated/google/protobuf/timestamp.js +136 -0
- package/dist/generated/google/protobuf/timestamp.js.map +1 -0
- package/dist/generated/packages/dht/protos/DhtRpc.client.d.ts +361 -0
- package/dist/generated/packages/dht/protos/DhtRpc.client.js +285 -0
- package/dist/generated/packages/dht/protos/DhtRpc.client.js.map +1 -0
- package/dist/generated/packages/dht/protos/DhtRpc.d.ts +999 -0
- package/dist/generated/packages/dht/protos/DhtRpc.js +677 -0
- package/dist/generated/packages/dht/protos/DhtRpc.js.map +1 -0
- package/dist/generated/packages/dht/protos/DhtRpc.server.d.ts +162 -0
- package/dist/generated/packages/dht/protos/DhtRpc.server.js +3 -0
- package/dist/generated/packages/dht/protos/DhtRpc.server.js.map +1 -0
- package/dist/generated/packages/proto-rpc/protos/ProtoRpc.d.ts +87 -0
- package/dist/generated/packages/proto-rpc/protos/ProtoRpc.js +66 -0
- package/dist/generated/packages/proto-rpc/protos/ProtoRpc.js.map +1 -0
- package/dist/package.json +7 -7
- package/package.json +7 -7
- 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 -209
- 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 -369
- 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 -245
- 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 -290
- package/src/dht/DhtNode.ts +0 -683
- 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 -305
- 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 -192
- 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 -191
- 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 -123
- 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 -86
- 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 -34
- 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 -79
- 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,244 +0,0 @@
|
|
|
1
|
-
import { Logger, scheduleAtInterval, setAbortableTimeout } from '@streamr/utils'
|
|
2
|
-
import { ConnectionLocker } from '../../connection/ConnectionManager'
|
|
3
|
-
import {
|
|
4
|
-
DhtAddress,
|
|
5
|
-
areEqualPeerDescriptors,
|
|
6
|
-
randomDhtAddress,
|
|
7
|
-
toDhtAddress,
|
|
8
|
-
toNodeId,
|
|
9
|
-
toDhtAddressRaw
|
|
10
|
-
} from '../../identifiers'
|
|
11
|
-
import { PeerDescriptor } from '../../../generated/packages/dht/protos/DhtRpc'
|
|
12
|
-
import { ServiceID } from '../../types/ServiceID'
|
|
13
|
-
import { DhtNodeRpcRemote } from '../DhtNodeRpcRemote'
|
|
14
|
-
import { PeerManager } from '../PeerManager'
|
|
15
|
-
import { getClosestNodes } from '../contact/getClosestNodes'
|
|
16
|
-
import { RingIdRaw, getRingIdRawFromPeerDescriptor } from '../contact/ringIdentifiers'
|
|
17
|
-
import { DiscoverySession } from './DiscoverySession'
|
|
18
|
-
import { RingDiscoverySession } from './RingDiscoverySession'
|
|
19
|
-
import { CONTROL_LAYER_NODE_SERVICE_ID } from '../DhtNode'
|
|
20
|
-
|
|
21
|
-
interface PeerDiscoveryOptions {
|
|
22
|
-
localPeerDescriptor: PeerDescriptor
|
|
23
|
-
joinNoProgressLimit: number
|
|
24
|
-
serviceId: ServiceID
|
|
25
|
-
parallelism: number
|
|
26
|
-
joinTimeout: number
|
|
27
|
-
connectionLocker?: ConnectionLocker
|
|
28
|
-
peerManager: PeerManager
|
|
29
|
-
abortSignal: AbortSignal
|
|
30
|
-
createDhtNodeRpcRemote: (peerDescriptor: PeerDescriptor) => DhtNodeRpcRemote
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export const createDistantDhtAddress = (address: DhtAddress): DhtAddress => {
|
|
34
|
-
const raw = toDhtAddressRaw(address)
|
|
35
|
-
const flipped = raw.map((val) => ~val)
|
|
36
|
-
return toDhtAddress(flipped)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const logger = new Logger(module)
|
|
40
|
-
|
|
41
|
-
export class PeerDiscovery {
|
|
42
|
-
|
|
43
|
-
private ongoingDiscoverySessions: Map<string, DiscoverySession> = new Map()
|
|
44
|
-
private ongoingRingDiscoverySessions: Map<string, RingDiscoverySession> = new Map()
|
|
45
|
-
|
|
46
|
-
private rejoinOngoing = false
|
|
47
|
-
private joinCalled = false
|
|
48
|
-
private recoveryIntervalStarted = false
|
|
49
|
-
private readonly options: PeerDiscoveryOptions
|
|
50
|
-
|
|
51
|
-
constructor(options: PeerDiscoveryOptions) {
|
|
52
|
-
this.options = options
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async joinDht(
|
|
56
|
-
entryPoints: PeerDescriptor[],
|
|
57
|
-
doAdditionalDistantPeerDiscovery = true,
|
|
58
|
-
retry = true
|
|
59
|
-
): Promise<void> {
|
|
60
|
-
const contactedPeers = new Set<DhtAddress>()
|
|
61
|
-
const distantJoinOptions = doAdditionalDistantPeerDiscovery
|
|
62
|
-
? { enabled: true, contactedPeers: new Set<DhtAddress>() } : { enabled: false } as const
|
|
63
|
-
await Promise.all(entryPoints.map((entryPoint) => this.joinThroughEntryPoint(
|
|
64
|
-
entryPoint,
|
|
65
|
-
contactedPeers,
|
|
66
|
-
distantJoinOptions,
|
|
67
|
-
retry
|
|
68
|
-
)))
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
private async joinThroughEntryPoint(
|
|
72
|
-
entryPointDescriptor: PeerDescriptor,
|
|
73
|
-
// Note that this set is mutated by DiscoverySession
|
|
74
|
-
contactedPeers: Set<DhtAddress>,
|
|
75
|
-
additionalDistantJoin: { enabled: true, contactedPeers: Set<DhtAddress> } | { enabled: false },
|
|
76
|
-
retry = true
|
|
77
|
-
): Promise<void> {
|
|
78
|
-
if (this.isStopped()) {
|
|
79
|
-
return
|
|
80
|
-
}
|
|
81
|
-
this.joinCalled = true
|
|
82
|
-
logger.debug(
|
|
83
|
-
`Joining ${this.options.serviceId === CONTROL_LAYER_NODE_SERVICE_ID
|
|
84
|
-
? 'The Streamr Network' : `Control Layer for ${this.options.serviceId}`}`
|
|
85
|
-
+ ` via entrypoint ${toNodeId(entryPointDescriptor)}`
|
|
86
|
-
)
|
|
87
|
-
if (areEqualPeerDescriptors(entryPointDescriptor, this.options.localPeerDescriptor)) {
|
|
88
|
-
return
|
|
89
|
-
}
|
|
90
|
-
this.options.connectionLocker?.lockConnection(entryPointDescriptor, `${this.options.serviceId}::joinDht`)
|
|
91
|
-
this.options.peerManager.addContact(entryPointDescriptor)
|
|
92
|
-
const targetId = toNodeId(this.options.localPeerDescriptor)
|
|
93
|
-
const sessions = [this.createSession(targetId, contactedPeers)]
|
|
94
|
-
if (additionalDistantJoin.enabled) {
|
|
95
|
-
sessions.push(this.createSession(createDistantDhtAddress(targetId), additionalDistantJoin.contactedPeers))
|
|
96
|
-
}
|
|
97
|
-
await this.runSessions(sessions, entryPointDescriptor, retry)
|
|
98
|
-
this.options.connectionLocker?.unlockConnection(entryPointDescriptor, `${this.options.serviceId}::joinDht`)
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async joinRing(): Promise<void> {
|
|
103
|
-
const contactedPeers = new Set<DhtAddress>()
|
|
104
|
-
const sessions = [this.createRingSession(getRingIdRawFromPeerDescriptor(this.options.localPeerDescriptor), contactedPeers)]
|
|
105
|
-
await this.runRingSessions(sessions)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
private createSession(targetId: DhtAddress, contactedPeers: Set<DhtAddress>): DiscoverySession {
|
|
109
|
-
const sessionOptions = {
|
|
110
|
-
targetId,
|
|
111
|
-
parallelism: this.options.parallelism,
|
|
112
|
-
noProgressLimit: this.options.joinNoProgressLimit,
|
|
113
|
-
peerManager: this.options.peerManager,
|
|
114
|
-
contactedPeers,
|
|
115
|
-
abortSignal: this.options.abortSignal,
|
|
116
|
-
createDhtNodeRpcRemote: this.options.createDhtNodeRpcRemote
|
|
117
|
-
}
|
|
118
|
-
return new DiscoverySession(sessionOptions)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
private createRingSession(targetId: RingIdRaw, contactedPeers: Set<DhtAddress>): RingDiscoverySession {
|
|
122
|
-
const sessionOptions = {
|
|
123
|
-
targetId,
|
|
124
|
-
parallelism: this.options.parallelism,
|
|
125
|
-
noProgressLimit: this.options.joinNoProgressLimit,
|
|
126
|
-
peerManager: this.options.peerManager,
|
|
127
|
-
contactedPeers,
|
|
128
|
-
abortSignal: this.options.abortSignal,
|
|
129
|
-
createDhtNodeRpcRemote: this.options.createDhtNodeRpcRemote
|
|
130
|
-
}
|
|
131
|
-
return new RingDiscoverySession(sessionOptions)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
private async runSessions(sessions: DiscoverySession[], entryPointDescriptor: PeerDescriptor, retry: boolean): Promise<void> {
|
|
135
|
-
try {
|
|
136
|
-
for (const session of sessions) {
|
|
137
|
-
this.ongoingDiscoverySessions.set(session.id, session)
|
|
138
|
-
await session.findClosestNodes(this.options.joinTimeout)
|
|
139
|
-
}
|
|
140
|
-
} catch (_e) {
|
|
141
|
-
logger.debug(`DHT join on ${this.options.serviceId} timed out`)
|
|
142
|
-
} finally {
|
|
143
|
-
if (!this.isStopped()) {
|
|
144
|
-
if (this.options.peerManager.getNeighborCount() === 0) {
|
|
145
|
-
if (retry) {
|
|
146
|
-
// TODO should we catch possible promise rejection?
|
|
147
|
-
// TODO use options option or named constant?
|
|
148
|
-
setAbortableTimeout(() => this.rejoinDht(entryPointDescriptor), 1000, this.options.abortSignal)
|
|
149
|
-
}
|
|
150
|
-
} else {
|
|
151
|
-
await this.ensureRecoveryIntervalIsRunning()
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
sessions.forEach((session) => this.ongoingDiscoverySessions.delete(session.id))
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
private async runRingSessions(sessions: RingDiscoverySession[]): Promise<void> {
|
|
159
|
-
try {
|
|
160
|
-
for (const session of sessions) {
|
|
161
|
-
this.ongoingRingDiscoverySessions.set(session.id, session)
|
|
162
|
-
await session.findClosestNodes(this.options.joinTimeout)
|
|
163
|
-
}
|
|
164
|
-
} catch (_e) {
|
|
165
|
-
logger.debug(`Ring join on ${this.options.serviceId} timed out`)
|
|
166
|
-
} finally {
|
|
167
|
-
sessions.forEach((session) => this.ongoingDiscoverySessions.delete(session.id))
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
public async rejoinDht(
|
|
172
|
-
entryPoint: PeerDescriptor,
|
|
173
|
-
contactedPeers: Set<DhtAddress> = new Set(),
|
|
174
|
-
distantJoinContactPeers: Set<DhtAddress> = new Set()
|
|
175
|
-
): Promise<void> {
|
|
176
|
-
if (this.isStopped() || this.rejoinOngoing) {
|
|
177
|
-
return
|
|
178
|
-
}
|
|
179
|
-
logger.debug(`Rejoining DHT ${this.options.serviceId}`)
|
|
180
|
-
this.rejoinOngoing = true
|
|
181
|
-
try {
|
|
182
|
-
await this.joinThroughEntryPoint(entryPoint, contactedPeers, { enabled: true, contactedPeers: distantJoinContactPeers })
|
|
183
|
-
logger.debug(`Rejoined DHT successfully ${this.options.serviceId}!`)
|
|
184
|
-
} catch {
|
|
185
|
-
logger.warn(`Rejoining DHT ${this.options.serviceId} failed`)
|
|
186
|
-
if (!this.isStopped()) {
|
|
187
|
-
// TODO should we catch possible promise rejection?
|
|
188
|
-
// TODO use options option or named constant?
|
|
189
|
-
setAbortableTimeout(() => this.rejoinDht(entryPoint), 5000, this.options.abortSignal)
|
|
190
|
-
}
|
|
191
|
-
} finally {
|
|
192
|
-
this.rejoinOngoing = false
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
private async ensureRecoveryIntervalIsRunning(): Promise<void> {
|
|
197
|
-
if (!this.recoveryIntervalStarted) {
|
|
198
|
-
this.recoveryIntervalStarted = true
|
|
199
|
-
// TODO use options option or named constant?
|
|
200
|
-
await scheduleAtInterval(() => this.fetchClosestAndRandomNeighbors(), 60000, true, this.options.abortSignal)
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
private async fetchClosestAndRandomNeighbors(): Promise<void> {
|
|
205
|
-
if (this.isStopped()) {
|
|
206
|
-
return
|
|
207
|
-
}
|
|
208
|
-
const localNodeId = toNodeId(this.options.localPeerDescriptor)
|
|
209
|
-
const nodes = this.getClosestNeighbors(localNodeId, this.options.parallelism)
|
|
210
|
-
const randomNodes = this.getClosestNeighbors(randomDhtAddress(), 1)
|
|
211
|
-
await Promise.allSettled([
|
|
212
|
-
...nodes.map(async (node: PeerDescriptor) => {
|
|
213
|
-
const remote = this.options.createDhtNodeRpcRemote(node)
|
|
214
|
-
const contacts = await remote.getClosestPeers(localNodeId)
|
|
215
|
-
for (const contact of contacts) {
|
|
216
|
-
this.options.peerManager.addContact(contact)
|
|
217
|
-
}
|
|
218
|
-
}),
|
|
219
|
-
...randomNodes.map(async (node: PeerDescriptor) => {
|
|
220
|
-
const remote = this.options.createDhtNodeRpcRemote(node)
|
|
221
|
-
const contacts = await remote.getClosestPeers(randomDhtAddress())
|
|
222
|
-
for (const contact of contacts) {
|
|
223
|
-
this.options.peerManager.addContact(contact)
|
|
224
|
-
}
|
|
225
|
-
})
|
|
226
|
-
])
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
private getClosestNeighbors(referenceId: DhtAddress, maxCount: number): PeerDescriptor[] {
|
|
230
|
-
return getClosestNodes(referenceId, this.options.peerManager.getNeighbors().map((n) => n.getPeerDescriptor()), { maxCount })
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
public isJoinOngoing(): boolean {
|
|
234
|
-
return !this.joinCalled ? true : this.ongoingDiscoverySessions.size > 0
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
public isJoinCalled(): boolean {
|
|
238
|
-
return this.joinCalled
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
private isStopped() {
|
|
242
|
-
return this.options.abortSignal.aborted
|
|
243
|
-
}
|
|
244
|
-
}
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { Gate, Logger, withTimeout } from '@streamr/utils'
|
|
2
|
-
import { v4 } from 'uuid'
|
|
3
|
-
import { DhtAddress, toNodeId } from '../../identifiers'
|
|
4
|
-
import { PeerDescriptor } from '../../../generated/packages/dht/protos/DhtRpc'
|
|
5
|
-
import { DhtNodeRpcRemote } from '../DhtNodeRpcRemote'
|
|
6
|
-
import { PeerManager } from '../PeerManager'
|
|
7
|
-
import { RingContacts } from '../contact/RingContactList'
|
|
8
|
-
import { RingId, RingIdRaw, getLeftDistance, getRingIdFromPeerDescriptor, getRingIdFromRaw } from '../contact/ringIdentifiers'
|
|
9
|
-
|
|
10
|
-
const logger = new Logger(module)
|
|
11
|
-
|
|
12
|
-
interface RingDiscoverySessionOptions {
|
|
13
|
-
targetId: RingIdRaw
|
|
14
|
-
parallelism: number
|
|
15
|
-
noProgressLimit: number
|
|
16
|
-
peerManager: PeerManager
|
|
17
|
-
// Note that contacted peers will be mutated by the DiscoverySession or other parallel sessions
|
|
18
|
-
contactedPeers: Set<DhtAddress>
|
|
19
|
-
abortSignal: AbortSignal
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export class RingDiscoverySession {
|
|
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: RingDiscoverySessionOptions
|
|
29
|
-
private numContactedPeers = 0
|
|
30
|
-
private targetIdAsRingId: RingId
|
|
31
|
-
|
|
32
|
-
constructor(options: RingDiscoverySessionOptions) {
|
|
33
|
-
this.options = options
|
|
34
|
-
this.targetIdAsRingId = getRingIdFromRaw(this.options.targetId)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
private addContacts(contacts: PeerDescriptor[]): void {
|
|
38
|
-
if (this.options.abortSignal.aborted || this.doneGate.isOpen()) {
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
for (const contact of contacts) {
|
|
42
|
-
this.options.peerManager.addContact(contact)
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
private async fetchClosestContactsFromRemote(contact: DhtNodeRpcRemote): Promise<RingContacts> {
|
|
47
|
-
if (this.options.abortSignal.aborted || this.doneGate.isOpen()) {
|
|
48
|
-
return { left: [], right: [] }
|
|
49
|
-
}
|
|
50
|
-
logger.trace(`Getting closest ring peers from contact: ${toNodeId(contact.getPeerDescriptor())}`)
|
|
51
|
-
this.numContactedPeers++
|
|
52
|
-
this.options.contactedPeers.add(contact.getNodeId())
|
|
53
|
-
const returnedContacts = await contact.getClosestRingPeers(this.options.targetId)
|
|
54
|
-
this.options.peerManager.setContactActive(contact.getNodeId())
|
|
55
|
-
return returnedContacts
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
private onRequestSucceeded(nodeId: DhtAddress, contacts: RingContacts) {
|
|
59
|
-
if (!this.ongoingRequests.has(nodeId)) {
|
|
60
|
-
return
|
|
61
|
-
}
|
|
62
|
-
this.ongoingRequests.delete(nodeId)
|
|
63
|
-
const oldClosestContacts = this.options.peerManager.getClosestRingContactsTo(this.options.targetId, 1)
|
|
64
|
-
const oldClosestLeftDistance = getLeftDistance(
|
|
65
|
-
this.targetIdAsRingId,
|
|
66
|
-
getRingIdFromPeerDescriptor(oldClosestContacts.left[0].getPeerDescriptor())
|
|
67
|
-
)
|
|
68
|
-
const oldClosestRightDistance = getLeftDistance(
|
|
69
|
-
this.targetIdAsRingId,
|
|
70
|
-
getRingIdFromPeerDescriptor(oldClosestContacts.right[0].getPeerDescriptor())
|
|
71
|
-
)
|
|
72
|
-
this.addContacts(contacts.left.concat(contacts.right))
|
|
73
|
-
const newClosestContacts = this.options.peerManager.getClosestRingContactsTo(this.options.targetId, 1)
|
|
74
|
-
const newClosestLeftDistance = getLeftDistance(this.targetIdAsRingId,
|
|
75
|
-
getRingIdFromPeerDescriptor(newClosestContacts.left[0].getPeerDescriptor()))
|
|
76
|
-
const newClosestRightDistance = getLeftDistance(this.targetIdAsRingId,
|
|
77
|
-
getRingIdFromPeerDescriptor(newClosestContacts.right[0].getPeerDescriptor()))
|
|
78
|
-
if (newClosestLeftDistance >= oldClosestLeftDistance && newClosestRightDistance >= oldClosestRightDistance) {
|
|
79
|
-
this.noProgressCounter++
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
private onRequestFailed(peer: DhtNodeRpcRemote) {
|
|
84
|
-
if (!this.ongoingRequests.has(peer.getNodeId())) {
|
|
85
|
-
return
|
|
86
|
-
}
|
|
87
|
-
this.ongoingRequests.delete(peer.getNodeId())
|
|
88
|
-
this.options.peerManager.removeContact(peer.getNodeId())
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
private findMoreContacts(): void {
|
|
92
|
-
if (this.options.abortSignal.aborted || this.doneGate.isOpen()) {
|
|
93
|
-
return
|
|
94
|
-
}
|
|
95
|
-
const uncontacted = this.options.peerManager.getClosestRingContactsTo(
|
|
96
|
-
this.options.targetId,
|
|
97
|
-
this.options.parallelism,
|
|
98
|
-
this.options.contactedPeers
|
|
99
|
-
)
|
|
100
|
-
if ((uncontacted.left.length === 0 && uncontacted.right.length === 0)
|
|
101
|
-
|| this.noProgressCounter >= this.options.noProgressLimit) {
|
|
102
|
-
this.doneGate.open()
|
|
103
|
-
return
|
|
104
|
-
}
|
|
105
|
-
// ask from both sides equally
|
|
106
|
-
const merged = []
|
|
107
|
-
const alreadyInMerged: Set<DhtAddress> = new Set()
|
|
108
|
-
const length = Math.max(uncontacted.left.length, uncontacted.right.length)
|
|
109
|
-
for (let i = 0; i < length; i++) {
|
|
110
|
-
if (i < uncontacted.left.length) {
|
|
111
|
-
if (!alreadyInMerged.has(uncontacted.left[i].getNodeId())) {
|
|
112
|
-
merged.push(uncontacted.left[i])
|
|
113
|
-
alreadyInMerged.add(uncontacted.left[i].getNodeId())
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
if (i < uncontacted.right.length) {
|
|
117
|
-
if (!alreadyInMerged.has(uncontacted.right[i].getNodeId())) {
|
|
118
|
-
merged.push(uncontacted.right[i])
|
|
119
|
-
alreadyInMerged.add(uncontacted.right[i].getNodeId())
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
for (const nextPeer of merged) {
|
|
125
|
-
if (this.ongoingRequests.size >= this.options.parallelism) {
|
|
126
|
-
break
|
|
127
|
-
}
|
|
128
|
-
this.ongoingRequests.add(nextPeer.getNodeId())
|
|
129
|
-
// eslint-disable-next-line promise/catch-or-return
|
|
130
|
-
this.fetchClosestContactsFromRemote(nextPeer)
|
|
131
|
-
.then((contacts) => this.onRequestSucceeded(nextPeer.getNodeId(), contacts))
|
|
132
|
-
.catch(() => this.onRequestFailed(nextPeer))
|
|
133
|
-
.finally(() => {
|
|
134
|
-
this.findMoreContacts()
|
|
135
|
-
})
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
public async findClosestNodes(timeout: number): Promise<void> {
|
|
140
|
-
if (this.options.peerManager.getNearbyContactCount(this.options.contactedPeers) === 0) {
|
|
141
|
-
return
|
|
142
|
-
}
|
|
143
|
-
setImmediate(() => {
|
|
144
|
-
this.findMoreContacts()
|
|
145
|
-
})
|
|
146
|
-
await withTimeout(this.doneGate.waitUntilOpen(), timeout, 'discovery session timed out', this.options.abortSignal)
|
|
147
|
-
}
|
|
148
|
-
}
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DataEntry,
|
|
3
|
-
PeerDescriptor,
|
|
4
|
-
RecursiveOperation,
|
|
5
|
-
RecursiveOperationRequest,
|
|
6
|
-
RouteMessageAck,
|
|
7
|
-
RouteMessageError,
|
|
8
|
-
RouteMessageWrapper
|
|
9
|
-
} from '../../../generated/packages/dht/protos/DhtRpc'
|
|
10
|
-
import { Router } from '../routing/Router'
|
|
11
|
-
import { RoutingMode } from '../routing/RoutingSession'
|
|
12
|
-
import { Logger, areEqualBinaries, runAndWaitForEvents3, wait } from '@streamr/utils'
|
|
13
|
-
import { RoutingRpcCommunicator } from '../../transport/RoutingRpcCommunicator'
|
|
14
|
-
import { RecursiveOperationSessionRpcRemote } from './RecursiveOperationSessionRpcRemote'
|
|
15
|
-
import { RECURSIVE_OPERATION_TIMEOUT, RecursiveOperationSession, RecursiveOperationSessionEvents } from './RecursiveOperationSession'
|
|
16
|
-
import { DhtNodeRpcRemote } from '../DhtNodeRpcRemote'
|
|
17
|
-
import { ITransport } from '../../transport/ITransport'
|
|
18
|
-
import { LocalDataStore } from '../store/LocalDataStore'
|
|
19
|
-
import { ListeningRpcCommunicator } from '../../transport/ListeningRpcCommunicator'
|
|
20
|
-
import { RecursiveOperationSessionRpcClient } from '../../../generated/packages/dht/protos/DhtRpc.client'
|
|
21
|
-
import { SortedContactList } from '../contact/SortedContactList'
|
|
22
|
-
import { getPreviousPeer } from '../routing/getPreviousPeer'
|
|
23
|
-
import { createRouteMessageAck } from '../routing/RouterRpcLocal'
|
|
24
|
-
import { ServiceID } from '../../types/ServiceID'
|
|
25
|
-
import { RecursiveOperationRpcLocal } from './RecursiveOperationRpcLocal'
|
|
26
|
-
import { DhtAddress, areEqualPeerDescriptors, toDhtAddress, toNodeId, toDhtAddressRaw } from '../../identifiers'
|
|
27
|
-
import { getDistance } from '../PeerManager'
|
|
28
|
-
import { ConnectionsView } from '../../exports'
|
|
29
|
-
|
|
30
|
-
interface RecursiveOperationManagerOptions {
|
|
31
|
-
rpcCommunicator: RoutingRpcCommunicator
|
|
32
|
-
sessionTransport: ITransport
|
|
33
|
-
router: Router
|
|
34
|
-
connectionsView: ConnectionsView
|
|
35
|
-
localPeerDescriptor: PeerDescriptor
|
|
36
|
-
serviceId: ServiceID
|
|
37
|
-
localDataStore: LocalDataStore
|
|
38
|
-
addContact: (contact: PeerDescriptor) => void
|
|
39
|
-
createDhtNodeRpcRemote: (peerDescriptor: PeerDescriptor) => DhtNodeRpcRemote
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface RecursiveOperationResult { closestNodes: PeerDescriptor[], dataEntries?: DataEntry[] }
|
|
43
|
-
|
|
44
|
-
const logger = new Logger(module)
|
|
45
|
-
|
|
46
|
-
export class RecursiveOperationManager {
|
|
47
|
-
|
|
48
|
-
private ongoingSessions: Map<string, RecursiveOperationSession> = new Map()
|
|
49
|
-
private stopped = false
|
|
50
|
-
private readonly options: RecursiveOperationManagerOptions
|
|
51
|
-
|
|
52
|
-
constructor(options: RecursiveOperationManagerOptions) {
|
|
53
|
-
this.options = options
|
|
54
|
-
this.registerLocalRpcMethods()
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
private registerLocalRpcMethods() {
|
|
58
|
-
const rpcLocal = new RecursiveOperationRpcLocal({
|
|
59
|
-
doRouteRequest: (routedMessage: RouteMessageWrapper) => this.doRouteRequest(routedMessage),
|
|
60
|
-
addContact: (contact: PeerDescriptor) => this.options.addContact(contact),
|
|
61
|
-
isMostLikelyDuplicate: (requestId: string) => this.options.router.isMostLikelyDuplicate(requestId),
|
|
62
|
-
addToDuplicateDetector: (requestId: string) => this.options.router.addToDuplicateDetector(requestId)
|
|
63
|
-
})
|
|
64
|
-
this.options.rpcCommunicator.registerRpcMethod(
|
|
65
|
-
RouteMessageWrapper,
|
|
66
|
-
RouteMessageAck,
|
|
67
|
-
'routeRequest',
|
|
68
|
-
async (routedMessage: RouteMessageWrapper) => {
|
|
69
|
-
if (this.stopped) {
|
|
70
|
-
return createRouteMessageAck(routedMessage, RouteMessageError.STOPPED)
|
|
71
|
-
} else {
|
|
72
|
-
return rpcLocal.routeRequest(routedMessage)
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
public async execute(
|
|
79
|
-
targetId: DhtAddress,
|
|
80
|
-
operation: RecursiveOperation,
|
|
81
|
-
excludedPeer?: DhtAddress,
|
|
82
|
-
waitForCompletion = true
|
|
83
|
-
): Promise<RecursiveOperationResult> {
|
|
84
|
-
if (this.stopped) {
|
|
85
|
-
return { closestNodes: [] }
|
|
86
|
-
}
|
|
87
|
-
const session = new RecursiveOperationSession({
|
|
88
|
-
transport: this.options.sessionTransport,
|
|
89
|
-
targetId,
|
|
90
|
-
localPeerDescriptor: this.options.localPeerDescriptor,
|
|
91
|
-
// TODO use options option or named constant?
|
|
92
|
-
waitedRoutingPathCompletions: this.options.connectionsView.getConnectionCount() > 1 ? 2 : 1,
|
|
93
|
-
operation,
|
|
94
|
-
// TODO would it make sense to give excludedPeer as one of the fields RecursiveOperationSession?
|
|
95
|
-
doRouteRequest: (routedMessage: RouteMessageWrapper) => {
|
|
96
|
-
return this.doRouteRequest(routedMessage, excludedPeer)
|
|
97
|
-
}
|
|
98
|
-
})
|
|
99
|
-
if (this.options.connectionsView.getConnectionCount() === 0) {
|
|
100
|
-
const dataEntries = Array.from(this.options.localDataStore.values(targetId))
|
|
101
|
-
session.onResponseReceived(
|
|
102
|
-
toNodeId(this.options.localPeerDescriptor),
|
|
103
|
-
[this.options.localPeerDescriptor],
|
|
104
|
-
[this.options.localPeerDescriptor],
|
|
105
|
-
dataEntries,
|
|
106
|
-
true
|
|
107
|
-
)
|
|
108
|
-
return session.getResults()
|
|
109
|
-
}
|
|
110
|
-
this.ongoingSessions.set(session.getId(), session)
|
|
111
|
-
if (waitForCompletion === true) {
|
|
112
|
-
try {
|
|
113
|
-
await runAndWaitForEvents3<RecursiveOperationSessionEvents>(
|
|
114
|
-
[() => session.start(this.options.serviceId)],
|
|
115
|
-
[[session, 'completed']],
|
|
116
|
-
// TODO use options option or named constant?
|
|
117
|
-
RECURSIVE_OPERATION_TIMEOUT
|
|
118
|
-
)
|
|
119
|
-
} catch (err) {
|
|
120
|
-
logger.debug('start failed', { err })
|
|
121
|
-
}
|
|
122
|
-
} else {
|
|
123
|
-
session.start(this.options.serviceId)
|
|
124
|
-
// Wait for delete operation to be sent out by the router
|
|
125
|
-
// TODO: Add a feature to wait for the router to pass the message?
|
|
126
|
-
await wait(50)
|
|
127
|
-
}
|
|
128
|
-
if (operation === RecursiveOperation.FETCH_DATA) {
|
|
129
|
-
const dataEntries = Array.from(this.options.localDataStore.values(targetId))
|
|
130
|
-
if (dataEntries.length > 0) {
|
|
131
|
-
this.sendResponse([this.options.localPeerDescriptor], this.options.localPeerDescriptor, session.getId(), [], dataEntries, true)
|
|
132
|
-
}
|
|
133
|
-
} else if (operation === RecursiveOperation.DELETE_DATA) {
|
|
134
|
-
this.options.localDataStore.markAsDeleted(targetId, toNodeId(this.options.localPeerDescriptor))
|
|
135
|
-
}
|
|
136
|
-
this.ongoingSessions.delete(session.getId())
|
|
137
|
-
session.stop()
|
|
138
|
-
return session.getResults()
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
private sendResponse(
|
|
142
|
-
routingPath: PeerDescriptor[],
|
|
143
|
-
targetPeerDescriptor: PeerDescriptor,
|
|
144
|
-
serviceId: ServiceID,
|
|
145
|
-
closestConnectedNodes: PeerDescriptor[],
|
|
146
|
-
dataEntries: DataEntry[],
|
|
147
|
-
noCloserNodesFound: boolean = false
|
|
148
|
-
): void {
|
|
149
|
-
const isOwnNode = areEqualPeerDescriptors(this.options.localPeerDescriptor, targetPeerDescriptor)
|
|
150
|
-
if (isOwnNode && this.ongoingSessions.has(serviceId)) {
|
|
151
|
-
this.ongoingSessions.get(serviceId)!
|
|
152
|
-
.onResponseReceived(
|
|
153
|
-
toNodeId(this.options.localPeerDescriptor),
|
|
154
|
-
routingPath,
|
|
155
|
-
closestConnectedNodes,
|
|
156
|
-
dataEntries,
|
|
157
|
-
noCloserNodesFound
|
|
158
|
-
)
|
|
159
|
-
} else {
|
|
160
|
-
// TODO use options option or named constant?
|
|
161
|
-
const remoteCommunicator = new ListeningRpcCommunicator(
|
|
162
|
-
serviceId,
|
|
163
|
-
this.options.sessionTransport,
|
|
164
|
-
{ rpcRequestTimeout: RECURSIVE_OPERATION_TIMEOUT }
|
|
165
|
-
)
|
|
166
|
-
const rpcRemote = new RecursiveOperationSessionRpcRemote(
|
|
167
|
-
this.options.localPeerDescriptor,
|
|
168
|
-
targetPeerDescriptor,
|
|
169
|
-
remoteCommunicator,
|
|
170
|
-
RecursiveOperationSessionRpcClient,
|
|
171
|
-
// TODO use options option or named constant?
|
|
172
|
-
10000
|
|
173
|
-
)
|
|
174
|
-
rpcRemote.sendResponse(routingPath, closestConnectedNodes, dataEntries, noCloserNodesFound)
|
|
175
|
-
remoteCommunicator.destroy()
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
private doRouteRequest(routedMessage: RouteMessageWrapper, excludedPeer?: DhtAddress): RouteMessageAck {
|
|
180
|
-
if (this.stopped) {
|
|
181
|
-
return createRouteMessageAck(routedMessage, RouteMessageError.STOPPED)
|
|
182
|
-
}
|
|
183
|
-
const targetId = toDhtAddress(routedMessage.target)
|
|
184
|
-
const request = (routedMessage.message!.body as { recursiveOperationRequest: RecursiveOperationRequest }).recursiveOperationRequest
|
|
185
|
-
// TODO use options option or named constant?
|
|
186
|
-
const closestConnectedNodes = this.getClosestConnectedNodes(targetId, 5)
|
|
187
|
-
const dataEntries = (request.operation === RecursiveOperation.FETCH_DATA)
|
|
188
|
-
? Array.from(this.options.localDataStore.values(targetId))
|
|
189
|
-
: []
|
|
190
|
-
if (request.operation === RecursiveOperation.DELETE_DATA) {
|
|
191
|
-
this.options.localDataStore.markAsDeleted(targetId, toNodeId(routedMessage.sourcePeer!))
|
|
192
|
-
}
|
|
193
|
-
if (areEqualBinaries(this.options.localPeerDescriptor.nodeId, routedMessage.target)) {
|
|
194
|
-
// TODO this is also very similar case to what we do at line 255, could simplify the code paths?
|
|
195
|
-
this.sendResponse(
|
|
196
|
-
routedMessage.routingPath,
|
|
197
|
-
routedMessage.sourcePeer!,
|
|
198
|
-
request.sessionId,
|
|
199
|
-
closestConnectedNodes,
|
|
200
|
-
dataEntries,
|
|
201
|
-
true
|
|
202
|
-
)
|
|
203
|
-
return createRouteMessageAck(routedMessage)
|
|
204
|
-
} else {
|
|
205
|
-
const ack = this.options.router.doRouteMessage(routedMessage, RoutingMode.RECURSIVE, excludedPeer)
|
|
206
|
-
if ((ack.error === undefined) || (ack.error === RouteMessageError.NO_TARGETS)) {
|
|
207
|
-
const noCloserContactsFound = (ack.error === RouteMessageError.NO_TARGETS) ||
|
|
208
|
-
(
|
|
209
|
-
closestConnectedNodes.length > 0
|
|
210
|
-
&& getPreviousPeer(routedMessage)
|
|
211
|
-
&& !this.isPeerCloserToIdThanSelf(closestConnectedNodes[0], targetId)
|
|
212
|
-
)
|
|
213
|
-
this.sendResponse(
|
|
214
|
-
routedMessage.routingPath,
|
|
215
|
-
routedMessage.sourcePeer!,
|
|
216
|
-
request.sessionId,
|
|
217
|
-
closestConnectedNodes,
|
|
218
|
-
dataEntries,
|
|
219
|
-
noCloserContactsFound
|
|
220
|
-
)
|
|
221
|
-
}
|
|
222
|
-
return ack
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
private getClosestConnectedNodes(referenceId: DhtAddress, limit: number): PeerDescriptor[] {
|
|
227
|
-
const connectedNodes = this.options.connectionsView.getConnections().map((c) => this.options.createDhtNodeRpcRemote(c))
|
|
228
|
-
const sorted = new SortedContactList<DhtNodeRpcRemote>({
|
|
229
|
-
referenceId,
|
|
230
|
-
maxSize: limit,
|
|
231
|
-
allowToContainReferenceId: true
|
|
232
|
-
})
|
|
233
|
-
sorted.addContacts(connectedNodes)
|
|
234
|
-
return sorted.getClosestContacts(limit).map((peer) => peer.getPeerDescriptor())
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
private isPeerCloserToIdThanSelf(peer: PeerDescriptor, nodeIdOrDataKey: DhtAddress): boolean {
|
|
238
|
-
const nodeIdOrDataKeyRaw = toDhtAddressRaw(nodeIdOrDataKey)
|
|
239
|
-
const distance1 = getDistance(peer.nodeId, nodeIdOrDataKeyRaw)
|
|
240
|
-
const distance2 = getDistance(this.options.localPeerDescriptor.nodeId, nodeIdOrDataKeyRaw)
|
|
241
|
-
return distance1 < distance2
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
public stop(): void {
|
|
245
|
-
this.stopped = true
|
|
246
|
-
this.ongoingSessions.forEach((session, _id) => {
|
|
247
|
-
session.stop()
|
|
248
|
-
})
|
|
249
|
-
this.ongoingSessions.clear()
|
|
250
|
-
}
|
|
251
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { Logger } from '@streamr/utils'
|
|
2
|
-
import { PeerDescriptor, RouteMessageAck, RouteMessageError, RouteMessageWrapper } from '../../../generated/packages/dht/protos/DhtRpc'
|
|
3
|
-
import { IRecursiveOperationRpc } from '../../../generated/packages/dht/protos/DhtRpc.server'
|
|
4
|
-
import { createRouteMessageAck } from '../routing/RouterRpcLocal'
|
|
5
|
-
import { getPreviousPeer } from '../routing/getPreviousPeer'
|
|
6
|
-
import { toNodeId } from '../../identifiers'
|
|
7
|
-
|
|
8
|
-
const logger = new Logger(module)
|
|
9
|
-
|
|
10
|
-
interface RecursiveOperationRpcLocalOptions {
|
|
11
|
-
doRouteRequest: (routedMessage: RouteMessageWrapper) => RouteMessageAck
|
|
12
|
-
addContact: (contact: PeerDescriptor, setActive?: boolean) => void
|
|
13
|
-
isMostLikelyDuplicate: (requestId: string) => boolean
|
|
14
|
-
addToDuplicateDetector: (requestId: string) => void
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export class RecursiveOperationRpcLocal implements IRecursiveOperationRpc {
|
|
18
|
-
|
|
19
|
-
private readonly options: RecursiveOperationRpcLocalOptions
|
|
20
|
-
|
|
21
|
-
constructor(options: RecursiveOperationRpcLocalOptions) {
|
|
22
|
-
this.options = options
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async routeRequest(routedMessage: RouteMessageWrapper): Promise<RouteMessageAck> {
|
|
26
|
-
if (this.options.isMostLikelyDuplicate(routedMessage.requestId)) {
|
|
27
|
-
return createRouteMessageAck(routedMessage, RouteMessageError.DUPLICATE)
|
|
28
|
-
}
|
|
29
|
-
const remoteNodeId = toNodeId(getPreviousPeer(routedMessage) ?? routedMessage.sourcePeer!)
|
|
30
|
-
logger.trace(`Received routeRequest call from ${remoteNodeId}`)
|
|
31
|
-
this.options.addToDuplicateDetector(routedMessage.requestId)
|
|
32
|
-
return this.options.doRouteRequest(routedMessage)
|
|
33
|
-
}
|
|
34
|
-
}
|