@streamr/dht 100.2.4-beta.0 → 100.2.4
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/package.json +8 -9
- package/dist/src/connection/ConnectionManager.d.ts +2 -1
- package/dist/src/connection/ConnectionManager.js +2 -10
- package/dist/src/connection/ConnectionManager.js.map +1 -1
- package/dist/src/connection/ConnectionsView.d.ts +7 -0
- package/dist/src/connection/ConnectionsView.js +3 -0
- package/dist/src/connection/ConnectionsView.js.map +1 -0
- package/dist/src/connection/ConnectorFacade.d.ts +2 -1
- package/dist/src/connection/ConnectorFacade.js +5 -4
- package/dist/src/connection/ConnectorFacade.js.map +1 -1
- package/dist/src/connection/connectivityRequestHandler.d.ts +2 -1
- package/dist/src/connection/connectivityRequestHandler.js +12 -5
- package/dist/src/connection/connectivityRequestHandler.js.map +1 -1
- package/dist/src/connection/{ManagedWebrtcConnection.d.ts → webrtc/ManagedWebrtcConnection.d.ts} +3 -3
- package/dist/src/connection/{ManagedWebrtcConnection.js → webrtc/ManagedWebrtcConnection.js} +2 -2
- package/dist/src/connection/webrtc/ManagedWebrtcConnection.js.map +1 -0
- package/dist/src/connection/webrtc/NodeWebrtcConnection.js +3 -26
- package/dist/src/connection/webrtc/NodeWebrtcConnection.js.map +1 -1
- package/dist/src/connection/webrtc/WebrtcConnector.js +1 -1
- package/dist/src/connection/webrtc/WebrtcConnector.js.map +1 -1
- package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.d.ts +1 -1
- package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js +1 -1
- package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js.map +1 -1
- package/dist/src/connection/websocket/WebsocketConnector.d.ts +2 -0
- package/dist/src/connection/websocket/WebsocketConnector.js +21 -13
- package/dist/src/connection/websocket/WebsocketConnector.js.map +1 -1
- package/dist/src/connection/websocket/WebsocketServerConnection.d.ts +2 -1
- package/dist/src/connection/websocket/WebsocketServerConnection.js +4 -0
- package/dist/src/connection/websocket/WebsocketServerConnection.js.map +1 -1
- package/dist/src/dht/DhtNode.d.ts +14 -11
- package/dist/src/dht/DhtNode.js +74 -61
- package/dist/src/dht/DhtNode.js.map +1 -1
- package/dist/src/dht/DhtNodeRpcLocal.d.ts +3 -3
- package/dist/src/dht/DhtNodeRpcLocal.js +5 -2
- package/dist/src/dht/DhtNodeRpcLocal.js.map +1 -1
- package/dist/src/dht/PeerManager.d.ts +14 -14
- package/dist/src/dht/PeerManager.js +51 -42
- package/dist/src/dht/PeerManager.js.map +1 -1
- package/dist/src/dht/contact/ContactList.d.ts +1 -2
- package/dist/src/dht/contact/ContactList.js +1 -3
- package/dist/src/dht/contact/ContactList.js.map +1 -1
- package/dist/src/dht/contact/RandomContactList.d.ts +1 -1
- package/dist/src/dht/contact/RandomContactList.js +7 -4
- package/dist/src/dht/contact/RandomContactList.js.map +1 -1
- package/dist/src/dht/contact/getClosestNodes.d.ts +6 -0
- package/dist/src/dht/contact/{getClosestContacts.js → getClosestNodes.js} +7 -6
- package/dist/src/dht/contact/getClosestNodes.js.map +1 -0
- package/dist/src/dht/discovery/DiscoverySession.d.ts +4 -0
- package/dist/src/dht/discovery/DiscoverySession.js +27 -21
- package/dist/src/dht/discovery/DiscoverySession.js.map +1 -1
- package/dist/src/dht/discovery/PeerDiscovery.d.ts +8 -5
- package/dist/src/dht/discovery/PeerDiscovery.js +34 -24
- package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
- package/dist/src/dht/discovery/RingDiscoverySession.d.ts +4 -4
- package/dist/src/dht/discovery/RingDiscoverySession.js +10 -19
- package/dist/src/dht/discovery/RingDiscoverySession.js.map +1 -1
- package/dist/src/dht/recursive-operation/RecursiveOperationManager.d.ts +2 -0
- package/dist/src/dht/recursive-operation/RecursiveOperationManager.js +3 -3
- package/dist/src/dht/recursive-operation/RecursiveOperationManager.js.map +1 -1
- package/dist/src/dht/store/StoreManager.d.ts +5 -6
- package/dist/src/dht/store/StoreManager.js +21 -76
- package/dist/src/dht/store/StoreManager.js.map +1 -1
- package/dist/src/dht/store/StoreRpcLocal.d.ts +5 -2
- package/dist/src/dht/store/StoreRpcLocal.js +22 -5
- package/dist/src/dht/store/StoreRpcLocal.js.map +1 -1
- package/dist/src/exports.d.ts +2 -1
- package/dist/src/exports.js.map +1 -1
- package/dist/src/helpers/version.d.ts +1 -1
- package/dist/src/helpers/version.js +1 -1
- package/dist/src/proto/google/protobuf/any.d.ts +8 -5
- package/dist/src/proto/google/protobuf/any.js.map +1 -1
- package/dist/src/proto/google/protobuf/empty.d.ts +0 -1
- package/dist/src/proto/google/protobuf/empty.js.map +1 -1
- package/dist/src/proto/google/protobuf/timestamp.d.ts +10 -1
- package/dist/src/proto/google/protobuf/timestamp.js.map +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +8 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.js +3 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -1
- package/dist/src/transport/ITransport.d.ts +0 -4
- package/dist/src/transport/ITransport.js.map +1 -1
- package/karma.config.js +2 -2
- package/package.json +8 -9
- package/protos/DhtRpc.proto +2 -0
- package/src/connection/ConnectionManager.ts +4 -10
- package/src/connection/ConnectionsView.ts +8 -0
- package/src/connection/ConnectorFacade.ts +7 -5
- package/src/connection/connectivityRequestHandler.ts +18 -5
- package/src/connection/{ManagedWebrtcConnection.ts → webrtc/ManagedWebrtcConnection.ts} +4 -4
- package/src/connection/webrtc/NodeWebrtcConnection.ts +3 -3
- package/src/connection/webrtc/WebrtcConnector.ts +1 -1
- package/src/connection/webrtc/WebrtcConnectorRpcLocal.ts +1 -1
- package/src/connection/websocket/WebsocketConnector.ts +26 -16
- package/src/connection/websocket/WebsocketServerConnection.ts +6 -1
- package/src/dht/DhtNode.ts +102 -74
- package/src/dht/DhtNodeRpcLocal.ts +12 -5
- package/src/dht/PeerManager.ts +58 -49
- package/src/dht/contact/ContactList.ts +1 -4
- package/src/dht/contact/RandomContactList.ts +7 -5
- package/src/dht/contact/{getClosestContacts.ts → getClosestNodes.ts} +8 -6
- package/src/dht/discovery/DiscoverySession.ts +34 -22
- package/src/dht/discovery/PeerDiscovery.ts +44 -30
- package/src/dht/discovery/RingDiscoverySession.ts +15 -29
- package/src/dht/recursive-operation/RecursiveOperationManager.ts +5 -3
- package/src/dht/store/StoreManager.ts +46 -84
- package/src/dht/store/StoreRpcLocal.ts +32 -9
- package/src/exports.ts +2 -1
- package/src/helpers/version.ts +1 -1
- package/src/proto/google/protobuf/any.ts +8 -5
- package/src/proto/google/protobuf/empty.ts +0 -1
- package/src/proto/google/protobuf/timestamp.ts +10 -1
- package/src/proto/packages/dht/protos/DhtRpc.ts +11 -1
- package/src/transport/ITransport.ts +0 -4
- package/test/benchmark/Find.test.ts +1 -1
- package/test/end-to-end/GeoIpLayer0.test.ts +55 -0
- package/test/end-to-end/Layer0-Layer1.test.ts +4 -4
- package/test/end-to-end/Layer0Webrtc-Layer1.test.ts +11 -5
- package/test/end-to-end/Layer1-Scale-WebSocket.test.ts +7 -1
- package/test/end-to-end/Layer1-Scale-Webrtc.test.ts +11 -2
- package/test/integration/ConnectionLocking.test.ts +1 -1
- package/test/integration/ConnectionManager.test.ts +3 -3
- package/test/integration/ConnectivityChecking.test.ts +2 -2
- package/test/integration/DhtNode.test.ts +5 -20
- package/test/integration/GeoIpConnectivityChecking.test.ts +71 -0
- package/test/integration/Layer1-scale.test.ts +6 -6
- package/test/integration/RouteMessage.test.ts +4 -0
- package/test/integration/ScaleDownDht.test.ts +1 -1
- package/test/integration/SimultaneousConnections.test.ts +2 -2
- package/test/integration/WebrtcConnectionManagement.test.ts +1 -1
- package/test/integration/WebsocketConnectionManagement.test.ts +1 -1
- package/test/integration/rpc-connections-over-webrpc.test.ts +1 -1
- package/test/unit/AutoCertifierClientFacade.test.ts +1 -1
- package/test/unit/DiscoverySession.test.ts +4 -2
- package/test/unit/PeerManager.test.ts +45 -51
- package/test/unit/RandomContactList.test.ts +10 -0
- package/test/unit/RecursiveOperationManager.test.ts +4 -2
- package/test/unit/StoreManager.test.ts +42 -34
- package/test/unit/StoreRpcLocal.test.ts +167 -0
- package/test/unit/WebsocketConnector.test.ts +1 -1
- package/test/unit/connectivityRequestHandler.test.ts +1 -1
- package/test/unit/getClosestNodes.test.ts +30 -0
- package/test/utils/FakeTransport.ts +4 -2
- package/test/utils/mock/MockConnectionsView.ts +18 -0
- package/test/utils/mock/{Transport.ts → MockTransport.ts} +0 -15
- package/test/utils/utils.ts +4 -1
- package/tsconfig.jest.json +2 -1
- package/tsconfig.node.json +2 -1
- package/dist/src/connection/ManagedWebrtcConnection.js.map +0 -1
- package/dist/src/dht/contact/getClosestContacts.d.ts +0 -7
- package/dist/src/dht/contact/getClosestContacts.js.map +0 -1
- package/test/unit/getClosestContacts.test.ts +0 -28
- /package/test/utils/mock/{Router.ts → MockRouter.ts} +0 -0
|
@@ -1,19 +1,14 @@
|
|
|
1
|
-
import { Logger,
|
|
2
|
-
import EventEmitter from 'eventemitter3'
|
|
1
|
+
import { Gate, Logger, withTimeout } from '@streamr/utils'
|
|
3
2
|
import { v4 } from 'uuid'
|
|
3
|
+
import { DhtAddress, getNodeIdFromPeerDescriptor } from '../../identifiers'
|
|
4
4
|
import { PeerDescriptor } from '../../proto/packages/dht/protos/DhtRpc'
|
|
5
|
-
import { PeerManager } from '../PeerManager'
|
|
6
5
|
import { DhtNodeRpcRemote } from '../DhtNodeRpcRemote'
|
|
7
|
-
import {
|
|
8
|
-
import { RingId, RingIdRaw, getLeftDistance, getRingIdFromPeerDescriptor, getRingIdFromRaw } from '../contact/ringIdentifiers'
|
|
6
|
+
import { PeerManager } from '../PeerManager'
|
|
9
7
|
import { RingContacts } from '../contact/RingContactList'
|
|
8
|
+
import { RingId, RingIdRaw, getLeftDistance, getRingIdFromPeerDescriptor, getRingIdFromRaw } from '../contact/ringIdentifiers'
|
|
10
9
|
|
|
11
10
|
const logger = new Logger(module)
|
|
12
11
|
|
|
13
|
-
interface RingDiscoverySessionEvents {
|
|
14
|
-
discoveryCompleted: () => void
|
|
15
|
-
}
|
|
16
|
-
|
|
17
12
|
interface RingDiscoverySessionConfig {
|
|
18
13
|
targetId: RingIdRaw
|
|
19
14
|
parallelism: number
|
|
@@ -21,15 +16,15 @@ interface RingDiscoverySessionConfig {
|
|
|
21
16
|
peerManager: PeerManager
|
|
22
17
|
// Note that contacted peers will be mutated by the DiscoverySession or other parallel sessions
|
|
23
18
|
contactedPeers: Set<DhtAddress>
|
|
19
|
+
abortSignal: AbortSignal
|
|
24
20
|
}
|
|
25
21
|
|
|
26
22
|
export class RingDiscoverySession {
|
|
27
23
|
|
|
28
24
|
public readonly id = v4()
|
|
29
|
-
private stopped = false
|
|
30
|
-
private emitter = new EventEmitter<RingDiscoverySessionEvents>()
|
|
31
25
|
private noProgressCounter = 0
|
|
32
26
|
private ongoingRequests: Set<DhtAddress> = new Set()
|
|
27
|
+
private doneGate = new Gate(false)
|
|
33
28
|
private readonly config: RingDiscoverySessionConfig
|
|
34
29
|
private numContactedPeers = 0
|
|
35
30
|
private targetIdAsRingId: RingId
|
|
@@ -40,7 +35,7 @@ export class RingDiscoverySession {
|
|
|
40
35
|
}
|
|
41
36
|
|
|
42
37
|
private addContacts(contacts: PeerDescriptor[]): void {
|
|
43
|
-
if (this.
|
|
38
|
+
if (this.config.abortSignal.aborted || this.doneGate.isOpen()) {
|
|
44
39
|
return
|
|
45
40
|
}
|
|
46
41
|
for (const contact of contacts) {
|
|
@@ -49,7 +44,7 @@ export class RingDiscoverySession {
|
|
|
49
44
|
}
|
|
50
45
|
|
|
51
46
|
private async fetchClosestContactsFromRemote(contact: DhtNodeRpcRemote): Promise<RingContacts> {
|
|
52
|
-
if (this.
|
|
47
|
+
if (this.config.abortSignal.aborted || this.doneGate.isOpen()) {
|
|
53
48
|
return { left: [], right: [] }
|
|
54
49
|
}
|
|
55
50
|
logger.trace(`Getting closest ring peers from contact: ${getNodeIdFromPeerDescriptor(contact.getPeerDescriptor())}`)
|
|
@@ -94,7 +89,7 @@ export class RingDiscoverySession {
|
|
|
94
89
|
}
|
|
95
90
|
|
|
96
91
|
private findMoreContacts(): void {
|
|
97
|
-
if (this.
|
|
92
|
+
if (this.config.abortSignal.aborted || this.doneGate.isOpen()) {
|
|
98
93
|
return
|
|
99
94
|
}
|
|
100
95
|
const uncontacted = this.config.peerManager.getClosestRingContactsTo(
|
|
@@ -104,8 +99,7 @@ export class RingDiscoverySession {
|
|
|
104
99
|
)
|
|
105
100
|
if ((uncontacted.left.length === 0 && uncontacted.right.length === 0)
|
|
106
101
|
|| this.noProgressCounter >= this.config.noProgressLimit) {
|
|
107
|
-
this.
|
|
108
|
-
this.stopped = true
|
|
102
|
+
this.doneGate.open()
|
|
109
103
|
return
|
|
110
104
|
}
|
|
111
105
|
// ask from both sides equally
|
|
@@ -143,20 +137,12 @@ export class RingDiscoverySession {
|
|
|
143
137
|
}
|
|
144
138
|
|
|
145
139
|
public async findClosestNodes(timeout: number): Promise<void> {
|
|
146
|
-
if (this.config.peerManager.
|
|
140
|
+
if (this.config.peerManager.getNearbyContactCount(this.config.contactedPeers) === 0) {
|
|
147
141
|
return
|
|
148
142
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
timeout
|
|
154
|
-
)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
public stop(): void {
|
|
158
|
-
this.stopped = true
|
|
159
|
-
this.emitter.emit('discoveryCompleted')
|
|
160
|
-
this.emitter.removeAllListeners()
|
|
143
|
+
setImmediate(() => {
|
|
144
|
+
this.findMoreContacts()
|
|
145
|
+
})
|
|
146
|
+
await withTimeout(this.doneGate.waitUntilOpen(), timeout, 'discovery session timed out', this.config.abortSignal)
|
|
161
147
|
}
|
|
162
148
|
}
|
|
@@ -25,11 +25,13 @@ import { ServiceID } from '../../types/ServiceID'
|
|
|
25
25
|
import { RecursiveOperationRpcLocal } from './RecursiveOperationRpcLocal'
|
|
26
26
|
import { DhtAddress, areEqualPeerDescriptors, getDhtAddressFromRaw, getNodeIdFromPeerDescriptor, getRawFromDhtAddress } from '../../identifiers'
|
|
27
27
|
import { getDistance } from '../PeerManager'
|
|
28
|
+
import { ConnectionsView } from '../../exports'
|
|
28
29
|
|
|
29
30
|
interface RecursiveOperationManagerConfig {
|
|
30
31
|
rpcCommunicator: RoutingRpcCommunicator
|
|
31
32
|
sessionTransport: ITransport
|
|
32
33
|
router: Router
|
|
34
|
+
connectionsView: ConnectionsView
|
|
33
35
|
localPeerDescriptor: PeerDescriptor
|
|
34
36
|
serviceId: ServiceID
|
|
35
37
|
localDataStore: LocalDataStore
|
|
@@ -87,14 +89,14 @@ export class RecursiveOperationManager {
|
|
|
87
89
|
targetId,
|
|
88
90
|
localPeerDescriptor: this.config.localPeerDescriptor,
|
|
89
91
|
// TODO use config option or named constant?
|
|
90
|
-
waitedRoutingPathCompletions: this.config.
|
|
92
|
+
waitedRoutingPathCompletions: this.config.connectionsView.getConnectionCount() > 1 ? 2 : 1,
|
|
91
93
|
operation,
|
|
92
94
|
// TODO would it make sense to give excludedPeer as one of the fields RecursiveOperationSession?
|
|
93
95
|
doRouteRequest: (routedMessage: RouteMessageWrapper) => {
|
|
94
96
|
return this.doRouteRequest(routedMessage, excludedPeer)
|
|
95
97
|
}
|
|
96
98
|
})
|
|
97
|
-
if (this.config.
|
|
99
|
+
if (this.config.connectionsView.getConnectionCount() === 0) {
|
|
98
100
|
const dataEntries = Array.from(this.config.localDataStore.values(targetId))
|
|
99
101
|
session.onResponseReceived(
|
|
100
102
|
getNodeIdFromPeerDescriptor(this.config.localPeerDescriptor),
|
|
@@ -218,7 +220,7 @@ export class RecursiveOperationManager {
|
|
|
218
220
|
}
|
|
219
221
|
|
|
220
222
|
private getClosestConnectedNodes(referenceId: DhtAddress, limit: number): PeerDescriptor[] {
|
|
221
|
-
const connectedNodes = this.config.
|
|
223
|
+
const connectedNodes = this.config.connectionsView.getConnections().map((c) => this.config.createDhtNodeRpcRemote(c))
|
|
222
224
|
const sorted = new SortedContactList<DhtNodeRpcRemote>({
|
|
223
225
|
referenceId,
|
|
224
226
|
maxSize: limit,
|
|
@@ -1,21 +1,28 @@
|
|
|
1
|
+
import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
|
|
2
|
+
import { Logger } from '@streamr/utils'
|
|
1
3
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
DhtAddress,
|
|
5
|
+
areEqualPeerDescriptors,
|
|
6
|
+
getDhtAddressFromRaw,
|
|
7
|
+
getNodeIdFromPeerDescriptor,
|
|
8
|
+
getRawFromDhtAddress
|
|
9
|
+
} from '../../identifiers'
|
|
5
10
|
import { Any } from '../../proto/google/protobuf/any'
|
|
6
|
-
import {
|
|
11
|
+
import { Timestamp } from '../../proto/google/protobuf/timestamp'
|
|
12
|
+
import {
|
|
13
|
+
DataEntry,
|
|
14
|
+
PeerDescriptor,
|
|
15
|
+
RecursiveOperation,
|
|
16
|
+
ReplicateDataRequest,
|
|
17
|
+
StoreDataRequest, StoreDataResponse
|
|
18
|
+
} from '../../proto/packages/dht/protos/DhtRpc'
|
|
7
19
|
import { RoutingRpcCommunicator } from '../../transport/RoutingRpcCommunicator'
|
|
20
|
+
import { ServiceID } from '../../types/ServiceID'
|
|
21
|
+
import { getClosestNodes } from '../contact/getClosestNodes'
|
|
8
22
|
import { RecursiveOperationManager } from '../recursive-operation/RecursiveOperationManager'
|
|
9
|
-
import { Logger, executeSafePromise } from '@streamr/utils'
|
|
10
23
|
import { LocalDataStore } from './LocalDataStore'
|
|
11
|
-
import { StoreRpcRemote } from './StoreRpcRemote'
|
|
12
|
-
import { Timestamp } from '../../proto/google/protobuf/timestamp'
|
|
13
|
-
import { SortedContactList } from '../contact/SortedContactList'
|
|
14
|
-
import { Contact } from '../contact/Contact'
|
|
15
|
-
import { ServiceID } from '../../types/ServiceID'
|
|
16
|
-
import { DhtAddress, areEqualPeerDescriptors, getDhtAddressFromRaw, getNodeIdFromPeerDescriptor, getRawFromDhtAddress } from '../../identifiers'
|
|
17
24
|
import { StoreRpcLocal } from './StoreRpcLocal'
|
|
18
|
-
import {
|
|
25
|
+
import { StoreRpcRemote } from './StoreRpcRemote'
|
|
19
26
|
|
|
20
27
|
interface StoreManagerConfig {
|
|
21
28
|
rpcCommunicator: RoutingRpcCommunicator
|
|
@@ -25,7 +32,7 @@ interface StoreManagerConfig {
|
|
|
25
32
|
serviceId: ServiceID
|
|
26
33
|
highestTtl: number
|
|
27
34
|
redundancyFactor: number
|
|
28
|
-
|
|
35
|
+
getNeighbors: () => ReadonlyArray<PeerDescriptor>
|
|
29
36
|
createRpcRemote: (contact: PeerDescriptor) => StoreRpcRemote
|
|
30
37
|
}
|
|
31
38
|
|
|
@@ -42,9 +49,10 @@ export class StoreManager {
|
|
|
42
49
|
|
|
43
50
|
private registerLocalRpcMethods() {
|
|
44
51
|
const rpcLocal = new StoreRpcLocal({
|
|
52
|
+
localPeerDescriptor: this.config.localPeerDescriptor,
|
|
45
53
|
localDataStore: this.config.localDataStore,
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
replicateDataToContact: (dataEntry: DataEntry, contact: PeerDescriptor) => this.replicateDataToContact(dataEntry, contact),
|
|
55
|
+
getStorers: (dataKey: DhtAddress) => this.getStorers(dataKey)
|
|
48
56
|
})
|
|
49
57
|
this.config.rpcCommunicator.registerRpcMethod(StoreDataRequest, StoreDataResponse, 'storeData',
|
|
50
58
|
(request: StoreDataRequest) => rpcLocal.storeData(request))
|
|
@@ -58,31 +66,19 @@ export class StoreManager {
|
|
|
58
66
|
}
|
|
59
67
|
}
|
|
60
68
|
|
|
61
|
-
private replicateAndUpdateStaleState(
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
allowToContainReferenceId: true
|
|
68
|
-
})
|
|
69
|
-
sortedList.addContact(new Contact(this.config.localPeerDescriptor))
|
|
70
|
-
closestToData.forEach((neighbor) => {
|
|
71
|
-
if (newNodeId !== getNodeIdFromPeerDescriptor(neighbor)) {
|
|
72
|
-
sortedList.addContact(new Contact(neighbor))
|
|
73
|
-
}
|
|
74
|
-
})
|
|
75
|
-
const selfIsPrimaryStorer = (sortedList.getClosestContactId() === getNodeIdFromPeerDescriptor(this.config.localPeerDescriptor))
|
|
76
|
-
if (selfIsPrimaryStorer) {
|
|
77
|
-
sortedList.addContact(new Contact(newNode))
|
|
78
|
-
if (sortedList.getContact(newNodeId) !== undefined) {
|
|
69
|
+
private replicateAndUpdateStaleState(dataKey: DhtAddress, newNode: PeerDescriptor): void {
|
|
70
|
+
const storers = this.getStorers(dataKey)
|
|
71
|
+
const storersBeforeContactAdded = storers.filter((p) => !areEqualPeerDescriptors(p, newNode))
|
|
72
|
+
const selfWasPrimaryStorer = areEqualPeerDescriptors(storersBeforeContactAdded[0], this.config.localPeerDescriptor)
|
|
73
|
+
if (selfWasPrimaryStorer) {
|
|
74
|
+
if (storers.some((p) => areEqualPeerDescriptors(p, newNode))) {
|
|
79
75
|
setImmediate(async () => {
|
|
80
|
-
const dataEntries = Array.from(this.config.localDataStore.values(
|
|
76
|
+
const dataEntries = Array.from(this.config.localDataStore.values(dataKey))
|
|
81
77
|
await Promise.all(dataEntries.map(async (dataEntry) => this.replicateDataToContact(dataEntry, newNode)))
|
|
82
78
|
})
|
|
83
79
|
}
|
|
84
|
-
} else if (!
|
|
85
|
-
this.config.localDataStore.setAllEntriesAsStale(
|
|
80
|
+
} else if (!storers.some((p) => areEqualPeerDescriptors(p, this.config.localPeerDescriptor))) {
|
|
81
|
+
this.config.localDataStore.setAllEntriesAsStale(dataKey)
|
|
86
82
|
}
|
|
87
83
|
}
|
|
88
84
|
|
|
@@ -137,21 +133,15 @@ export class StoreManager {
|
|
|
137
133
|
return successfulNodes
|
|
138
134
|
}
|
|
139
135
|
|
|
140
|
-
private selfIsWithinRedundancyFactor(dataKey: DhtAddress): boolean {
|
|
141
|
-
const closestNeighbors = this.config.getClosestNeighborsTo(dataKey, this.config.redundancyFactor)
|
|
142
|
-
if (closestNeighbors.length < this.config.redundancyFactor) {
|
|
143
|
-
return true
|
|
144
|
-
} else {
|
|
145
|
-
const furthestCloseNeighbor = closestNeighbors[closestNeighbors.length - 1]
|
|
146
|
-
const dataKeyRaw = getRawFromDhtAddress(dataKey)
|
|
147
|
-
return getDistance(dataKeyRaw, this.config.localPeerDescriptor.nodeId) < getDistance(dataKeyRaw, furthestCloseNeighbor.nodeId)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
136
|
private async replicateDataToClosestNodes(): Promise<void> {
|
|
152
137
|
const dataEntries = Array.from(this.config.localDataStore.values())
|
|
153
138
|
await Promise.all(dataEntries.map(async (dataEntry) => {
|
|
154
|
-
const
|
|
139
|
+
const dataKey = getDhtAddressFromRaw(dataEntry.key)
|
|
140
|
+
const neighbors = getClosestNodes(
|
|
141
|
+
dataKey,
|
|
142
|
+
this.config.getNeighbors(),
|
|
143
|
+
{ maxCount: this.config.redundancyFactor }
|
|
144
|
+
)
|
|
155
145
|
await Promise.all(neighbors.map(async (neighbor) => {
|
|
156
146
|
const rpcRemote = this.config.createRpcRemote(neighbor)
|
|
157
147
|
try {
|
|
@@ -163,43 +153,15 @@ export class StoreManager {
|
|
|
163
153
|
}))
|
|
164
154
|
}
|
|
165
155
|
|
|
166
|
-
private
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const sortedList = new SortedContactList<Contact>({
|
|
174
|
-
referenceId: key,
|
|
175
|
-
maxSize: this.config.redundancyFactor,
|
|
176
|
-
allowToContainReferenceId: true
|
|
177
|
-
})
|
|
178
|
-
sortedList.addContact(new Contact(this.config.localPeerDescriptor))
|
|
179
|
-
closestToData.forEach((neighbor) => {
|
|
180
|
-
sortedList.addContact(new Contact(neighbor))
|
|
181
|
-
})
|
|
182
|
-
const selfIsPrimaryStorer = (sortedList.getClosestContactId() === localNodeId)
|
|
183
|
-
const targetLimit = selfIsPrimaryStorer
|
|
184
|
-
// if we are the closest to the data, replicate to all storageRedundancyFactor nearest
|
|
185
|
-
? undefined
|
|
186
|
-
// if we are not the closest node to the data, replicate only to the closest one to the data
|
|
187
|
-
: 1
|
|
188
|
-
const targets = sortedList.getClosestContacts(targetLimit)
|
|
189
|
-
targets.forEach((contact) => {
|
|
190
|
-
const contactNodeId = contact.getNodeId()
|
|
191
|
-
if ((incomingNodeId !== contactNodeId) && (localNodeId !== contactNodeId)) {
|
|
192
|
-
setImmediate(() => {
|
|
193
|
-
executeSafePromise(async () => {
|
|
194
|
-
await this.replicateDataToContact(dataEntry, contact.getPeerDescriptor())
|
|
195
|
-
logger.trace('replicateDataToContact() returned', {
|
|
196
|
-
node: contactNodeId,
|
|
197
|
-
replicateOnlyToClosest: !selfIsPrimaryStorer
|
|
198
|
-
})
|
|
199
|
-
})
|
|
200
|
-
})
|
|
156
|
+
private getStorers(dataKey: DhtAddress, excludedNode?: PeerDescriptor): PeerDescriptor[] {
|
|
157
|
+
return getClosestNodes(
|
|
158
|
+
dataKey,
|
|
159
|
+
[...this.config.getNeighbors(), this.config.localPeerDescriptor],
|
|
160
|
+
{
|
|
161
|
+
maxCount: this.config.redundancyFactor,
|
|
162
|
+
excludedNodeIds: excludedNode !== undefined ? new Set([getNodeIdFromPeerDescriptor(excludedNode)]) : undefined
|
|
201
163
|
}
|
|
202
|
-
|
|
164
|
+
)
|
|
203
165
|
}
|
|
204
166
|
|
|
205
167
|
async destroy(): Promise<void> {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
|
|
2
|
-
import { Logger } from '@streamr/utils'
|
|
2
|
+
import { Logger, executeSafePromise } from '@streamr/utils'
|
|
3
3
|
import { Empty } from '../../proto/google/protobuf/empty'
|
|
4
4
|
import { Timestamp } from '../../proto/google/protobuf/timestamp'
|
|
5
5
|
import {
|
|
@@ -11,12 +11,13 @@ import {
|
|
|
11
11
|
import { IStoreRpc } from '../../proto/packages/dht/protos/DhtRpc.server'
|
|
12
12
|
import { DhtCallContext } from '../../rpc-protocol/DhtCallContext'
|
|
13
13
|
import { LocalDataStore } from './LocalDataStore'
|
|
14
|
-
import { DhtAddress, getDhtAddressFromRaw } from '../../identifiers'
|
|
14
|
+
import { areEqualPeerDescriptors, DhtAddress, getDhtAddressFromRaw } from '../../identifiers'
|
|
15
15
|
|
|
16
16
|
interface StoreRpcLocalConfig {
|
|
17
17
|
localDataStore: LocalDataStore
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
localPeerDescriptor: PeerDescriptor
|
|
19
|
+
replicateDataToContact: (dataEntry: DataEntry, contact: PeerDescriptor) => Promise<void>
|
|
20
|
+
getStorers: (key: DhtAddress) => ReadonlyArray<PeerDescriptor>
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
const logger = new Logger(module)
|
|
@@ -32,7 +33,7 @@ export class StoreRpcLocal implements IStoreRpc {
|
|
|
32
33
|
async storeData(request: StoreDataRequest): Promise<StoreDataResponse> {
|
|
33
34
|
logger.trace('storeData()')
|
|
34
35
|
const key = getDhtAddressFromRaw(request.key)
|
|
35
|
-
const
|
|
36
|
+
const isLocalNodeStorer = this.isLocalNodeStorer(key)
|
|
36
37
|
this.config.localDataStore.storeEntry({
|
|
37
38
|
key: request.key,
|
|
38
39
|
data: request.data,
|
|
@@ -40,10 +41,10 @@ export class StoreRpcLocal implements IStoreRpc {
|
|
|
40
41
|
createdAt: request.createdAt,
|
|
41
42
|
storedAt: Timestamp.now(),
|
|
42
43
|
ttl: request.ttl,
|
|
43
|
-
stale: !
|
|
44
|
+
stale: !isLocalNodeStorer,
|
|
44
45
|
deleted: false
|
|
45
46
|
})
|
|
46
|
-
if (!
|
|
47
|
+
if (!isLocalNodeStorer) {
|
|
47
48
|
this.config.localDataStore.setAllEntriesAsStale(key)
|
|
48
49
|
}
|
|
49
50
|
return {}
|
|
@@ -54,13 +55,35 @@ export class StoreRpcLocal implements IStoreRpc {
|
|
|
54
55
|
const dataEntry = request.entry!
|
|
55
56
|
const wasStored = this.config.localDataStore.storeEntry(dataEntry)
|
|
56
57
|
if (wasStored) {
|
|
57
|
-
this.
|
|
58
|
+
this.replicateDataToNeighbors((context as DhtCallContext).incomingSourceDescriptor!, request.entry!)
|
|
58
59
|
}
|
|
59
60
|
const key = getDhtAddressFromRaw(dataEntry.key)
|
|
60
|
-
if (!this.
|
|
61
|
+
if (!this.isLocalNodeStorer(key)) {
|
|
61
62
|
this.config.localDataStore.setAllEntriesAsStale(key)
|
|
62
63
|
}
|
|
63
64
|
logger.trace('server-side replicateData() at end')
|
|
64
65
|
return {}
|
|
65
66
|
}
|
|
67
|
+
|
|
68
|
+
private isLocalNodeStorer(dataKey: DhtAddress): boolean {
|
|
69
|
+
return this.config.getStorers(dataKey).some((p) => areEqualPeerDescriptors(p, this.config.localPeerDescriptor))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private replicateDataToNeighbors(requestor: PeerDescriptor, dataEntry: DataEntry): void {
|
|
73
|
+
const dataKey = getDhtAddressFromRaw(dataEntry.key)
|
|
74
|
+
const storers = this.config.getStorers(dataKey)
|
|
75
|
+
const isLocalNodePrimaryStorer = areEqualPeerDescriptors(storers[0], this.config.localPeerDescriptor)
|
|
76
|
+
// If we are the closest to the data, get storageRedundancyFactor - 1 nearest node to the data, and
|
|
77
|
+
// replicate to all those node. Otherwise replicate only to the one closest one. And never replicate
|
|
78
|
+
// to the requestor nor to itself.
|
|
79
|
+
const targets = (isLocalNodePrimaryStorer ? storers : [storers[0]]).filter(
|
|
80
|
+
(p) => !areEqualPeerDescriptors(p, requestor) && !areEqualPeerDescriptors(p, this.config.localPeerDescriptor)
|
|
81
|
+
)
|
|
82
|
+
targets.forEach((target) => {
|
|
83
|
+
setImmediate(() => {
|
|
84
|
+
executeSafePromise(() => this.config.replicateDataToContact(dataEntry, target))
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
66
89
|
}
|
package/src/exports.ts
CHANGED
|
@@ -5,8 +5,9 @@ export { Simulator, LatencyType } from './connection/simulator/Simulator'
|
|
|
5
5
|
export { SimulatorTransport } from './connection/simulator/SimulatorTransport'
|
|
6
6
|
export { getRandomRegion, getRegionDelayMatrix } from './connection/simulator/pings'
|
|
7
7
|
export { PeerDescriptor, Message, NodeType, DataEntry } from './proto/packages/dht/protos/DhtRpc'
|
|
8
|
-
export { ITransport } from './transport/ITransport'
|
|
8
|
+
export { ITransport, TransportEvents } from './transport/ITransport'
|
|
9
9
|
export { ConnectionManager, ConnectionLocker, PortRange, TlsCertificate } from './connection/ConnectionManager'
|
|
10
|
+
export { ConnectionsView } from './connection/ConnectionsView'
|
|
10
11
|
export { LockID } from './connection/ConnectionLockStates'
|
|
11
12
|
export { DefaultConnectorFacade } from './connection/ConnectorFacade'
|
|
12
13
|
export { DhtRpcOptions } from './rpc-protocol/DhtRpcOptions'
|
package/src/helpers/version.ts
CHANGED
|
@@ -74,7 +74,7 @@ import { MessageType } from "@protobuf-ts/runtime";
|
|
|
74
74
|
* foo = any.unpack(Foo.class);
|
|
75
75
|
* }
|
|
76
76
|
*
|
|
77
|
-
*
|
|
77
|
+
* Example 3: Pack and unpack a message in Python.
|
|
78
78
|
*
|
|
79
79
|
* foo = Foo(...)
|
|
80
80
|
* any = Any()
|
|
@@ -84,13 +84,16 @@ import { MessageType } from "@protobuf-ts/runtime";
|
|
|
84
84
|
* any.Unpack(foo)
|
|
85
85
|
* ...
|
|
86
86
|
*
|
|
87
|
-
*
|
|
87
|
+
* Example 4: Pack and unpack a message in Go
|
|
88
88
|
*
|
|
89
89
|
* foo := &pb.Foo{...}
|
|
90
|
-
* any, err :=
|
|
90
|
+
* any, err := anypb.New(foo)
|
|
91
|
+
* if err != nil {
|
|
92
|
+
* ...
|
|
93
|
+
* }
|
|
91
94
|
* ...
|
|
92
95
|
* foo := &pb.Foo{}
|
|
93
|
-
* if err :=
|
|
96
|
+
* if err := any.UnmarshalTo(foo); err != nil {
|
|
94
97
|
* ...
|
|
95
98
|
* }
|
|
96
99
|
*
|
|
@@ -102,7 +105,7 @@ import { MessageType } from "@protobuf-ts/runtime";
|
|
|
102
105
|
*
|
|
103
106
|
*
|
|
104
107
|
* JSON
|
|
105
|
-
*
|
|
108
|
+
*
|
|
106
109
|
* The JSON representation of an `Any` value uses the regular
|
|
107
110
|
* representation of the deserialized, embedded message, with an
|
|
108
111
|
* additional field `@type` which contains the type URL. Example:
|
|
@@ -49,7 +49,6 @@ import { MessageType } from "@protobuf-ts/runtime";
|
|
|
49
49
|
* rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
|
|
50
50
|
* }
|
|
51
51
|
*
|
|
52
|
-
* The JSON representation for `Empty` is empty JSON object `{}`.
|
|
53
52
|
*
|
|
54
53
|
* @generated from protobuf message google.protobuf.Empty
|
|
55
54
|
*/
|
|
@@ -98,7 +98,16 @@ import { MessageType } from "@protobuf-ts/runtime";
|
|
|
98
98
|
* .setNanos((int) ((millis % 1000) * 1000000)).build();
|
|
99
99
|
*
|
|
100
100
|
*
|
|
101
|
-
* Example 5: Compute Timestamp from
|
|
101
|
+
* Example 5: Compute Timestamp from Java `Instant.now()`.
|
|
102
|
+
*
|
|
103
|
+
* Instant now = Instant.now();
|
|
104
|
+
*
|
|
105
|
+
* Timestamp timestamp =
|
|
106
|
+
* Timestamp.newBuilder().setSeconds(now.getEpochSecond())
|
|
107
|
+
* .setNanos(now.getNano()).build();
|
|
108
|
+
*
|
|
109
|
+
*
|
|
110
|
+
* Example 6: Compute Timestamp from current time in Python.
|
|
102
111
|
*
|
|
103
112
|
* timestamp = Timestamp()
|
|
104
113
|
* timestamp.GetCurrentTime()
|
|
@@ -379,6 +379,14 @@ export interface ConnectivityResponse {
|
|
|
379
379
|
* @generated from protobuf field: string version = 5;
|
|
380
380
|
*/
|
|
381
381
|
version: string;
|
|
382
|
+
/**
|
|
383
|
+
* @generated from protobuf field: optional double latitude = 6;
|
|
384
|
+
*/
|
|
385
|
+
latitude?: number;
|
|
386
|
+
/**
|
|
387
|
+
* @generated from protobuf field: optional double longitude = 7;
|
|
388
|
+
*/
|
|
389
|
+
longitude?: number;
|
|
382
390
|
}
|
|
383
391
|
/**
|
|
384
392
|
* @generated from protobuf message dht.HandshakeRequest
|
|
@@ -978,7 +986,9 @@ class ConnectivityResponse$Type extends MessageType<ConnectivityResponse> {
|
|
|
978
986
|
{ no: 2, name: "natType", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
979
987
|
{ no: 3, name: "websocket", kind: "message", T: () => ConnectivityMethod },
|
|
980
988
|
{ no: 4, name: "ipAddress", kind: "scalar", T: 13 /*ScalarType.UINT32*/ },
|
|
981
|
-
{ no: 5, name: "version", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
989
|
+
{ no: 5, name: "version", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
990
|
+
{ no: 6, name: "latitude", kind: "scalar", opt: true, T: 1 /*ScalarType.DOUBLE*/ },
|
|
991
|
+
{ no: 7, name: "longitude", kind: "scalar", opt: true, T: 1 /*ScalarType.DOUBLE*/ }
|
|
982
992
|
]);
|
|
983
993
|
}
|
|
984
994
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { DhtAddress } from '../identifiers'
|
|
2
1
|
import { Message, PeerDescriptor } from '../proto/packages/dht/protos/DhtRpc'
|
|
3
2
|
|
|
4
3
|
export interface TransportEvents {
|
|
@@ -33,8 +32,5 @@ export interface ITransport {
|
|
|
33
32
|
|
|
34
33
|
send(msg: Message, opts?: SendOptions): Promise<void>
|
|
35
34
|
getLocalPeerDescriptor(): PeerDescriptor
|
|
36
|
-
getConnections(): PeerDescriptor[]
|
|
37
|
-
getConnectionCount(): number
|
|
38
|
-
hasConnection(nodeId: DhtAddress): boolean
|
|
39
35
|
stop(): void | Promise<void>
|
|
40
36
|
}
|
|
@@ -56,7 +56,7 @@ describe('Find correctness', () => {
|
|
|
56
56
|
logger.info('waiting over')
|
|
57
57
|
|
|
58
58
|
nodes.forEach((node) => logger.info(getNodeIdFromPeerDescriptor(node.getLocalPeerDescriptor()) + ': connections:' +
|
|
59
|
-
node.getConnectionCount() + ', kbucket: ' + node.getNeighborCount()
|
|
59
|
+
node.getConnectionsView().getConnectionCount() + ', kbucket: ' + node.getNeighborCount()
|
|
60
60
|
+ ', localLocked: ' + node.getLocalLockedConnectionCount()
|
|
61
61
|
+ ', remoteLocked: ' + node.getRemoteLockedConnectionCount()
|
|
62
62
|
+ ', weakLocked: ' + node.getWeakLockedConnectionCount()))
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { WebsocketServerConnection } from '../../src/connection/websocket/WebsocketServerConnection'
|
|
2
|
+
import { DhtNode } from '../../src/dht/DhtNode'
|
|
3
|
+
import fs from 'fs'
|
|
4
|
+
|
|
5
|
+
const WEBSOCKET_PORT_RANGE = { min: 10012, max: 10015 }
|
|
6
|
+
|
|
7
|
+
// '51.120.98.194' is the IP address of norway.no in OSL = 7900
|
|
8
|
+
const testIp = '51.120.98.194'
|
|
9
|
+
const testRegion = 7900
|
|
10
|
+
const dbPath = '/tmp/geoipdatabasesl0'
|
|
11
|
+
|
|
12
|
+
describe('Layer0', () => {
|
|
13
|
+
|
|
14
|
+
let epDhtNode: DhtNode
|
|
15
|
+
let node1: DhtNode
|
|
16
|
+
let mock: jest.SpyInstance<string, [], any>
|
|
17
|
+
|
|
18
|
+
beforeEach(async () => {
|
|
19
|
+
|
|
20
|
+
epDhtNode = new DhtNode({
|
|
21
|
+
websocketHost: '127.0.0.1', websocketPortRange: { min: 10011, max: 10011 }, websocketServerEnableTls: false,
|
|
22
|
+
geoIpDatabaseFolder: dbPath
|
|
23
|
+
})
|
|
24
|
+
await epDhtNode.start()
|
|
25
|
+
await epDhtNode.joinDht([epDhtNode.getLocalPeerDescriptor()])
|
|
26
|
+
|
|
27
|
+
node1 = new DhtNode({
|
|
28
|
+
websocketPortRange: WEBSOCKET_PORT_RANGE,
|
|
29
|
+
websocketHost: '127.0.0.1',
|
|
30
|
+
entryPoints: [epDhtNode.getLocalPeerDescriptor()],
|
|
31
|
+
websocketServerEnableTls: false
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
mock = jest.spyOn(WebsocketServerConnection.prototype, 'getRemoteIpAddress').mockImplementation(() => testIp)
|
|
35
|
+
|
|
36
|
+
}, 10000)
|
|
37
|
+
|
|
38
|
+
afterEach(async () => {
|
|
39
|
+
await Promise.all([
|
|
40
|
+
epDhtNode.stop(),
|
|
41
|
+
node1.stop()
|
|
42
|
+
])
|
|
43
|
+
fs.unlinkSync(dbPath + '/GeoLite2-City.mmdb')
|
|
44
|
+
fs.rmSync(dbPath, { recursive: true })
|
|
45
|
+
mock.mockRestore()
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('Gets the correct region number by IP address', async () => {
|
|
49
|
+
await node1.start()
|
|
50
|
+
await node1.joinDht([epDhtNode.getLocalPeerDescriptor()])
|
|
51
|
+
|
|
52
|
+
expect(node1.getLocalPeerDescriptor().region).toBe(testRegion)
|
|
53
|
+
|
|
54
|
+
}, 10000)
|
|
55
|
+
})
|
|
@@ -39,11 +39,11 @@ describe('Layer0-Layer1', () => {
|
|
|
39
39
|
await node1.start()
|
|
40
40
|
await node2.start()
|
|
41
41
|
|
|
42
|
-
stream1Node1 = new DhtNode({ transport: epDhtNode, serviceId: STREAM_ID1 })
|
|
43
|
-
stream1Node2 = new DhtNode({ transport: node1, serviceId: STREAM_ID1 })
|
|
42
|
+
stream1Node1 = new DhtNode({ transport: epDhtNode, connectionsView: epDhtNode.getConnectionsView(), serviceId: STREAM_ID1 })
|
|
43
|
+
stream1Node2 = new DhtNode({ transport: node1, connectionsView: node1.getConnectionsView(), serviceId: STREAM_ID1 })
|
|
44
44
|
|
|
45
|
-
stream2Node1 = new DhtNode({ transport: epDhtNode, serviceId: STREAM_ID2 })
|
|
46
|
-
stream2Node2 = new DhtNode({ transport: node2, serviceId: STREAM_ID2 })
|
|
45
|
+
stream2Node1 = new DhtNode({ transport: epDhtNode, connectionsView: epDhtNode.getConnectionsView(), serviceId: STREAM_ID2 })
|
|
46
|
+
stream2Node2 = new DhtNode({ transport: node2, connectionsView: node2.getConnectionsView(), serviceId: STREAM_ID2 })
|
|
47
47
|
|
|
48
48
|
await Promise.all([
|
|
49
49
|
stream1Node1.start(),
|