@streamr/dht 0.0.1-tatum.4 → 0.0.1-tatum.6
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/src/connection/ConnectionManager.d.ts +1 -0
- package/dist/src/connection/ConnectionManager.js +14 -2
- package/dist/src/connection/ConnectionManager.js.map +1 -1
- package/dist/src/connection/ConnectivityChecker.js +27 -17
- package/dist/src/connection/ConnectivityChecker.js.map +1 -1
- package/dist/src/connection/Handshaker.js +18 -13
- package/dist/src/connection/Handshaker.js.map +1 -1
- package/dist/src/connection/WebSocket/ServerWebSocket.js +0 -1
- package/dist/src/connection/WebSocket/ServerWebSocket.js.map +1 -1
- package/dist/src/dht/DhtNode.d.ts +2 -3
- package/dist/src/dht/DhtNode.js +24 -42
- package/dist/src/dht/DhtNode.js.map +1 -1
- package/dist/src/dht/DhtPeer.d.ts +2 -1
- package/dist/src/dht/DhtPeer.js +18 -25
- package/dist/src/dht/DhtPeer.js.map +1 -1
- package/dist/src/dht/RemoteExternalApi.d.ts +3 -1
- package/dist/src/dht/RemoteExternalApi.js +20 -6
- package/dist/src/dht/RemoteExternalApi.js.map +1 -1
- package/dist/src/dht/contact/Contact.d.ts +1 -15
- package/dist/src/dht/contact/Contact.js +1 -9
- package/dist/src/dht/contact/Contact.js.map +1 -1
- package/dist/src/dht/contact/ContactList.d.ts +27 -0
- package/dist/src/dht/contact/ContactList.js +44 -0
- package/dist/src/dht/contact/ContactList.js.map +1 -0
- package/dist/src/dht/contact/RandomContactList.d.ts +8 -16
- package/dist/src/dht/contact/RandomContactList.js +11 -36
- package/dist/src/dht/contact/RandomContactList.js.map +1 -1
- package/dist/src/dht/contact/Remote.d.ts +10 -10
- package/dist/src/dht/contact/Remote.js +17 -9
- package/dist/src/dht/contact/Remote.js.map +1 -1
- package/dist/src/dht/contact/SortedContactList.d.ts +11 -20
- package/dist/src/dht/contact/SortedContactList.js +17 -39
- package/dist/src/dht/contact/SortedContactList.js.map +1 -1
- package/dist/src/dht/find/RecursiveFinder.js +1 -1
- package/dist/src/dht/find/RecursiveFinder.js.map +1 -1
- package/dist/src/dht/find/RemoteRecursiveFindSession.js +1 -5
- package/dist/src/dht/find/RemoteRecursiveFindSession.js.map +1 -1
- package/dist/src/dht/registerExternalApiRpcMethods.d.ts +2 -0
- package/dist/src/dht/{registerExternalApiRpcMethod.js → registerExternalApiRpcMethods.js} +13 -5
- package/dist/src/dht/registerExternalApiRpcMethods.js.map +1 -0
- package/dist/src/dht/routing/RemoteRouter.js +13 -19
- package/dist/src/dht/routing/RemoteRouter.js.map +1 -1
- package/dist/src/dht/routing/RoutingSession.d.ts +0 -1
- package/dist/src/dht/routing/RoutingSession.js +15 -10
- package/dist/src/dht/routing/RoutingSession.js.map +1 -1
- package/dist/src/dht/store/DataStore.js +3 -3
- package/dist/src/dht/store/DataStore.js.map +1 -1
- package/dist/src/dht/store/RemoteStore.js +13 -17
- package/dist/src/dht/store/RemoteStore.js.map +1 -1
- package/dist/src/exports.d.ts +1 -1
- package/dist/src/exports.js +3 -3
- package/dist/src/exports.js.map +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.d.ts +10 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.js +7 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.js.map +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +36 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.js +29 -2
- package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.server.d.ts +6 -0
- package/package.json +6 -6
- package/protos/DhtRpc.proto +10 -0
- package/src/connection/ConnectionManager.ts +17 -4
- package/src/connection/ConnectivityChecker.ts +26 -17
- package/src/connection/Handshaker.ts +18 -13
- package/src/connection/WebSocket/ServerWebSocket.ts +0 -1
- package/src/dht/DhtNode.ts +36 -25
- package/src/dht/DhtPeer.ts +20 -27
- package/src/dht/RemoteExternalApi.ts +22 -8
- package/src/dht/contact/Contact.ts +1 -18
- package/src/dht/contact/ContactList.ts +59 -0
- package/src/dht/contact/RandomContactList.ts +17 -43
- package/src/dht/contact/Remote.ts +27 -20
- package/src/dht/contact/SortedContactList.ts +29 -58
- package/src/dht/find/RecursiveFinder.ts +3 -3
- package/src/dht/find/RemoteRecursiveFindSession.ts +1 -8
- package/src/dht/registerExternalApiRpcMethods.ts +41 -0
- package/src/dht/routing/RemoteRouter.ts +13 -20
- package/src/dht/routing/RoutingSession.ts +29 -20
- package/src/dht/store/DataStore.ts +6 -6
- package/src/dht/store/RemoteStore.ts +13 -20
- package/src/exports.ts +1 -1
- package/src/proto/packages/dht/protos/DhtRpc.client.ts +13 -0
- package/src/proto/packages/dht/protos/DhtRpc.server.ts +6 -0
- package/src/proto/packages/dht/protos/DhtRpc.ts +49 -1
- package/test/benchmark/KademliaCorrectness.test.ts +2 -1
- package/test/end-to-end/Layer0-Layer1.test.ts +10 -10
- package/test/integration/DhtNodeExternalAPI.test.ts +9 -0
- package/test/integration/DhtWithMockConnectionLatencies.test.ts +1 -1
- package/test/integration/DhtWithMockConnections.test.ts +1 -1
- package/test/integration/DhtWithRealConnectionLatencies.test.ts +1 -1
- package/test/integration/RemoteRouter.test.ts +1 -1
- package/test/integration/RemoteStore.test.ts +1 -1
- package/test/unit/RandomContactList.test.ts +31 -73
- package/test/unit/SortedContactList.test.ts +72 -96
- package/dist/src/dht/registerExternalApiRpcMethod.d.ts +0 -2
- package/dist/src/dht/registerExternalApiRpcMethod.js.map +0 -1
- package/src/dht/registerExternalApiRpcMethod.ts +0 -26
|
@@ -32,21 +32,26 @@ export class Handshaker extends EventEmitter<HandshakerEvents> {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
private onData = (data: Uint8Array) => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
35
|
+
try {
|
|
36
|
+
const message = Message.fromBinary(data)
|
|
37
|
+
if (message.body.oneofKind === 'handshakeRequest') {
|
|
38
|
+
logger.trace('handshake request received')
|
|
39
|
+
const handshake = message.body.handshakeRequest
|
|
40
|
+
this.emit('handshakeRequest', handshake.peerDescriptor!)
|
|
41
|
+
}
|
|
42
|
+
if (message.body.oneofKind === 'handshakeResponse') {
|
|
43
|
+
logger.trace('handshake response received')
|
|
44
|
+
const handshake = message.body.handshakeResponse
|
|
45
|
+
if (handshake.responseError) {
|
|
46
|
+
this.emit('handshakeFailed', handshake.responseError)
|
|
47
|
+
} else {
|
|
48
|
+
this.emit('handshakeCompleted', handshake.peerDescriptor!)
|
|
49
|
+
}
|
|
48
50
|
}
|
|
51
|
+
} catch (err) {
|
|
52
|
+
logger.error('error while parsing handshake message', err)
|
|
49
53
|
}
|
|
54
|
+
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
public sendHandshakeRequest(): void {
|
package/src/dht/DhtNode.ts
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
FindMode,
|
|
19
19
|
DataEntry,
|
|
20
20
|
} from '../proto/packages/dht/protos/DhtRpc'
|
|
21
|
-
import * as Err from '../helpers/errors'
|
|
22
21
|
import { DisconnectionType, ITransport, TransportEvents } from '../transport/ITransport'
|
|
23
22
|
import { ConnectionManager, ConnectionManagerConfig, PortRange, TlsCertificate } from '../connection/ConnectionManager'
|
|
24
23
|
import { DhtRpcServiceClient, ExternalApiServiceClient } from '../proto/packages/dht/protos/DhtRpc.client'
|
|
@@ -40,10 +39,11 @@ import { DataStore } from './store/DataStore'
|
|
|
40
39
|
import { PeerDiscovery } from './discovery/PeerDiscovery'
|
|
41
40
|
import { LocalDataStore } from './store/LocalDataStore'
|
|
42
41
|
import { IceServer } from '../connection/WebRTC/WebRtcConnector'
|
|
43
|
-
import {
|
|
42
|
+
import { registerExternalApiRpcMethods } from './registerExternalApiRpcMethods'
|
|
44
43
|
import { RemoteExternalApi } from './RemoteExternalApi'
|
|
45
44
|
import { UUID } from '../exports'
|
|
46
45
|
import { isNodeJS } from '../helpers/browser/isNodeJS'
|
|
46
|
+
import { sample } from 'lodash'
|
|
47
47
|
|
|
48
48
|
export interface DhtNodeEvents {
|
|
49
49
|
newContact: (peerDescriptor: PeerDescriptor, closestPeers: PeerDescriptor[]) => void
|
|
@@ -142,7 +142,8 @@ export const createPeerDescriptor = (msg?: ConnectivityResponse, peerId?: string
|
|
|
142
142
|
} else {
|
|
143
143
|
kademliaId = hexToBinary(peerId!)
|
|
144
144
|
}
|
|
145
|
-
const
|
|
145
|
+
const nodeType = isNodeJS() ? NodeType.NODEJS : NodeType.BROWSER
|
|
146
|
+
const ret: PeerDescriptor = { kademliaId, nodeName: nodeName ? nodeName : binaryToHex(kademliaId), type: nodeType }
|
|
146
147
|
if (msg && msg.websocket) {
|
|
147
148
|
ret.websocket = { host: msg.websocket.host, port: msg.websocket.port, tls: msg.websocket.tls }
|
|
148
149
|
ret.openInternet = true
|
|
@@ -299,7 +300,7 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
299
300
|
return this.bucket!.closest(id, n)
|
|
300
301
|
}
|
|
301
302
|
})
|
|
302
|
-
|
|
303
|
+
registerExternalApiRpcMethods(this)
|
|
303
304
|
if (this.connectionManager! && this.config.entryPoints && this.config.entryPoints.length > 0
|
|
304
305
|
&& !isSamePeerDescriptor(this.config.entryPoints[0], this.ownPeerDescriptor!)) {
|
|
305
306
|
this.connectToEntryPoint(this.config.entryPoints[0])
|
|
@@ -319,29 +320,29 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
319
320
|
// TODO: Update contact info to the connection manager and reconnect
|
|
320
321
|
})
|
|
321
322
|
this.neighborList = new SortedContactList(selfId, this.config.maxNeighborListSize)
|
|
322
|
-
this.neighborList.on('contactRemoved', (
|
|
323
|
+
this.neighborList.on('contactRemoved', (removedContact: DhtPeer, activeContacts: DhtPeer[]) => {
|
|
323
324
|
if (this.stopped) {
|
|
324
325
|
return
|
|
325
326
|
}
|
|
326
|
-
this.emit('contactRemoved',
|
|
327
|
+
this.emit('contactRemoved', removedContact.getPeerDescriptor(), activeContacts.map((c) => c.getPeerDescriptor()))
|
|
327
328
|
this.randomPeers!.addContact(
|
|
328
329
|
new DhtPeer(
|
|
329
330
|
this.ownPeerDescriptor!,
|
|
330
|
-
|
|
331
|
+
removedContact.getPeerDescriptor(),
|
|
331
332
|
toProtoRpcClient(new DhtRpcServiceClient(this.rpcCommunicator!.getRpcClientTransport())),
|
|
332
333
|
this.config.serviceId
|
|
333
334
|
)
|
|
334
335
|
)
|
|
335
336
|
})
|
|
336
|
-
this.neighborList.on('newContact', (
|
|
337
|
-
this.emit('newContact',
|
|
337
|
+
this.neighborList.on('newContact', (newContact: DhtPeer, activeContacts: DhtPeer[]) =>
|
|
338
|
+
this.emit('newContact', newContact.getPeerDescriptor(), activeContacts.map((c) => c.getPeerDescriptor()))
|
|
338
339
|
)
|
|
339
340
|
this.openInternetPeers = new SortedContactList(selfId, this.config.maxNeighborListSize / 2)
|
|
340
|
-
this.openInternetPeers.on('contactRemoved', (
|
|
341
|
-
this.emit('openInternetContactRemoved',
|
|
341
|
+
this.openInternetPeers.on('contactRemoved', (removedContact: DhtPeer, activeContacts: DhtPeer[]) =>
|
|
342
|
+
this.emit('openInternetContactRemoved', removedContact.getPeerDescriptor(), activeContacts.map((c) => c.getPeerDescriptor()))
|
|
342
343
|
)
|
|
343
|
-
this.openInternetPeers.on('newContact', (
|
|
344
|
-
this.emit('newOpenInternetContact',
|
|
344
|
+
this.openInternetPeers.on('newContact', (newContact: DhtPeer, activeContacts: DhtPeer[]) =>
|
|
345
|
+
this.emit('newOpenInternetContact', newContact.getPeerDescriptor(), activeContacts.map((c) => c.getPeerDescriptor()))
|
|
345
346
|
)
|
|
346
347
|
this.transportLayer!.on('connected', (peerDescriptor: PeerDescriptor) => this.onTransportConnected(peerDescriptor))
|
|
347
348
|
|
|
@@ -363,11 +364,11 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
363
364
|
this.connections.set(peerId.toKey(), dhtPeer)
|
|
364
365
|
})
|
|
365
366
|
this.randomPeers = new RandomContactList(selfId, this.config.maxNeighborListSize)
|
|
366
|
-
this.randomPeers.on('contactRemoved', (
|
|
367
|
-
this.emit('randomContactRemoved',
|
|
367
|
+
this.randomPeers.on('contactRemoved', (removedContact: DhtPeer, activeContacts: DhtPeer[]) =>
|
|
368
|
+
this.emit('randomContactRemoved', removedContact.getPeerDescriptor(), activeContacts.map((c) => c.getPeerDescriptor()))
|
|
368
369
|
)
|
|
369
|
-
this.randomPeers.on('newContact', (
|
|
370
|
-
this.emit('newRandomContact',
|
|
370
|
+
this.randomPeers.on('newContact', (newContact: DhtPeer, activeContacts: DhtPeer[]) =>
|
|
371
|
+
this.emit('newRandomContact', newContact.getPeerDescriptor(), activeContacts.map((c) => c.getPeerDescriptor()))
|
|
371
372
|
)
|
|
372
373
|
}
|
|
373
374
|
|
|
@@ -555,8 +556,8 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
555
556
|
return undefined
|
|
556
557
|
}
|
|
557
558
|
|
|
558
|
-
public
|
|
559
|
-
return this.neighborList
|
|
559
|
+
public getClosestContacts(maxCount?: number): PeerDescriptor[] {
|
|
560
|
+
return this.neighborList!.getClosestContacts(maxCount).map((c) => c.getPeerDescriptor())
|
|
560
561
|
}
|
|
561
562
|
|
|
562
563
|
public getNodeId(): PeerID {
|
|
@@ -640,9 +641,22 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
640
641
|
}
|
|
641
642
|
|
|
642
643
|
public async storeDataToDht(key: Uint8Array, data: Any): Promise<PeerDescriptor[]> {
|
|
644
|
+
if (this.isJoinOngoing() && this.config.entryPoints && this.config.entryPoints.length > 0) {
|
|
645
|
+
return this.storeDataViaPeer(key, data, sample(this.config.entryPoints)!)
|
|
646
|
+
}
|
|
643
647
|
return this.dataStore!.storeDataToDht(key, data)
|
|
644
648
|
}
|
|
645
649
|
|
|
650
|
+
public async storeDataViaPeer(key: Uint8Array, data: Any, peer: PeerDescriptor): Promise<PeerDescriptor[]> {
|
|
651
|
+
const target = new RemoteExternalApi(
|
|
652
|
+
this.ownPeerDescriptor!,
|
|
653
|
+
peer,
|
|
654
|
+
this.config.serviceId,
|
|
655
|
+
toProtoRpcClient(new ExternalApiServiceClient(this.rpcCommunicator!.getRpcClientTransport()))
|
|
656
|
+
)
|
|
657
|
+
return await target.storeData(key, data)
|
|
658
|
+
}
|
|
659
|
+
|
|
646
660
|
public async getDataFromDht(idToFind: Uint8Array): Promise<RecursiveFindResult> {
|
|
647
661
|
return this.recursiveFinder!.startRecursiveFind(idToFind, FindMode.DATA)
|
|
648
662
|
}
|
|
@@ -657,8 +671,8 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
657
671
|
const target = new RemoteExternalApi(
|
|
658
672
|
this.ownPeerDescriptor!,
|
|
659
673
|
peer,
|
|
660
|
-
|
|
661
|
-
this.
|
|
674
|
+
this.config.serviceId,
|
|
675
|
+
toProtoRpcClient(new ExternalApiServiceClient(this.rpcCommunicator!.getRpcClientTransport()))
|
|
662
676
|
)
|
|
663
677
|
return await target.findData(idToFind)
|
|
664
678
|
}
|
|
@@ -720,13 +734,10 @@ export class DhtNode extends EventEmitter<Events> implements ITransport {
|
|
|
720
734
|
}
|
|
721
735
|
|
|
722
736
|
public async stop(): Promise<void> {
|
|
723
|
-
if (this.stopped) {
|
|
737
|
+
if (this.stopped || !this.started) {
|
|
724
738
|
return
|
|
725
739
|
}
|
|
726
740
|
logger.trace('stop()')
|
|
727
|
-
if (!this.started) {
|
|
728
|
-
throw new Err.CouldNotStop('Cannot not stop() before start()')
|
|
729
|
-
}
|
|
730
741
|
this.stopped = true
|
|
731
742
|
|
|
732
743
|
if (this.entryPointDisconnectTimeout) {
|
package/src/dht/DhtPeer.ts
CHANGED
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
PingRequest
|
|
7
7
|
} from '../proto/packages/dht/protos/DhtRpc'
|
|
8
8
|
import { v4 } from 'uuid'
|
|
9
|
-
import { DhtRpcOptions } from '../rpc-protocol/DhtRpcOptions'
|
|
10
9
|
import { Logger } from '@streamr/utils'
|
|
11
10
|
import { ProtoRpcClient } from '@streamr/proto-rpc'
|
|
12
11
|
import { Remote } from './contact/Remote'
|
|
12
|
+
import { PeerID, peerIdFromPeerDescriptor } from '../exports'
|
|
13
13
|
|
|
14
14
|
const logger = new Logger(module)
|
|
15
15
|
|
|
@@ -20,77 +20,70 @@ export interface KBucketContact {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export class DhtPeer extends Remote<IDhtRpcServiceClient> implements KBucketContact {
|
|
23
|
+
|
|
23
24
|
private static counter = 0
|
|
24
25
|
public vectorClock: number
|
|
25
26
|
public readonly id: Uint8Array
|
|
27
|
+
|
|
26
28
|
constructor(
|
|
27
29
|
ownPeerDescriptor: PeerDescriptor,
|
|
28
30
|
peerDescriptor: PeerDescriptor,
|
|
29
31
|
client: ProtoRpcClient<IDhtRpcServiceClient>,
|
|
30
32
|
serviceId: string
|
|
31
33
|
) {
|
|
32
|
-
super(ownPeerDescriptor, peerDescriptor,
|
|
33
|
-
this.id = this.
|
|
34
|
+
super(ownPeerDescriptor, peerDescriptor, serviceId, client)
|
|
35
|
+
this.id = this.getPeerId().value
|
|
34
36
|
this.vectorClock = DhtPeer.counter++
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
async getClosestPeers(kademliaId: Uint8Array): Promise<PeerDescriptor[]> {
|
|
38
|
-
logger.trace(`Requesting getClosestPeers on ${this.
|
|
40
|
+
logger.trace(`Requesting getClosestPeers on ${this.getServiceId()} from ${this.getPeerId().toKey()}`)
|
|
39
41
|
const request: ClosestPeersRequest = {
|
|
40
42
|
kademliaId,
|
|
41
43
|
requestId: v4()
|
|
42
44
|
}
|
|
43
|
-
const options: DhtRpcOptions = {
|
|
44
|
-
sourceDescriptor: this.ownPeerDescriptor,
|
|
45
|
-
targetDescriptor: this.peerDescriptor
|
|
46
|
-
}
|
|
47
45
|
try {
|
|
48
|
-
const peers = await this.
|
|
46
|
+
const peers = await this.getClient().getClosestPeers(request, this.formDhtRpcOptions())
|
|
49
47
|
return peers.peers
|
|
50
48
|
} catch (err) {
|
|
51
|
-
logger.trace(`getClosestPeers error ${this.
|
|
49
|
+
logger.trace(`getClosestPeers error ${this.getServiceId()}`, { err })
|
|
52
50
|
throw err
|
|
53
51
|
}
|
|
54
52
|
}
|
|
55
53
|
|
|
56
54
|
async ping(): Promise<boolean> {
|
|
57
|
-
logger.trace(`Requesting ping on ${this.
|
|
55
|
+
logger.trace(`Requesting ping on ${this.getServiceId()} from ${this.getPeerId().toKey()}`)
|
|
58
56
|
const request: PingRequest = {
|
|
59
57
|
requestId: v4()
|
|
60
58
|
}
|
|
61
|
-
const options
|
|
62
|
-
sourceDescriptor: this.ownPeerDescriptor,
|
|
63
|
-
targetDescriptor: this.peerDescriptor,
|
|
59
|
+
const options = this.formDhtRpcOptions({
|
|
64
60
|
timeout: 10000
|
|
65
|
-
}
|
|
61
|
+
})
|
|
66
62
|
try {
|
|
67
|
-
const pong = await this.
|
|
63
|
+
const pong = await this.getClient().ping(request, options)
|
|
68
64
|
if (pong.requestId === request.requestId) {
|
|
69
65
|
return true
|
|
70
66
|
}
|
|
71
67
|
} catch (err) {
|
|
72
|
-
logger.trace(`ping failed on ${this.
|
|
68
|
+
logger.trace(`ping failed on ${this.getServiceId()} to ${this.getPeerId().toKey()}: ${err}`)
|
|
73
69
|
}
|
|
74
70
|
return false
|
|
75
71
|
}
|
|
76
72
|
|
|
77
73
|
leaveNotice(): void {
|
|
78
|
-
logger.trace(`Sending leaveNotice on ${this.
|
|
74
|
+
logger.trace(`Sending leaveNotice on ${this.getServiceId()} from ${this.getPeerId().toKey()}`)
|
|
79
75
|
const request: LeaveNotice = {
|
|
80
|
-
serviceId: this.
|
|
76
|
+
serviceId: this.getServiceId()
|
|
81
77
|
}
|
|
82
|
-
const options
|
|
83
|
-
sourceDescriptor: this.ownPeerDescriptor,
|
|
84
|
-
targetDescriptor: this.peerDescriptor,
|
|
78
|
+
const options = this.formDhtRpcOptions({
|
|
85
79
|
notification: true
|
|
86
|
-
}
|
|
87
|
-
this.
|
|
80
|
+
})
|
|
81
|
+
this.getClient().leaveNotice(request, options).catch((e) => {
|
|
88
82
|
logger.trace('Failed to send leaveNotice' + e)
|
|
89
83
|
})
|
|
90
84
|
}
|
|
91
85
|
|
|
92
|
-
|
|
93
|
-
return this.
|
|
86
|
+
getPeerId(): PeerID {
|
|
87
|
+
return peerIdFromPeerDescriptor(this.getPeerDescriptor())
|
|
94
88
|
}
|
|
95
|
-
|
|
96
89
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { DataEntry, FindDataRequest } from '../proto/packages/dht/protos/DhtRpc'
|
|
1
|
+
import { Any } from '../proto/google/protobuf/any'
|
|
2
|
+
import { DataEntry, ExternalStoreDataRequest, FindDataRequest, PeerDescriptor } from '../proto/packages/dht/protos/DhtRpc'
|
|
3
3
|
import { IExternalApiServiceClient } from '../proto/packages/dht/protos/DhtRpc.client'
|
|
4
4
|
import { Remote } from './contact/Remote'
|
|
5
5
|
|
|
@@ -8,18 +8,32 @@ export class RemoteExternalApi extends Remote<IExternalApiServiceClient> {
|
|
|
8
8
|
async findData(idToFind: Uint8Array): Promise<DataEntry[]> {
|
|
9
9
|
const request: FindDataRequest = {
|
|
10
10
|
kademliaId: idToFind,
|
|
11
|
-
requestor: this.
|
|
11
|
+
requestor: this.getLocalPeerDescriptor(),
|
|
12
12
|
}
|
|
13
|
-
const options
|
|
14
|
-
sourceDescriptor: this.ownPeerDescriptor,
|
|
15
|
-
targetDescriptor: this.peerDescriptor,
|
|
13
|
+
const options = this.formDhtRpcOptions({
|
|
16
14
|
timeout: 10000
|
|
17
|
-
}
|
|
15
|
+
})
|
|
18
16
|
try {
|
|
19
|
-
const data = await this.
|
|
17
|
+
const data = await this.getClient().findData(request, options)
|
|
20
18
|
return data.dataEntries
|
|
21
19
|
} catch (err) {
|
|
22
20
|
return []
|
|
23
21
|
}
|
|
24
22
|
}
|
|
23
|
+
|
|
24
|
+
async storeData(key: Uint8Array, data: Any): Promise<PeerDescriptor[]> {
|
|
25
|
+
const request: ExternalStoreDataRequest = {
|
|
26
|
+
key,
|
|
27
|
+
data
|
|
28
|
+
}
|
|
29
|
+
const options = this.formDhtRpcOptions({
|
|
30
|
+
timeout: 10000
|
|
31
|
+
})
|
|
32
|
+
try {
|
|
33
|
+
const response = await this.getClient().externalStoreData(request, options)
|
|
34
|
+
return response.storers
|
|
35
|
+
} catch (err) {
|
|
36
|
+
return []
|
|
37
|
+
}
|
|
38
|
+
}
|
|
25
39
|
}
|
|
@@ -2,24 +2,7 @@ import { PeerID } from '../../helpers/PeerID'
|
|
|
2
2
|
import { PeerDescriptor } from '../../proto/packages/dht/protos/DhtRpc'
|
|
3
3
|
import { peerIdFromPeerDescriptor } from '../../helpers/peerIdFromPeerDescriptor'
|
|
4
4
|
|
|
5
|
-
export class
|
|
6
|
-
public contacted = false
|
|
7
|
-
public active = false
|
|
8
|
-
public contact: TContact
|
|
9
|
-
|
|
10
|
-
constructor(contact: TContact) {
|
|
11
|
-
this.contact = contact
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface IContact { getPeerId: () => PeerID, getPeerDescriptor: () => PeerDescriptor }
|
|
16
|
-
|
|
17
|
-
export interface Events {
|
|
18
|
-
contactRemoved: (removedDescriptor: PeerDescriptor, closestDescriptors: PeerDescriptor[]) => void
|
|
19
|
-
newContact: (newDescriptor: PeerDescriptor, closestDescriptors: PeerDescriptor[]) => void
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export class Contact implements IContact {
|
|
5
|
+
export class Contact {
|
|
23
6
|
private peerDescriptor: PeerDescriptor
|
|
24
7
|
|
|
25
8
|
constructor(peerDescriptor: PeerDescriptor) {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { PeerID, PeerIDKey } from '../../helpers/PeerID'
|
|
2
|
+
import EventEmitter from 'eventemitter3'
|
|
3
|
+
|
|
4
|
+
export class ContactState<C> {
|
|
5
|
+
public contacted = false
|
|
6
|
+
public active = false
|
|
7
|
+
public contact: C
|
|
8
|
+
|
|
9
|
+
constructor(contact: C) {
|
|
10
|
+
this.contact = contact
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface Events<C> {
|
|
15
|
+
contactRemoved: (removedContact: C, closestContacts: C[]) => void
|
|
16
|
+
newContact: (newContact: C, closestContacts: C[]) => void
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class ContactList<C extends { getPeerId: () => PeerID }> extends EventEmitter<Events<C>> {
|
|
20
|
+
|
|
21
|
+
protected contactsById: Map<PeerIDKey, ContactState<C>> = new Map()
|
|
22
|
+
protected contactIds: PeerID[] = []
|
|
23
|
+
protected ownId: PeerID
|
|
24
|
+
protected maxSize: number
|
|
25
|
+
protected defaultContactQueryLimit
|
|
26
|
+
|
|
27
|
+
constructor(
|
|
28
|
+
ownId: PeerID,
|
|
29
|
+
maxSize: number,
|
|
30
|
+
defaultContactQueryLimit = 20
|
|
31
|
+
) {
|
|
32
|
+
super()
|
|
33
|
+
this.ownId = ownId
|
|
34
|
+
this.maxSize = maxSize
|
|
35
|
+
this.defaultContactQueryLimit = defaultContactQueryLimit
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public getContact(id: PeerID): ContactState<C> {
|
|
39
|
+
return this.contactsById.get(id.toKey())!
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public hasContact(id: PeerID): boolean {
|
|
43
|
+
return this.contactsById.has(id.toKey())
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public getSize(): number {
|
|
47
|
+
return this.contactIds.length
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public clear(): void {
|
|
51
|
+
this.contactsById.clear()
|
|
52
|
+
this.contactIds = []
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public stop(): void {
|
|
56
|
+
this.removeAllListeners()
|
|
57
|
+
this.clear()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -1,29 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PeerID } from '../../helpers/PeerID'
|
|
2
|
+
import { ContactList, ContactState } from './ContactList'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
private contactsById: Map<PeerIDKey, ContactState<Contact>> = new Map()
|
|
7
|
-
private contactIds: PeerID[] = []
|
|
8
|
-
private ownId: PeerID
|
|
9
|
-
private maxSize: number
|
|
10
|
-
private randomness = 0.20
|
|
11
|
-
private getContactsLimit = 20
|
|
4
|
+
export class RandomContactList<C extends { getPeerId: () => PeerID }> extends ContactList<C> {
|
|
5
|
+
|
|
6
|
+
private randomness: number
|
|
12
7
|
|
|
13
8
|
constructor(
|
|
14
9
|
ownId: PeerID,
|
|
15
10
|
maxSize: number,
|
|
16
11
|
randomness = 0.20,
|
|
17
|
-
|
|
12
|
+
defaultContactQueryLimit?: number
|
|
18
13
|
) {
|
|
19
|
-
super()
|
|
20
|
-
this.ownId = ownId
|
|
21
|
-
this.maxSize = maxSize
|
|
14
|
+
super(ownId, maxSize, defaultContactQueryLimit)
|
|
22
15
|
this.randomness = randomness
|
|
23
|
-
this.getContactsLimit = getContactsLimit
|
|
24
16
|
}
|
|
25
17
|
|
|
26
|
-
addContact(contact:
|
|
18
|
+
addContact(contact: C): void {
|
|
27
19
|
if (this.ownId.equals(contact.getPeerId())) {
|
|
28
20
|
return
|
|
29
21
|
}
|
|
@@ -38,55 +30,37 @@ export class RandomContactList<Contact extends IContact> extends EventEmitter<Ev
|
|
|
38
30
|
this.contactsById.set(contact.getPeerId().toKey(), new ContactState(contact))
|
|
39
31
|
this.emit(
|
|
40
32
|
'newContact',
|
|
41
|
-
contact
|
|
42
|
-
this.getContacts()
|
|
33
|
+
contact,
|
|
34
|
+
this.getContacts()
|
|
43
35
|
)
|
|
44
36
|
}
|
|
45
37
|
}
|
|
46
38
|
}
|
|
47
39
|
|
|
48
|
-
addContacts(contacts:
|
|
40
|
+
addContacts(contacts: C[]): void {
|
|
49
41
|
contacts.forEach((contact) => this.addContact(contact))
|
|
50
42
|
}
|
|
51
43
|
|
|
52
44
|
removeContact(id: PeerID): boolean {
|
|
53
45
|
if (this.contactsById.has(id.toKey())) {
|
|
54
|
-
const
|
|
55
|
-
const index = this.contactIds.
|
|
46
|
+
const removed = this.contactsById.get(id.toKey())!.contact
|
|
47
|
+
const index = this.contactIds.findIndex((element) => element.equals(id))
|
|
56
48
|
this.contactIds.splice(index, 1)
|
|
57
49
|
this.contactsById.delete(id.toKey())
|
|
58
|
-
this.emit('contactRemoved',
|
|
50
|
+
this.emit('contactRemoved', removed, this.getContacts())
|
|
59
51
|
return true
|
|
60
52
|
}
|
|
61
53
|
return false
|
|
62
54
|
}
|
|
63
55
|
|
|
64
|
-
public
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
public getContact(id: PeerID): ContactState<Contact> {
|
|
69
|
-
return this.contactsById.get(id.toKey())!
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
public getContacts(limit = this.getContactsLimit): Contact[] {
|
|
73
|
-
const ret: Contact[] = []
|
|
56
|
+
public getContacts(limit = this.defaultContactQueryLimit): C[] {
|
|
57
|
+
const ret: C[] = []
|
|
74
58
|
this.contactIds.forEach((contactId) => {
|
|
75
59
|
const contact = this.contactsById.get(contactId.toKey())
|
|
76
60
|
if (contact) {
|
|
77
61
|
ret.push(contact.contact)
|
|
78
62
|
}
|
|
79
63
|
})
|
|
80
|
-
return ret.
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
public clear(): void {
|
|
84
|
-
this.contactsById.clear()
|
|
85
|
-
this.contactIds = []
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
public stop(): void {
|
|
89
|
-
this.removeAllListeners()
|
|
90
|
-
this.clear()
|
|
64
|
+
return ret.slice(0, limit)
|
|
91
65
|
}
|
|
92
66
|
}
|
|
@@ -1,40 +1,47 @@
|
|
|
1
1
|
import { PeerDescriptor } from '../../proto/packages/dht/protos/DhtRpc'
|
|
2
2
|
import { ProtoRpcClient } from '@streamr/proto-rpc'
|
|
3
|
-
import {
|
|
4
|
-
import { PeerID } from '../../helpers/PeerID'
|
|
5
|
-
import { IContact } from './Contact'
|
|
3
|
+
import { DhtRpcOptions } from '../../rpc-protocol/DhtRpcOptions'
|
|
6
4
|
|
|
7
|
-
export abstract class Remote<T>
|
|
5
|
+
export abstract class Remote<T> {
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
protected readonly ownPeerDescriptor: PeerDescriptor
|
|
7
|
+
private readonly localPeerDescriptor: PeerDescriptor
|
|
8
|
+
private readonly remotePeerDescriptor: PeerDescriptor
|
|
9
|
+
private readonly serviceId: string
|
|
10
|
+
private readonly client: ProtoRpcClient<T>
|
|
14
11
|
|
|
15
12
|
constructor(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
localPeerDescriptor: PeerDescriptor,
|
|
14
|
+
remotePeerDescriptor: PeerDescriptor,
|
|
15
|
+
serviceId: string,
|
|
16
|
+
client: ProtoRpcClient<T>
|
|
20
17
|
) {
|
|
21
|
-
this.
|
|
22
|
-
this.
|
|
23
|
-
this.peerDescriptor = peerDescriptor
|
|
18
|
+
this.localPeerDescriptor = localPeerDescriptor
|
|
19
|
+
this.remotePeerDescriptor = remotePeerDescriptor
|
|
24
20
|
this.client = client
|
|
25
21
|
this.serviceId = serviceId
|
|
26
22
|
}
|
|
27
23
|
|
|
28
|
-
|
|
29
|
-
return this.
|
|
24
|
+
getPeerDescriptor(): PeerDescriptor {
|
|
25
|
+
return this.remotePeerDescriptor
|
|
30
26
|
}
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
return this.
|
|
28
|
+
getLocalPeerDescriptor(): PeerDescriptor {
|
|
29
|
+
return this.localPeerDescriptor
|
|
34
30
|
}
|
|
35
31
|
|
|
36
32
|
getServiceId(): string {
|
|
37
33
|
return this.serviceId
|
|
38
34
|
}
|
|
39
35
|
|
|
36
|
+
getClient(): ProtoRpcClient<T> {
|
|
37
|
+
return this.client
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
formDhtRpcOptions(opts?: Omit<DhtRpcOptions, 'sourceDescriptor' | 'targetDescriptor'>): DhtRpcOptions {
|
|
41
|
+
return {
|
|
42
|
+
sourceDescriptor: this.localPeerDescriptor,
|
|
43
|
+
targetDescriptor: this.remotePeerDescriptor,
|
|
44
|
+
...opts
|
|
45
|
+
}
|
|
46
|
+
}
|
|
40
47
|
}
|