@streamr/trackerless-network 0.0.1-tatum.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +7 -0
- package/.eslintrc +3 -0
- package/README.md +6 -0
- package/bin/bootstrap-node.ts +73 -0
- package/bin/full-node-webrtc.ts +102 -0
- package/bin/full-node-websocket.ts +102 -0
- package/bin/network.ts +43 -0
- package/dist/package.json +53 -0
- package/dist/src/NameDirectory.d.ts +5 -0
- package/dist/src/NameDirectory.js +44 -0
- package/dist/src/NameDirectory.js.map +1 -0
- package/dist/src/NetworkNode.d.ts +35 -0
- package/dist/src/NetworkNode.js +130 -0
- package/dist/src/NetworkNode.js.map +1 -0
- package/dist/src/NetworkStack.d.ts +32 -0
- package/dist/src/NetworkStack.js +108 -0
- package/dist/src/NetworkStack.js.map +1 -0
- package/dist/src/exports.d.ts +6 -0
- package/dist/src/exports.js +12 -0
- package/dist/src/exports.js.map +1 -0
- package/dist/src/identifiers.d.ts +1 -0
- package/dist/src/identifiers.js +3 -0
- package/dist/src/identifiers.js.map +1 -0
- package/dist/src/logic/DuplicateMessageDetector.d.ts +55 -0
- package/dist/src/logic/DuplicateMessageDetector.js +155 -0
- package/dist/src/logic/DuplicateMessageDetector.js.map +1 -0
- package/dist/src/logic/ILayer0.d.ts +13 -0
- package/dist/src/logic/ILayer0.js +3 -0
- package/dist/src/logic/ILayer0.js.map +1 -0
- package/dist/src/logic/IStreamNode.d.ts +12 -0
- package/dist/src/logic/IStreamNode.js +3 -0
- package/dist/src/logic/IStreamNode.js.map +1 -0
- package/dist/src/logic/PeerList.d.ts +27 -0
- package/dist/src/logic/PeerList.js +84 -0
- package/dist/src/logic/PeerList.js.map +1 -0
- package/dist/src/logic/RandomGraphNode.d.ts +68 -0
- package/dist/src/logic/RandomGraphNode.js +201 -0
- package/dist/src/logic/RandomGraphNode.js.map +1 -0
- package/dist/src/logic/Remote.d.ts +9 -0
- package/dist/src/logic/Remote.js +15 -0
- package/dist/src/logic/Remote.js.map +1 -0
- package/dist/src/logic/RemoteRandomGraphNode.d.ts +8 -0
- package/dist/src/logic/RemoteRandomGraphNode.js +35 -0
- package/dist/src/logic/RemoteRandomGraphNode.js.map +1 -0
- package/dist/src/logic/StreamEntryPointDiscovery.d.ts +36 -0
- package/dist/src/logic/StreamEntryPointDiscovery.js +179 -0
- package/dist/src/logic/StreamEntryPointDiscovery.js.map +1 -0
- package/dist/src/logic/StreamNodeServer.d.ts +20 -0
- package/dist/src/logic/StreamNodeServer.js +26 -0
- package/dist/src/logic/StreamNodeServer.js.map +1 -0
- package/dist/src/logic/StreamrNode.d.ts +76 -0
- package/dist/src/logic/StreamrNode.js +303 -0
- package/dist/src/logic/StreamrNode.js.map +1 -0
- package/dist/src/logic/createRandomGraphNode.d.ts +5 -0
- package/dist/src/logic/createRandomGraphNode.js +110 -0
- package/dist/src/logic/createRandomGraphNode.js.map +1 -0
- package/dist/src/logic/inspect/InspectSession.d.ts +18 -0
- package/dist/src/logic/inspect/InspectSession.js +38 -0
- package/dist/src/logic/inspect/InspectSession.js.map +1 -0
- package/dist/src/logic/inspect/Inspector.d.ts +33 -0
- package/dist/src/logic/inspect/Inspector.js +63 -0
- package/dist/src/logic/inspect/Inspector.js.map +1 -0
- package/dist/src/logic/neighbor-discovery/Handshaker.d.ts +35 -0
- package/dist/src/logic/neighbor-discovery/Handshaker.js +121 -0
- package/dist/src/logic/neighbor-discovery/Handshaker.js.map +1 -0
- package/dist/src/logic/neighbor-discovery/HandshakerServer.d.ts +30 -0
- package/dist/src/logic/neighbor-discovery/HandshakerServer.js +78 -0
- package/dist/src/logic/neighbor-discovery/HandshakerServer.js.map +1 -0
- package/dist/src/logic/neighbor-discovery/NeighborFinder.d.ts +23 -0
- package/dist/src/logic/neighbor-discovery/NeighborFinder.js +44 -0
- package/dist/src/logic/neighbor-discovery/NeighborFinder.js.map +1 -0
- package/dist/src/logic/neighbor-discovery/NeighborUpdateManager.d.ts +30 -0
- package/dist/src/logic/neighbor-discovery/NeighborUpdateManager.js +42 -0
- package/dist/src/logic/neighbor-discovery/NeighborUpdateManager.js.map +1 -0
- package/dist/src/logic/neighbor-discovery/NeighborUpdateManagerServer.d.ts +20 -0
- package/dist/src/logic/neighbor-discovery/NeighborUpdateManagerServer.js +42 -0
- package/dist/src/logic/neighbor-discovery/NeighborUpdateManagerServer.js.map +1 -0
- package/dist/src/logic/neighbor-discovery/RemoteHandshaker.d.ts +12 -0
- package/dist/src/logic/neighbor-discovery/RemoteHandshaker.js +54 -0
- package/dist/src/logic/neighbor-discovery/RemoteHandshaker.js.map +1 -0
- package/dist/src/logic/neighbor-discovery/RemoteNeighborUpdateManager.d.ts +11 -0
- package/dist/src/logic/neighbor-discovery/RemoteNeighborUpdateManager.js +37 -0
- package/dist/src/logic/neighbor-discovery/RemoteNeighborUpdateManager.js.map +1 -0
- package/dist/src/logic/propagation/FifoMapWithTTL.d.ts +36 -0
- package/dist/src/logic/propagation/FifoMapWithTTL.js +81 -0
- package/dist/src/logic/propagation/FifoMapWithTTL.js.map +1 -0
- package/dist/src/logic/propagation/Propagation.d.ts +31 -0
- package/dist/src/logic/propagation/Propagation.js +64 -0
- package/dist/src/logic/propagation/Propagation.js.map +1 -0
- package/dist/src/logic/propagation/PropagationTaskStore.d.ts +21 -0
- package/dist/src/logic/propagation/PropagationTaskStore.js +32 -0
- package/dist/src/logic/propagation/PropagationTaskStore.js.map +1 -0
- package/dist/src/logic/protocol-integration/stream-message/ContentMessageTranslator.d.ts +5 -0
- package/dist/src/logic/protocol-integration/stream-message/ContentMessageTranslator.js +17 -0
- package/dist/src/logic/protocol-integration/stream-message/ContentMessageTranslator.js.map +1 -0
- package/dist/src/logic/protocol-integration/stream-message/GroupKeyRequestTranslator.d.ts +6 -0
- package/dist/src/logic/protocol-integration/stream-message/GroupKeyRequestTranslator.js +27 -0
- package/dist/src/logic/protocol-integration/stream-message/GroupKeyRequestTranslator.js.map +1 -0
- package/dist/src/logic/protocol-integration/stream-message/GroupKeyResponseTranslator.d.ts +6 -0
- package/dist/src/logic/protocol-integration/stream-message/GroupKeyResponseTranslator.js +33 -0
- package/dist/src/logic/protocol-integration/stream-message/GroupKeyResponseTranslator.js.map +1 -0
- package/dist/src/logic/protocol-integration/stream-message/StreamMessageTranslator.d.ts +6 -0
- package/dist/src/logic/protocol-integration/stream-message/StreamMessageTranslator.js +109 -0
- package/dist/src/logic/protocol-integration/stream-message/StreamMessageTranslator.js.map +1 -0
- package/dist/src/logic/proxy/ProxyStreamConnectionClient.d.ts +44 -0
- package/dist/src/logic/proxy/ProxyStreamConnectionClient.js +189 -0
- package/dist/src/logic/proxy/ProxyStreamConnectionClient.js.map +1 -0
- package/dist/src/logic/proxy/ProxyStreamConnectionServer.d.ts +34 -0
- package/dist/src/logic/proxy/ProxyStreamConnectionServer.js +64 -0
- package/dist/src/logic/proxy/ProxyStreamConnectionServer.js.map +1 -0
- package/dist/src/logic/proxy/RemoteProxyServer.d.ts +7 -0
- package/dist/src/logic/proxy/RemoteProxyServer.js +36 -0
- package/dist/src/logic/proxy/RemoteProxyServer.js.map +1 -0
- package/dist/src/logic/temporary-connection/RemoteTemporaryConnectionRpcServer.d.ts +6 -0
- package/dist/src/logic/temporary-connection/RemoteTemporaryConnectionRpcServer.js +28 -0
- package/dist/src/logic/temporary-connection/RemoteTemporaryConnectionRpcServer.js.map +1 -0
- package/dist/src/logic/temporary-connection/TemporaryConnectionRpcServer.d.ts +20 -0
- package/dist/src/logic/temporary-connection/TemporaryConnectionRpcServer.js +29 -0
- package/dist/src/logic/temporary-connection/TemporaryConnectionRpcServer.js.map +1 -0
- package/dist/src/logic/utils.d.ts +3 -0
- package/dist/src/logic/utils.js +16 -0
- package/dist/src/logic/utils.js.map +1 -0
- package/dist/src/proto/google/protobuf/any.d.ts +173 -0
- package/dist/src/proto/google/protobuf/any.js +155 -0
- package/dist/src/proto/google/protobuf/any.js.map +1 -0
- package/dist/src/proto/google/protobuf/empty.d.ts +32 -0
- package/dist/src/proto/google/protobuf/empty.js +34 -0
- package/dist/src/proto/google/protobuf/empty.js.map +1 -0
- package/dist/src/proto/google/protobuf/timestamp.d.ts +149 -0
- package/dist/src/proto/google/protobuf/timestamp.js +136 -0
- package/dist/src/proto/google/protobuf/timestamp.js.map +1 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.d.ts +320 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.js +245 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.js.map +1 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +1089 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.js +710 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.server.d.ts +145 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.server.js +3 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.server.js.map +1 -0
- package/dist/src/proto/packages/proto-rpc/protos/ProtoRpc.d.ts +87 -0
- package/dist/src/proto/packages/proto-rpc/protos/ProtoRpc.js +66 -0
- package/dist/src/proto/packages/proto-rpc/protos/ProtoRpc.js.map +1 -0
- package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.client.d.ts +156 -0
- package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.client.js +122 -0
- package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.client.js.map +1 -0
- package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.d.ts +524 -0
- package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.js +350 -0
- package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.js.map +1 -0
- package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.server.d.ts +65 -0
- package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.server.js +3 -0
- package/dist/src/proto/packages/trackerless-network/protos/NetworkRpc.server.js.map +1 -0
- package/dist/test/benchmark/first-message.d.ts +1 -0
- package/dist/test/benchmark/first-message.js +137 -0
- package/dist/test/benchmark/first-message.js.map +1 -0
- package/dist/test/utils/utils.d.ts +12 -0
- package/dist/test/utils/utils.js +86 -0
- package/dist/test/utils/utils.js.map +1 -0
- package/jest.config.js +36 -0
- package/karma.config.js +20 -0
- package/log.txt +501 -0
- package/package.json +53 -0
- package/proto.sh +2 -0
- package/protos/NetworkRpc.proto +161 -0
- package/src/NameDirectory.ts +44 -0
- package/src/NetworkNode.ts +169 -0
- package/src/NetworkStack.ts +144 -0
- package/src/exports.ts +6 -0
- package/src/identifiers.ts +1 -0
- package/src/logic/DuplicateMessageDetector.ts +167 -0
- package/src/logic/ILayer0.ts +14 -0
- package/src/logic/IStreamNode.ts +17 -0
- package/src/logic/PeerList.ts +106 -0
- package/src/logic/RandomGraphNode.ts +310 -0
- package/src/logic/Remote.ts +19 -0
- package/src/logic/RemoteRandomGraphNode.ts +39 -0
- package/src/logic/StreamEntryPointDiscovery.ts +221 -0
- package/src/logic/StreamNodeServer.ts +44 -0
- package/src/logic/StreamrNode.ts +416 -0
- package/src/logic/createRandomGraphNode.ts +114 -0
- package/src/logic/inspect/InspectSession.ts +49 -0
- package/src/logic/inspect/Inspector.ts +89 -0
- package/src/logic/neighbor-discovery/Handshaker.ts +180 -0
- package/src/logic/neighbor-discovery/HandshakerServer.ts +99 -0
- package/src/logic/neighbor-discovery/NeighborFinder.ts +61 -0
- package/src/logic/neighbor-discovery/NeighborUpdateManager.ts +67 -0
- package/src/logic/neighbor-discovery/NeighborUpdateManagerServer.ts +61 -0
- package/src/logic/neighbor-discovery/RemoteHandshaker.ts +64 -0
- package/src/logic/neighbor-discovery/RemoteNeighborUpdateManager.ts +41 -0
- package/src/logic/propagation/FifoMapWithTTL.ts +108 -0
- package/src/logic/propagation/Propagation.ts +83 -0
- package/src/logic/propagation/PropagationTaskStore.ts +40 -0
- package/src/logic/protocol-integration/stream-message/ContentMessageTranslator.ts +16 -0
- package/src/logic/protocol-integration/stream-message/GroupKeyRequestTranslator.ts +28 -0
- package/src/logic/protocol-integration/stream-message/GroupKeyResponseTranslator.ts +38 -0
- package/src/logic/protocol-integration/stream-message/StreamMessageTranslator.ts +142 -0
- package/src/logic/proxy/ProxyStreamConnectionClient.ts +255 -0
- package/src/logic/proxy/ProxyStreamConnectionServer.ts +97 -0
- package/src/logic/proxy/RemoteProxyServer.ts +36 -0
- package/src/logic/temporary-connection/RemoteTemporaryConnectionRpcServer.ts +27 -0
- package/src/logic/temporary-connection/TemporaryConnectionRpcServer.ts +50 -0
- package/src/logic/utils.ts +17 -0
- package/src/proto/google/protobuf/any.ts +319 -0
- package/src/proto/google/protobuf/empty.ts +84 -0
- package/src/proto/google/protobuf/timestamp.ts +281 -0
- package/src/proto/packages/dht/protos/DhtRpc.client.ts +373 -0
- package/src/proto/packages/dht/protos/DhtRpc.server.ts +148 -0
- package/src/proto/packages/dht/protos/DhtRpc.ts +1399 -0
- package/src/proto/packages/proto-rpc/protos/ProtoRpc.ts +108 -0
- package/src/proto/packages/trackerless-network/protos/NetworkRpc.client.ts +176 -0
- package/src/proto/packages/trackerless-network/protos/NetworkRpc.server.ts +68 -0
- package/src/proto/packages/trackerless-network/protos/NetworkRpc.ts +667 -0
- package/test/benchmark/first-message.ts +155 -0
- package/test/end-to-end/inspect.test.ts +119 -0
- package/test/end-to-end/proxy-and-full-node.test.ts +140 -0
- package/test/end-to-end/proxy-connections.test.ts +228 -0
- package/test/end-to-end/proxy-key-exchange.test.ts +142 -0
- package/test/end-to-end/random-graph-with-real-connections.test.ts +154 -0
- package/test/end-to-end/webrtc-full-node-network.test.ts +97 -0
- package/test/end-to-end/websocket-full-node-network.test.ts +93 -0
- package/test/integration/Handshakes.test.ts +167 -0
- package/test/integration/Inspect.test.ts +102 -0
- package/test/integration/NetworkNode.test.ts +99 -0
- package/test/integration/NetworkRpc.test.ts +61 -0
- package/test/integration/NetworkStack.test.ts +74 -0
- package/test/integration/NetworkStackStoppedDuringStart.test.ts +45 -0
- package/test/integration/Propagation.test.ts +79 -0
- package/test/integration/RandomGraphNode-Layer1Node-Latencies.test.ts +141 -0
- package/test/integration/RandomGraphNode-Layer1Node.test.ts +226 -0
- package/test/integration/RemoteHandshaker.test.ts +78 -0
- package/test/integration/RemoteNeighborUpdateManager.test.ts +82 -0
- package/test/integration/RemoteRandomGraphNode.test.ts +102 -0
- package/test/integration/StreamrNode.test.ts +145 -0
- package/test/integration/stream-without-default-entrypoints.test.ts +132 -0
- package/test/unit/ContentMessageTranslator.test.ts +20 -0
- package/test/unit/DuplicateMessageDetector.test.ts +192 -0
- package/test/unit/FifoMapWithTtl.test.ts +229 -0
- package/test/unit/GroupKeyRequestTranslator.test.ts +36 -0
- package/test/unit/GroupKeyResponseTranslator.test.ts +39 -0
- package/test/unit/Handshaker.test.ts +63 -0
- package/test/unit/HandshakerServer.test.ts +123 -0
- package/test/unit/InspectSession.test.ts +78 -0
- package/test/unit/Inspector.test.ts +57 -0
- package/test/unit/NeighborFinder.test.ts +48 -0
- package/test/unit/NumberPair.test.ts +22 -0
- package/test/unit/PeerList.test.ts +150 -0
- package/test/unit/Propagation.test.ts +134 -0
- package/test/unit/RandomGraphNode.test.ts +73 -0
- package/test/unit/StreamEntrypointDiscovery.test.ts +152 -0
- package/test/unit/StreamMessageTranslator.test.ts +67 -0
- package/test/unit/StreamNodeServer.test.ts +63 -0
- package/test/unit/StreamrNode.test.ts +74 -0
- package/test/utils/mock/MockHandshaker.ts +15 -0
- package/test/utils/mock/MockLayer0.ts +71 -0
- package/test/utils/mock/MockLayer1.ts +6 -0
- package/test/utils/mock/MockNeighborFinder.ts +19 -0
- package/test/utils/mock/MockNeighborUpdateManager.ts +21 -0
- package/test/utils/mock/Transport.ts +25 -0
- package/test/utils/utils.ts +104 -0
- package/tsconfig.browser.json +12 -0
- package/tsconfig.jest.json +15 -0
- package/tsconfig.node.json +18 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { ListeningRpcCommunicator, PeerIDKey, peerIdFromPeerDescriptor } from '@streamr/dht'
|
|
2
|
+
import { Handshaker } from './neighbor-discovery/Handshaker'
|
|
3
|
+
import { NeighborFinder } from './neighbor-discovery/NeighborFinder'
|
|
4
|
+
import { NeighborUpdateManager } from './neighbor-discovery/NeighborUpdateManager'
|
|
5
|
+
import { StrictRandomGraphNodeConfig, RandomGraphNode } from './RandomGraphNode'
|
|
6
|
+
import { PeerList } from './PeerList'
|
|
7
|
+
import { Propagation } from './propagation/Propagation'
|
|
8
|
+
import { StreamMessage } from '../proto/packages/trackerless-network/protos/NetworkRpc'
|
|
9
|
+
import { MarkOptional } from 'ts-essentials'
|
|
10
|
+
import { ProxyStreamConnectionServer } from './proxy/ProxyStreamConnectionServer'
|
|
11
|
+
import { Inspector } from './inspect/Inspector'
|
|
12
|
+
import { TemporaryConnectionRpcServer } from './temporary-connection/TemporaryConnectionRpcServer'
|
|
13
|
+
|
|
14
|
+
type RandomGraphNodeConfig = MarkOptional<StrictRandomGraphNodeConfig,
|
|
15
|
+
'nearbyContactPool' | 'randomContactPool' | 'targetNeighbors' | 'propagation'
|
|
16
|
+
| 'handshaker' | 'neighborFinder' | 'neighborUpdateManager' | 'name' | 'numOfTargetNeighbors'
|
|
17
|
+
| 'maxNumberOfContacts' | 'minPropagationTargets' | 'rpcCommunicator' | 'peerViewSize' | 'acceptProxyConnections'
|
|
18
|
+
| 'neighborUpdateInterval' | 'inspector' | 'temporaryConnectionServer'>
|
|
19
|
+
|
|
20
|
+
const createConfigWithDefaults = (config: RandomGraphNodeConfig): StrictRandomGraphNodeConfig => {
|
|
21
|
+
const peerId = peerIdFromPeerDescriptor(config.ownPeerDescriptor)
|
|
22
|
+
const rpcCommunicator = config.rpcCommunicator ?? new ListeningRpcCommunicator(`layer2-${config.randomGraphId}`, config.P2PTransport)
|
|
23
|
+
const name = config.name ?? peerId.toKey()
|
|
24
|
+
const numOfTargetNeighbors = config.numOfTargetNeighbors ?? 4
|
|
25
|
+
const maxNumberOfContacts = config.maxNumberOfContacts ?? 20
|
|
26
|
+
const minPropagationTargets = config.minPropagationTargets ?? 2
|
|
27
|
+
const acceptProxyConnections = config.acceptProxyConnections ?? false
|
|
28
|
+
const neighborUpdateInterval = config.neighborUpdateInterval ?? 10000
|
|
29
|
+
const nearbyContactPool = config.nearbyContactPool ?? new PeerList(peerId, numOfTargetNeighbors + 1)
|
|
30
|
+
const randomContactPool = config.randomContactPool ?? new PeerList(peerId, maxNumberOfContacts)
|
|
31
|
+
const targetNeighbors = config.targetNeighbors ?? new PeerList(peerId, maxNumberOfContacts)
|
|
32
|
+
|
|
33
|
+
const temporaryConnectionServer = new TemporaryConnectionRpcServer({
|
|
34
|
+
randomGraphId: config.randomGraphId,
|
|
35
|
+
rpcCommunicator,
|
|
36
|
+
ownPeerId: peerId
|
|
37
|
+
})
|
|
38
|
+
const proxyConnectionServer = acceptProxyConnections ? new ProxyStreamConnectionServer({
|
|
39
|
+
ownPeerDescriptor: config.ownPeerDescriptor,
|
|
40
|
+
streamPartId: config.randomGraphId,
|
|
41
|
+
rpcCommunicator
|
|
42
|
+
}) : undefined
|
|
43
|
+
const propagation = config.propagation ?? new Propagation({
|
|
44
|
+
minPropagationTargets,
|
|
45
|
+
sendToNeighbor: async (neighborId: string, msg: StreamMessage): Promise<void> => {
|
|
46
|
+
const remote = targetNeighbors.getNeighborById(neighborId) ?? temporaryConnectionServer.getPeers().getNeighborById(neighborId)
|
|
47
|
+
const proxyConnection = proxyConnectionServer?.getConnection(neighborId as PeerIDKey)
|
|
48
|
+
if (remote) {
|
|
49
|
+
await remote.sendData(config.ownPeerDescriptor, msg)
|
|
50
|
+
} else if (proxyConnection) {
|
|
51
|
+
await proxyConnection.remote.sendData(config.ownPeerDescriptor, msg)
|
|
52
|
+
} else {
|
|
53
|
+
throw new Error('Propagation target not found')
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
const handshaker = config.handshaker ?? new Handshaker({
|
|
58
|
+
ownPeerDescriptor: config.ownPeerDescriptor,
|
|
59
|
+
randomGraphId: config.randomGraphId,
|
|
60
|
+
connectionLocker: config.connectionLocker,
|
|
61
|
+
rpcCommunicator,
|
|
62
|
+
nearbyContactPool,
|
|
63
|
+
randomContactPool,
|
|
64
|
+
targetNeighbors,
|
|
65
|
+
N: numOfTargetNeighbors
|
|
66
|
+
})
|
|
67
|
+
const neighborFinder = config.neighborFinder ?? new NeighborFinder({
|
|
68
|
+
targetNeighbors: targetNeighbors,
|
|
69
|
+
nearbyContactPool: nearbyContactPool,
|
|
70
|
+
doFindNeighbors: (excludedIds) => handshaker!.attemptHandshakesOnContacts(excludedIds),
|
|
71
|
+
N: numOfTargetNeighbors
|
|
72
|
+
})
|
|
73
|
+
const neighborUpdateManager = config.neighborUpdateManager ?? new NeighborUpdateManager({
|
|
74
|
+
targetNeighbors,
|
|
75
|
+
nearbyContactPool,
|
|
76
|
+
ownStringId: peerId.toKey(),
|
|
77
|
+
ownPeerDescriptor: config.ownPeerDescriptor,
|
|
78
|
+
neighborFinder,
|
|
79
|
+
randomGraphId: config.randomGraphId,
|
|
80
|
+
rpcCommunicator,
|
|
81
|
+
neighborUpdateInterval
|
|
82
|
+
})
|
|
83
|
+
const inspector = config.inspector ?? new Inspector({
|
|
84
|
+
ownPeerDescriptor: config.ownPeerDescriptor,
|
|
85
|
+
rpcCommunicator,
|
|
86
|
+
graphId: config.randomGraphId,
|
|
87
|
+
connectionLocker: config.connectionLocker
|
|
88
|
+
})
|
|
89
|
+
return {
|
|
90
|
+
...config,
|
|
91
|
+
nearbyContactPool,
|
|
92
|
+
randomContactPool,
|
|
93
|
+
targetNeighbors,
|
|
94
|
+
rpcCommunicator,
|
|
95
|
+
handshaker,
|
|
96
|
+
neighborFinder,
|
|
97
|
+
neighborUpdateManager,
|
|
98
|
+
propagation,
|
|
99
|
+
numOfTargetNeighbors,
|
|
100
|
+
minPropagationTargets,
|
|
101
|
+
maxNumberOfContacts,
|
|
102
|
+
name,
|
|
103
|
+
peerViewSize: maxNumberOfContacts,
|
|
104
|
+
acceptProxyConnections,
|
|
105
|
+
proxyConnectionServer,
|
|
106
|
+
neighborUpdateInterval,
|
|
107
|
+
inspector,
|
|
108
|
+
temporaryConnectionServer
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export const createRandomGraphNode = (config: RandomGraphNodeConfig): RandomGraphNode => {
|
|
113
|
+
return new RandomGraphNode(createConfigWithDefaults(config))
|
|
114
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { EventEmitter } from 'eventemitter3'
|
|
2
|
+
import { MessageRef } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
|
|
3
|
+
import { PeerIDKey } from '@streamr/dht'
|
|
4
|
+
|
|
5
|
+
export interface Events {
|
|
6
|
+
done: () => void
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface InspectSessionConfig {
|
|
10
|
+
inspectedPeer: PeerIDKey
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const createMessageKey = (messageRef: MessageRef): string => {
|
|
14
|
+
return `${messageRef.publisherId}:${messageRef.messageChainId}:${messageRef.timestamp}:${messageRef.sequenceNumber}`
|
|
15
|
+
}
|
|
16
|
+
export class InspectSession extends EventEmitter<Events> {
|
|
17
|
+
|
|
18
|
+
// Boolean indicates if the message has been received by the inspected node
|
|
19
|
+
private readonly inspectionMessages: Map<string, boolean> = new Map()
|
|
20
|
+
private readonly inspectedPeer: PeerIDKey
|
|
21
|
+
|
|
22
|
+
constructor(config: InspectSessionConfig) {
|
|
23
|
+
super()
|
|
24
|
+
this.inspectedPeer = config.inspectedPeer
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
markMessage(senderId: PeerIDKey, messageRef: MessageRef): void {
|
|
28
|
+
const messageKey = createMessageKey(messageRef)
|
|
29
|
+
if (!this.inspectionMessages.has(messageKey)) {
|
|
30
|
+
this.inspectionMessages.set(messageKey, senderId === this.inspectedPeer)
|
|
31
|
+
} else if (this.inspectionMessages.has(messageKey)
|
|
32
|
+
&& this.inspectionMessages.get(messageKey) === false
|
|
33
|
+
&& senderId === this.inspectedPeer
|
|
34
|
+
) {
|
|
35
|
+
this.emit('done')
|
|
36
|
+
} else if (this.inspectionMessages.has(messageKey)
|
|
37
|
+
&& this.inspectionMessages.get(messageKey) === true) {
|
|
38
|
+
this.emit('done')
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
getInspectedMessageCount(): number {
|
|
43
|
+
return this.inspectionMessages.size
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
stop(): void {
|
|
47
|
+
this.emit('done')
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { PeerIDKey, PeerDescriptor, keyFromPeerDescriptor, ConnectionLocker } from '@streamr/dht'
|
|
2
|
+
import { MessageRef } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
|
|
3
|
+
import { InspectSession, Events as InspectSessionEvents } from './InspectSession'
|
|
4
|
+
import { TemporaryConnectionRpcClient } from '../../proto/packages/trackerless-network/protos/NetworkRpc.client'
|
|
5
|
+
import { ProtoRpcClient, RpcCommunicator, toProtoRpcClient } from '@streamr/proto-rpc'
|
|
6
|
+
import { Logger, waitForEvent3 } from '@streamr/utils'
|
|
7
|
+
import { RemoteTemporaryConnectionRpcServer } from '../temporary-connection/RemoteTemporaryConnectionRpcServer'
|
|
8
|
+
|
|
9
|
+
interface InspectorConfig {
|
|
10
|
+
ownPeerDescriptor: PeerDescriptor
|
|
11
|
+
graphId: string
|
|
12
|
+
rpcCommunicator: RpcCommunicator
|
|
13
|
+
connectionLocker: ConnectionLocker
|
|
14
|
+
inspectionTimeout?: number
|
|
15
|
+
openInspectConnection?: (peerDescriptor: PeerDescriptor, lockId: string) => Promise<void>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface IInspector {
|
|
19
|
+
inspect(peerDescriptor: PeerDescriptor): Promise<boolean>
|
|
20
|
+
markMessage(sender: PeerIDKey, messageId: MessageRef): void
|
|
21
|
+
isInspected(nodeId: PeerIDKey): boolean
|
|
22
|
+
stop(): void
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const logger = new Logger(module)
|
|
26
|
+
const DEFAULT_TIMEOUT = 60 * 1000
|
|
27
|
+
|
|
28
|
+
export class Inspector implements IInspector {
|
|
29
|
+
|
|
30
|
+
private readonly sessions: Map<PeerIDKey, InspectSession> = new Map()
|
|
31
|
+
private readonly graphId: string
|
|
32
|
+
private readonly client: ProtoRpcClient<TemporaryConnectionRpcClient>
|
|
33
|
+
private readonly ownPeerDescriptor: PeerDescriptor
|
|
34
|
+
private readonly connectionLocker: ConnectionLocker
|
|
35
|
+
private readonly inspectionTimeout: number
|
|
36
|
+
private readonly openInspectConnection: (peerDescriptor: PeerDescriptor, lockId: string) => Promise<void>
|
|
37
|
+
|
|
38
|
+
constructor(config: InspectorConfig) {
|
|
39
|
+
this.graphId = config.graphId
|
|
40
|
+
this.ownPeerDescriptor = config.ownPeerDescriptor
|
|
41
|
+
this.client = toProtoRpcClient(new TemporaryConnectionRpcClient(config.rpcCommunicator.getRpcClientTransport()))
|
|
42
|
+
this.connectionLocker = config.connectionLocker
|
|
43
|
+
this.inspectionTimeout = config.inspectionTimeout ?? DEFAULT_TIMEOUT
|
|
44
|
+
this.openInspectConnection = config.openInspectConnection ?? this.defaultOpenInspectConnection
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async defaultOpenInspectConnection(peerDescriptor: PeerDescriptor, lockId: string): Promise<void> {
|
|
48
|
+
const remoteRandomGraphNode = new RemoteTemporaryConnectionRpcServer(peerDescriptor, this.graphId, this.client)
|
|
49
|
+
await remoteRandomGraphNode.openConnection(this.ownPeerDescriptor)
|
|
50
|
+
this.connectionLocker.lockConnection(peerDescriptor, lockId)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async inspect(peerDescriptor: PeerDescriptor): Promise<boolean> {
|
|
54
|
+
const nodeId = keyFromPeerDescriptor(peerDescriptor)
|
|
55
|
+
const session = new InspectSession({
|
|
56
|
+
inspectedPeer: nodeId
|
|
57
|
+
})
|
|
58
|
+
const lockId = `inspector-${this.graphId}`
|
|
59
|
+
this.sessions.set(nodeId, session)
|
|
60
|
+
await this.openInspectConnection(peerDescriptor, lockId)
|
|
61
|
+
let success = false
|
|
62
|
+
try {
|
|
63
|
+
await waitForEvent3<InspectSessionEvents>(session, 'done', this.inspectionTimeout)
|
|
64
|
+
success = true
|
|
65
|
+
} catch (err) {
|
|
66
|
+
logger.trace('Inspect session timed out, removing')
|
|
67
|
+
} finally {
|
|
68
|
+
this.sessions.delete(nodeId)
|
|
69
|
+
this.connectionLocker.unlockConnection(peerDescriptor, lockId)
|
|
70
|
+
}
|
|
71
|
+
return success || session.getInspectedMessageCount() < 1
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
markMessage(sender: PeerIDKey, messageId: MessageRef): void {
|
|
75
|
+
this.sessions.forEach((session) => session.markMessage(sender, messageId))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
isInspected(nodeId: PeerIDKey): boolean {
|
|
79
|
+
return this.sessions.has(nodeId)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
stop(): void {
|
|
83
|
+
this.sessions.forEach((session) => {
|
|
84
|
+
session.stop()
|
|
85
|
+
})
|
|
86
|
+
this.sessions.clear()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { ConnectionLocker, keyFromPeerDescriptor, PeerDescriptor } from '@streamr/dht'
|
|
2
|
+
import { PeerList } from '../PeerList'
|
|
3
|
+
import { RemoteRandomGraphNode } from '../RemoteRandomGraphNode'
|
|
4
|
+
import { ProtoRpcClient, RpcCommunicator, toProtoRpcClient } from '@streamr/proto-rpc'
|
|
5
|
+
import {
|
|
6
|
+
HandshakeRpcClient,
|
|
7
|
+
IHandshakeRpcClient, NetworkRpcClient
|
|
8
|
+
} from '../../proto/packages/trackerless-network/protos/NetworkRpc.client'
|
|
9
|
+
import {
|
|
10
|
+
InterleaveNotice,
|
|
11
|
+
StreamHandshakeRequest,
|
|
12
|
+
StreamHandshakeResponse
|
|
13
|
+
} from '../../proto/packages/trackerless-network/protos/NetworkRpc'
|
|
14
|
+
import { Logger } from '@streamr/utils'
|
|
15
|
+
import { IHandshakeRpc } from '../../proto/packages/trackerless-network/protos/NetworkRpc.server'
|
|
16
|
+
import { RemoteHandshaker } from './RemoteHandshaker'
|
|
17
|
+
import { HandshakerServer } from './HandshakerServer'
|
|
18
|
+
|
|
19
|
+
interface HandshakerConfig {
|
|
20
|
+
ownPeerDescriptor: PeerDescriptor
|
|
21
|
+
randomGraphId: string
|
|
22
|
+
connectionLocker: ConnectionLocker
|
|
23
|
+
targetNeighbors: PeerList
|
|
24
|
+
nearbyContactPool: PeerList
|
|
25
|
+
randomContactPool: PeerList
|
|
26
|
+
rpcCommunicator: RpcCommunicator
|
|
27
|
+
N: number
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const logger = new Logger(module)
|
|
31
|
+
|
|
32
|
+
const PARALLEL_HANDSHAKE_COUNT = 2
|
|
33
|
+
|
|
34
|
+
export interface IHandshaker {
|
|
35
|
+
attemptHandshakesOnContacts(excludedIds: string[]): Promise<string[]>
|
|
36
|
+
getOngoingHandshakes(): Set<string>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class Handshaker implements IHandshaker {
|
|
40
|
+
|
|
41
|
+
private readonly ongoingHandshakes: Set<string> = new Set()
|
|
42
|
+
private config: HandshakerConfig
|
|
43
|
+
private readonly client: ProtoRpcClient<IHandshakeRpcClient>
|
|
44
|
+
private readonly server: IHandshakeRpc
|
|
45
|
+
|
|
46
|
+
constructor(config: HandshakerConfig) {
|
|
47
|
+
this.config = config
|
|
48
|
+
this.client = toProtoRpcClient(new HandshakeRpcClient(this.config.rpcCommunicator.getRpcClientTransport()))
|
|
49
|
+
this.server = new HandshakerServer({
|
|
50
|
+
randomGraphId: this.config.randomGraphId,
|
|
51
|
+
ownPeerDescriptor: this.config.ownPeerDescriptor,
|
|
52
|
+
targetNeighbors: this.config.targetNeighbors,
|
|
53
|
+
connectionLocker: this.config.connectionLocker,
|
|
54
|
+
ongoingHandshakes: this.ongoingHandshakes,
|
|
55
|
+
N: this.config.N,
|
|
56
|
+
handshakeWithInterleaving: (target: PeerDescriptor, senderId: string) => this.handshakeWithInterleaving(target, senderId),
|
|
57
|
+
createRemoteHandshaker: (target: PeerDescriptor) => this.createRemoteHandshaker(target),
|
|
58
|
+
createRemoteNode: (target: PeerDescriptor) => this.createRemoteNode(target)
|
|
59
|
+
})
|
|
60
|
+
this.config.rpcCommunicator.registerRpcNotification(InterleaveNotice, 'interleaveNotice',
|
|
61
|
+
(req: InterleaveNotice, context) => this.server.interleaveNotice(req, context))
|
|
62
|
+
this.config.rpcCommunicator.registerRpcMethod(StreamHandshakeRequest, StreamHandshakeResponse, 'handshake',
|
|
63
|
+
(req: StreamHandshakeRequest, context) => this.server.handshake(req, context))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public async attemptHandshakesOnContacts(excludedIds: string[]): Promise<string[]> {
|
|
67
|
+
if (this.config.targetNeighbors!.size() + this.ongoingHandshakes.size < this.config.N - 2) {
|
|
68
|
+
logger.trace(`Attempting parallel handshakes with ${PARALLEL_HANDSHAKE_COUNT} targets`)
|
|
69
|
+
return this.selectParallelTargetsAndHandshake(excludedIds)
|
|
70
|
+
} else if (this.config.targetNeighbors!.size() + this.ongoingHandshakes.size < this.config.N) {
|
|
71
|
+
logger.trace(`Attempting handshake with new target`)
|
|
72
|
+
return this.selectNewTargetAndHandshake(excludedIds)
|
|
73
|
+
}
|
|
74
|
+
return excludedIds
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private async selectParallelTargetsAndHandshake(excludedIds: string[]): Promise<string[]> {
|
|
78
|
+
const exclude = excludedIds.concat(this.config.targetNeighbors.getStringIds())
|
|
79
|
+
const targetNeighbors = this.selectParallelTargets(exclude)
|
|
80
|
+
targetNeighbors.forEach((contact) => this.ongoingHandshakes.add(keyFromPeerDescriptor(contact.getPeerDescriptor())))
|
|
81
|
+
return this.doParallelHandshakes(targetNeighbors, exclude)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private selectParallelTargets(excludedIds: string[]): RemoteHandshaker[] {
|
|
85
|
+
const targetNeighbors = this.config.nearbyContactPool.getClosestAndFurthest(excludedIds)
|
|
86
|
+
while (targetNeighbors.length < PARALLEL_HANDSHAKE_COUNT && this.config.randomContactPool.size(excludedIds) > 0) {
|
|
87
|
+
const random = this.config.randomContactPool.getRandom(excludedIds)
|
|
88
|
+
if (random) {
|
|
89
|
+
targetNeighbors.push(random)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return targetNeighbors.map((neighbor) => this.createRemoteHandshaker(neighbor.getPeerDescriptor()))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private async doParallelHandshakes(targets: RemoteHandshaker[], excludedIds: string[]): Promise<string[]> {
|
|
96
|
+
const results = await Promise.allSettled(
|
|
97
|
+
Array.from(targets.values()).map(async (target: RemoteHandshaker, i) => {
|
|
98
|
+
const otherPeer = i === 0 ? targets[1] : targets[0]
|
|
99
|
+
const otherPeerStringId = otherPeer ? keyFromPeerDescriptor(otherPeer.getPeerDescriptor()) : undefined
|
|
100
|
+
return this.handshakeWithTarget(target, otherPeerStringId)
|
|
101
|
+
})
|
|
102
|
+
)
|
|
103
|
+
results.map((res, i) => {
|
|
104
|
+
if (res.status !== 'fulfilled' || !res.value) {
|
|
105
|
+
excludedIds.push(keyFromPeerDescriptor(targets[i].getPeerDescriptor()))
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
return excludedIds
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private async selectNewTargetAndHandshake(excludedIds: string[]): Promise<string[]> {
|
|
112
|
+
const exclude = excludedIds.concat(this.config.targetNeighbors.getStringIds())
|
|
113
|
+
const targetNeighbor = this.config.nearbyContactPool.getClosest(exclude) ?? this.config.randomContactPool.getRandom(exclude)
|
|
114
|
+
if (targetNeighbor) {
|
|
115
|
+
const accepted = await this.handshakeWithTarget(this.createRemoteHandshaker(targetNeighbor.getPeerDescriptor()))
|
|
116
|
+
if (!accepted) {
|
|
117
|
+
excludedIds.push(keyFromPeerDescriptor(targetNeighbor.getPeerDescriptor()))
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return excludedIds
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private async handshakeWithTarget(targetNeighbor: RemoteHandshaker, concurrentStringId?: string): Promise<boolean> {
|
|
124
|
+
const targetStringId = keyFromPeerDescriptor(targetNeighbor.getPeerDescriptor())
|
|
125
|
+
this.ongoingHandshakes.add(targetStringId)
|
|
126
|
+
const result = await targetNeighbor.handshake(
|
|
127
|
+
this.config.ownPeerDescriptor,
|
|
128
|
+
this.config.targetNeighbors.getStringIds(),
|
|
129
|
+
concurrentStringId
|
|
130
|
+
)
|
|
131
|
+
if (result.accepted) {
|
|
132
|
+
this.config.targetNeighbors.add(this.createRemoteNode(targetNeighbor.getPeerDescriptor()))
|
|
133
|
+
this.config.connectionLocker.lockConnection(targetNeighbor.getPeerDescriptor(), this.config.randomGraphId)
|
|
134
|
+
}
|
|
135
|
+
if (result.interleaveTarget) {
|
|
136
|
+
await this.handshakeWithInterleaving(result.interleaveTarget, targetStringId)
|
|
137
|
+
}
|
|
138
|
+
this.ongoingHandshakes.delete(targetStringId)
|
|
139
|
+
return result.accepted
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private async handshakeWithInterleaving(target: PeerDescriptor, interleavingFrom: string): Promise<boolean> {
|
|
143
|
+
const targetNeighbor = new RemoteHandshaker(
|
|
144
|
+
target,
|
|
145
|
+
this.config.randomGraphId,
|
|
146
|
+
this.client
|
|
147
|
+
)
|
|
148
|
+
const targetStringId = keyFromPeerDescriptor(targetNeighbor.getPeerDescriptor())
|
|
149
|
+
this.ongoingHandshakes.add(targetStringId)
|
|
150
|
+
const result = await targetNeighbor.handshake(
|
|
151
|
+
this.config.ownPeerDescriptor,
|
|
152
|
+
this.config.targetNeighbors.getStringIds(),
|
|
153
|
+
undefined,
|
|
154
|
+
interleavingFrom
|
|
155
|
+
)
|
|
156
|
+
if (result.accepted) {
|
|
157
|
+
this.config.targetNeighbors.add(this.createRemoteNode(targetNeighbor.getPeerDescriptor()))
|
|
158
|
+
this.config.connectionLocker.lockConnection(targetNeighbor.getPeerDescriptor(), this.config.randomGraphId)
|
|
159
|
+
}
|
|
160
|
+
this.ongoingHandshakes.delete(targetStringId)
|
|
161
|
+
return result.accepted
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private createRemoteHandshaker(targetPeerDescriptor: PeerDescriptor): RemoteHandshaker {
|
|
165
|
+
return new RemoteHandshaker(targetPeerDescriptor, this.config.randomGraphId, this.client)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private createRemoteNode(targetPeerDescriptor: PeerDescriptor): RemoteRandomGraphNode {
|
|
169
|
+
return new RemoteRandomGraphNode(
|
|
170
|
+
targetPeerDescriptor,
|
|
171
|
+
this.config.randomGraphId,
|
|
172
|
+
toProtoRpcClient(new NetworkRpcClient(this.config.rpcCommunicator!.getRpcClientTransport()))
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public getOngoingHandshakes(): Set<string> {
|
|
177
|
+
return this.ongoingHandshakes
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Empty } from '../../proto/google/protobuf/empty'
|
|
2
|
+
import { InterleaveNotice, StreamHandshakeRequest, StreamHandshakeResponse } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
|
|
3
|
+
import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
|
|
4
|
+
import { PeerList } from '../PeerList'
|
|
5
|
+
import { ConnectionLocker, keyFromPeerDescriptor, PeerDescriptor } from '@streamr/dht'
|
|
6
|
+
import { IHandshakeRpc } from '../../proto/packages/trackerless-network/protos/NetworkRpc.server'
|
|
7
|
+
import { RemoteHandshaker } from './RemoteHandshaker'
|
|
8
|
+
import { RemoteRandomGraphNode } from '../RemoteRandomGraphNode'
|
|
9
|
+
|
|
10
|
+
interface HandshakerServerConfig {
|
|
11
|
+
randomGraphId: string
|
|
12
|
+
ownPeerDescriptor: PeerDescriptor
|
|
13
|
+
targetNeighbors: PeerList
|
|
14
|
+
connectionLocker: ConnectionLocker
|
|
15
|
+
ongoingHandshakes: Set<string>
|
|
16
|
+
N: number
|
|
17
|
+
createRemoteHandshaker: (target: PeerDescriptor) => RemoteHandshaker
|
|
18
|
+
createRemoteNode: (peerDescriptor: PeerDescriptor) => RemoteRandomGraphNode
|
|
19
|
+
handshakeWithInterleaving: (target: PeerDescriptor, senderId: string) => Promise<boolean>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class HandshakerServer implements IHandshakeRpc {
|
|
23
|
+
|
|
24
|
+
private readonly config: HandshakerServerConfig
|
|
25
|
+
|
|
26
|
+
constructor(config: HandshakerServerConfig) {
|
|
27
|
+
this.config = config
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async handshake(request: StreamHandshakeRequest, _context: ServerCallContext): Promise<StreamHandshakeResponse> {
|
|
31
|
+
return this.handleRequest(request)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private handleRequest(request: StreamHandshakeRequest): StreamHandshakeResponse {
|
|
35
|
+
if (this.config.targetNeighbors!.hasPeer(request.senderDescriptor!)
|
|
36
|
+
|| this.config.ongoingHandshakes.has(keyFromPeerDescriptor(request.senderDescriptor!))
|
|
37
|
+
) {
|
|
38
|
+
return this.acceptHandshake(request, request.senderDescriptor!)
|
|
39
|
+
} else if (this.config.targetNeighbors!.size() + this.config.ongoingHandshakes.size < this.config.N) {
|
|
40
|
+
return this.acceptHandshake(request, request.senderDescriptor!)
|
|
41
|
+
} else if (this.config.targetNeighbors!.size([request.interleavingFrom!]) >= 2) {
|
|
42
|
+
return this.acceptHandshakeWithInterleaving(request, request.senderDescriptor!)
|
|
43
|
+
} else {
|
|
44
|
+
return this.rejectHandshake(request)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private acceptHandshake(request: StreamHandshakeRequest, requester: PeerDescriptor) {
|
|
49
|
+
const res: StreamHandshakeResponse = {
|
|
50
|
+
requestId: request.requestId,
|
|
51
|
+
accepted: true
|
|
52
|
+
}
|
|
53
|
+
this.config.targetNeighbors.add(this.config.createRemoteNode(requester))
|
|
54
|
+
this.config.connectionLocker.lockConnection(request.senderDescriptor!, this.config.randomGraphId)
|
|
55
|
+
return res
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// eslint-disable-next-line class-methods-use-this
|
|
59
|
+
private rejectHandshake(request: StreamHandshakeRequest) {
|
|
60
|
+
const res: StreamHandshakeResponse = {
|
|
61
|
+
requestId: request.requestId,
|
|
62
|
+
accepted: false
|
|
63
|
+
}
|
|
64
|
+
return res
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private acceptHandshakeWithInterleaving(request: StreamHandshakeRequest, requester: PeerDescriptor): StreamHandshakeResponse {
|
|
68
|
+
const exclude = request.neighbors
|
|
69
|
+
exclude.push(request.senderId)
|
|
70
|
+
exclude.push(request.interleavingFrom!)
|
|
71
|
+
const furthest = this.config.targetNeighbors.getFurthest(exclude)
|
|
72
|
+
const furthestPeerDescriptor = furthest ? furthest.getPeerDescriptor() : undefined
|
|
73
|
+
if (furthest) {
|
|
74
|
+
const remote = this.config.createRemoteHandshaker(furthest.getPeerDescriptor())
|
|
75
|
+
remote.interleaveNotice(this.config.ownPeerDescriptor, request.senderDescriptor!)
|
|
76
|
+
this.config.targetNeighbors.remove(furthest.getPeerDescriptor())
|
|
77
|
+
this.config.connectionLocker.unlockConnection(furthestPeerDescriptor!, this.config.randomGraphId)
|
|
78
|
+
}
|
|
79
|
+
this.config.targetNeighbors.add(this.config.createRemoteNode(requester))
|
|
80
|
+
this.config.connectionLocker.lockConnection(request.senderDescriptor!, this.config.randomGraphId)
|
|
81
|
+
return {
|
|
82
|
+
requestId: request.requestId,
|
|
83
|
+
accepted: true,
|
|
84
|
+
interleaveTarget: furthestPeerDescriptor
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async interleaveNotice(message: InterleaveNotice, _context: ServerCallContext): Promise<Empty> {
|
|
89
|
+
if (message.randomGraphId === this.config.randomGraphId) {
|
|
90
|
+
if (this.config.targetNeighbors.hasPeerWithStringId(message.senderId)) {
|
|
91
|
+
const senderDescriptor = this.config.targetNeighbors.getNeighborById(message.senderId)!.getPeerDescriptor()
|
|
92
|
+
this.config.connectionLocker.unlockConnection(senderDescriptor, this.config.randomGraphId)
|
|
93
|
+
this.config.targetNeighbors.remove(senderDescriptor)
|
|
94
|
+
}
|
|
95
|
+
this.config.handshakeWithInterleaving(message.interleaveTarget!, message.senderId).catch((_e) => {})
|
|
96
|
+
}
|
|
97
|
+
return Empty
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { setAbortableTimeout } from '@streamr/utils'
|
|
2
|
+
import { PeerList } from '../PeerList'
|
|
3
|
+
|
|
4
|
+
interface FindNeighborsSessionConfig {
|
|
5
|
+
targetNeighbors: PeerList
|
|
6
|
+
nearbyContactPool: PeerList
|
|
7
|
+
doFindNeighbors: (excludedNodes: string[]) => Promise<string[]>
|
|
8
|
+
N: number
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const INITIAL_TIMEOUT = 100
|
|
12
|
+
const INTERVAL_TIMEOUT = 250
|
|
13
|
+
|
|
14
|
+
export interface INeighborFinder {
|
|
15
|
+
start(excluded?: string[]): void
|
|
16
|
+
stop(): void
|
|
17
|
+
isRunning(): boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class NeighborFinder implements INeighborFinder {
|
|
21
|
+
private readonly abortController: AbortController
|
|
22
|
+
private readonly config: FindNeighborsSessionConfig
|
|
23
|
+
private running = false
|
|
24
|
+
|
|
25
|
+
constructor(config: FindNeighborsSessionConfig) {
|
|
26
|
+
this.config = config
|
|
27
|
+
this.abortController = new AbortController()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private async findNeighbors(excluded: string[]): Promise<void> {
|
|
31
|
+
if (!this.running) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
const newExcludes = await this.config.doFindNeighbors(excluded)
|
|
35
|
+
if (this.config.targetNeighbors!.size() < this.config.N && newExcludes.length < this.config.nearbyContactPool!.size()) {
|
|
36
|
+
setAbortableTimeout(() => this.findNeighbors(newExcludes), INTERVAL_TIMEOUT, this.abortController.signal)
|
|
37
|
+
} else {
|
|
38
|
+
this.running = false
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
isRunning(): boolean {
|
|
43
|
+
return this.running
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
start(excluded: string[] = []): void {
|
|
47
|
+
if (this.running) {
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
this.running = true
|
|
51
|
+
setAbortableTimeout(() => this.findNeighbors(excluded), INITIAL_TIMEOUT, this.abortController.signal)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
stop(): void {
|
|
55
|
+
if (!this.running) {
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
this.running = false
|
|
59
|
+
this.abortController.abort()
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { NeighborUpdate } from '../../proto/packages/trackerless-network/protos/NetworkRpc'
|
|
2
|
+
import { keyFromPeerDescriptor, ListeningRpcCommunicator, PeerDescriptor } from '@streamr/dht'
|
|
3
|
+
import { ProtoRpcClient, toProtoRpcClient } from '@streamr/proto-rpc'
|
|
4
|
+
import { NeighborUpdateRpcClient } from '../../proto/packages/trackerless-network/protos/NetworkRpc.client'
|
|
5
|
+
import { Logger, scheduleAtInterval } from '@streamr/utils'
|
|
6
|
+
import { PeerIDKey } from '@streamr/dht/dist/src/helpers/PeerID'
|
|
7
|
+
import { INeighborFinder } from './NeighborFinder'
|
|
8
|
+
import { PeerList } from '../PeerList'
|
|
9
|
+
import { RemoteNeighborUpdateManager } from './RemoteNeighborUpdateManager'
|
|
10
|
+
import { NeighborUpdateManagerServer } from './NeighborUpdateManagerServer'
|
|
11
|
+
|
|
12
|
+
interface NeighborUpdateManagerConfig {
|
|
13
|
+
ownStringId: PeerIDKey
|
|
14
|
+
ownPeerDescriptor: PeerDescriptor
|
|
15
|
+
targetNeighbors: PeerList
|
|
16
|
+
nearbyContactPool: PeerList
|
|
17
|
+
neighborFinder: INeighborFinder
|
|
18
|
+
randomGraphId: string
|
|
19
|
+
rpcCommunicator: ListeningRpcCommunicator
|
|
20
|
+
neighborUpdateInterval: number
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const logger = new Logger(module)
|
|
24
|
+
|
|
25
|
+
export interface INeighborUpdateManager {
|
|
26
|
+
start(): Promise<void>
|
|
27
|
+
stop(): void
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class NeighborUpdateManager implements INeighborUpdateManager {
|
|
31
|
+
private readonly abortController: AbortController
|
|
32
|
+
private readonly config: NeighborUpdateManagerConfig
|
|
33
|
+
private readonly client: ProtoRpcClient<NeighborUpdateRpcClient>
|
|
34
|
+
private readonly server: NeighborUpdateManagerServer
|
|
35
|
+
constructor(config: NeighborUpdateManagerConfig) {
|
|
36
|
+
this.abortController = new AbortController()
|
|
37
|
+
this.client = toProtoRpcClient(new NeighborUpdateRpcClient(config.rpcCommunicator.getRpcClientTransport()))
|
|
38
|
+
this.server = new NeighborUpdateManagerServer(config)
|
|
39
|
+
this.config = config
|
|
40
|
+
this.config.rpcCommunicator.registerRpcMethod(NeighborUpdate, NeighborUpdate, 'neighborUpdate',
|
|
41
|
+
(req: NeighborUpdate, context) => this.server.neighborUpdate(req, context))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public async start(): Promise<void> {
|
|
45
|
+
await scheduleAtInterval(() => this.updateNeighborInfo(), this.config.neighborUpdateInterval, false, this.abortController.signal)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public stop(): void {
|
|
49
|
+
this.abortController.abort()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private async updateNeighborInfo(): Promise<void> {
|
|
53
|
+
logger.trace(`Updating neighbor info to peers`)
|
|
54
|
+
const neighborDescriptors = this.config.targetNeighbors!.getPeers().map((neighbor) => neighbor.getPeerDescriptor())
|
|
55
|
+
await Promise.allSettled(this.config.targetNeighbors!.getPeers().map(async (neighbor) => {
|
|
56
|
+
const res = await this.createRemote(neighbor.getPeerDescriptor()).updateNeighbors(this.config.ownPeerDescriptor, neighborDescriptors)
|
|
57
|
+
if (res.removeMe) {
|
|
58
|
+
this.config.targetNeighbors!.remove(neighbor.getPeerDescriptor())
|
|
59
|
+
this.config.neighborFinder!.start([keyFromPeerDescriptor(neighbor.getPeerDescriptor())])
|
|
60
|
+
}
|
|
61
|
+
}))
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private createRemote(targetPeerDescriptor: PeerDescriptor): RemoteNeighborUpdateManager {
|
|
65
|
+
return new RemoteNeighborUpdateManager(targetPeerDescriptor, this.config.randomGraphId, this.client)
|
|
66
|
+
}
|
|
67
|
+
}
|