@streamr/dht 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 +5 -0
- package/.eslintrc +3 -0
- package/README.md +38 -0
- package/dist/src/connection/Connection.d.ts +11 -0
- package/dist/src/connection/Connection.js +23 -0
- package/dist/src/connection/Connection.js.map +1 -0
- package/dist/src/connection/ConnectionLockHandler.d.ts +23 -0
- package/dist/src/connection/ConnectionLockHandler.js +94 -0
- package/dist/src/connection/ConnectionLockHandler.js.map +1 -0
- package/dist/src/connection/ConnectionManager.d.ts +94 -0
- package/dist/src/connection/ConnectionManager.js +554 -0
- package/dist/src/connection/ConnectionManager.js.map +1 -0
- package/dist/src/connection/ConnectivityChecker.d.ts +17 -0
- package/dist/src/connection/ConnectivityChecker.js +187 -0
- package/dist/src/connection/ConnectivityChecker.js.map +1 -0
- package/dist/src/connection/Handshaker.d.ts +19 -0
- package/dist/src/connection/Handshaker.js +77 -0
- package/dist/src/connection/Handshaker.js.map +1 -0
- package/dist/src/connection/IConnection.d.ts +38 -0
- package/dist/src/connection/IConnection.js +19 -0
- package/dist/src/connection/IConnection.js.map +1 -0
- package/dist/src/connection/IConnectionSource.d.ts +4 -0
- package/dist/src/connection/IConnectionSource.js +3 -0
- package/dist/src/connection/IConnectionSource.js.map +1 -0
- package/dist/src/connection/ManagedConnection.d.ts +60 -0
- package/dist/src/connection/ManagedConnection.js +352 -0
- package/dist/src/connection/ManagedConnection.js.map +1 -0
- package/dist/src/connection/ManagedWebRtcConnection.d.ts +7 -0
- package/dist/src/connection/ManagedWebRtcConnection.js +20 -0
- package/dist/src/connection/ManagedWebRtcConnection.js.map +1 -0
- package/dist/src/connection/RemoteConnectionLocker.d.ts +14 -0
- package/dist/src/connection/RemoteConnectionLocker.js +93 -0
- package/dist/src/connection/RemoteConnectionLocker.js.map +1 -0
- package/dist/src/connection/Simulator/Simulator.d.ts +42 -0
- package/dist/src/connection/Simulator/Simulator.js +325 -0
- package/dist/src/connection/Simulator/Simulator.js.map +1 -0
- package/dist/src/connection/Simulator/SimulatorConnection.d.ts +19 -0
- package/dist/src/connection/Simulator/SimulatorConnection.js +118 -0
- package/dist/src/connection/Simulator/SimulatorConnection.js.map +1 -0
- package/dist/src/connection/Simulator/SimulatorConnector.d.ts +17 -0
- package/dist/src/connection/Simulator/SimulatorConnector.js +72 -0
- package/dist/src/connection/Simulator/SimulatorConnector.js.map +1 -0
- package/dist/src/connection/Simulator/SimulatorTransport.d.ts +6 -0
- package/dist/src/connection/Simulator/SimulatorTransport.js +11 -0
- package/dist/src/connection/Simulator/SimulatorTransport.js.map +1 -0
- package/dist/src/connection/Simulator/pings.d.ts +21 -0
- package/dist/src/connection/Simulator/pings.js +61 -0
- package/dist/src/connection/Simulator/pings.js.map +1 -0
- package/dist/src/connection/WebRTC/IWebRtcConnection.d.ts +20 -0
- package/dist/src/connection/WebRTC/IWebRtcConnection.js +9 -0
- package/dist/src/connection/WebRTC/IWebRtcConnection.js.map +1 -0
- package/dist/src/connection/WebRTC/NodeWebRtcConnection.d.ts +47 -0
- package/dist/src/connection/WebRTC/NodeWebRtcConnection.js +233 -0
- package/dist/src/connection/WebRTC/NodeWebRtcConnection.js.map +1 -0
- package/dist/src/connection/WebRTC/RemoteWebrtcConnector.d.ts +12 -0
- package/dist/src/connection/WebRTC/RemoteWebrtcConnector.js +74 -0
- package/dist/src/connection/WebRTC/RemoteWebrtcConnector.js.map +1 -0
- package/dist/src/connection/WebRTC/WebRtcConnector.d.ts +47 -0
- package/dist/src/connection/WebRTC/WebRtcConnector.js +227 -0
- package/dist/src/connection/WebRTC/WebRtcConnector.js.map +1 -0
- package/dist/src/connection/WebRTC/iceServerAsString.d.ts +2 -0
- package/dist/src/connection/WebRTC/iceServerAsString.js +18 -0
- package/dist/src/connection/WebRTC/iceServerAsString.js.map +1 -0
- package/dist/src/connection/WebSocket/ClientWebSocket.d.ts +15 -0
- package/dist/src/connection/WebSocket/ClientWebSocket.js +113 -0
- package/dist/src/connection/WebSocket/ClientWebSocket.js.map +1 -0
- package/dist/src/connection/WebSocket/RemoteWebSocketConnector.d.ts +9 -0
- package/dist/src/connection/WebSocket/RemoteWebSocketConnector.js +63 -0
- package/dist/src/connection/WebSocket/RemoteWebSocketConnector.js.map +1 -0
- package/dist/src/connection/WebSocket/ServerWebSocket.d.ts +18 -0
- package/dist/src/connection/WebSocket/ServerWebSocket.js +103 -0
- package/dist/src/connection/WebSocket/ServerWebSocket.js.map +1 -0
- package/dist/src/connection/WebSocket/WebSocketConnector.d.ts +31 -0
- package/dist/src/connection/WebSocket/WebSocketConnector.js +202 -0
- package/dist/src/connection/WebSocket/WebSocketConnector.js.map +1 -0
- package/dist/src/connection/WebSocket/WebSocketServer.d.ts +9 -0
- package/dist/src/connection/WebSocket/WebSocketServer.js +101 -0
- package/dist/src/connection/WebSocket/WebSocketServer.js.map +1 -0
- package/dist/src/dht/DhtNode.d.ts +153 -0
- package/dist/src/dht/DhtNode.js +599 -0
- package/dist/src/dht/DhtNode.js.map +1 -0
- package/dist/src/dht/DhtPeer.d.ts +18 -0
- package/dist/src/dht/DhtPeer.js +74 -0
- package/dist/src/dht/DhtPeer.js.map +1 -0
- package/dist/src/dht/ExternalApi.d.ts +8 -0
- package/dist/src/dht/ExternalApi.js +26 -0
- package/dist/src/dht/ExternalApi.js.map +1 -0
- package/dist/src/dht/RemoteExternalApi.d.ts +6 -0
- package/dist/src/dht/RemoteExternalApi.js +26 -0
- package/dist/src/dht/RemoteExternalApi.js.map +1 -0
- package/dist/src/dht/contact/Contact.d.ts +22 -0
- package/dist/src/dht/contact/Contact.js +25 -0
- package/dist/src/dht/contact/Contact.js.map +1 -0
- package/dist/src/dht/contact/RandomContactList.d.ts +20 -0
- package/dist/src/dht/contact/RandomContactList.js +78 -0
- package/dist/src/dht/contact/RandomContactList.js.map +1 -0
- package/dist/src/dht/contact/Remote.d.ts +15 -0
- package/dist/src/dht/contact/Remote.js +24 -0
- package/dist/src/dht/contact/Remote.js.map +1 -0
- package/dist/src/dht/contact/SortedContactList.d.ts +35 -0
- package/dist/src/dht/contact/SortedContactList.js +156 -0
- package/dist/src/dht/contact/SortedContactList.js.map +1 -0
- package/dist/src/dht/discovery/DiscoverySession.d.ts +36 -0
- package/dist/src/dht/discovery/DiscoverySession.js +116 -0
- package/dist/src/dht/discovery/DiscoverySession.js.map +1 -0
- package/dist/src/dht/discovery/PeerDiscovery.d.ts +42 -0
- package/dist/src/dht/discovery/PeerDiscovery.js +157 -0
- package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -0
- package/dist/src/dht/find/RecursiveFindSession.d.ts +46 -0
- package/dist/src/dht/find/RecursiveFindSession.js +142 -0
- package/dist/src/dht/find/RecursiveFindSession.js.map +1 -0
- package/dist/src/dht/find/RecursiveFinder.d.ts +54 -0
- package/dist/src/dht/find/RecursiveFinder.js +180 -0
- package/dist/src/dht/find/RecursiveFinder.js.map +1 -0
- package/dist/src/dht/find/RemoteRecursiveFindSession.d.ts +6 -0
- package/dist/src/dht/find/RemoteRecursiveFindSession.js +25 -0
- package/dist/src/dht/find/RemoteRecursiveFindSession.js.map +1 -0
- package/dist/src/dht/routing/DuplicateDetector.d.ts +13 -0
- package/dist/src/dht/routing/DuplicateDetector.js +41 -0
- package/dist/src/dht/routing/DuplicateDetector.js.map +1 -0
- package/dist/src/dht/routing/RemoteRouter.d.ts +8 -0
- package/dist/src/dht/routing/RemoteRouter.js +106 -0
- package/dist/src/dht/routing/RemoteRouter.js.map +1 -0
- package/dist/src/dht/routing/Router.d.ts +60 -0
- package/dist/src/dht/routing/Router.js +207 -0
- package/dist/src/dht/routing/Router.js.map +1 -0
- package/dist/src/dht/routing/RoutingSession.d.ts +42 -0
- package/dist/src/dht/routing/RoutingSession.js +178 -0
- package/dist/src/dht/routing/RoutingSession.js.map +1 -0
- package/dist/src/dht/store/DataStore.d.ts +45 -0
- package/dist/src/dht/store/DataStore.js +244 -0
- package/dist/src/dht/store/DataStore.js.map +1 -0
- package/dist/src/dht/store/LocalDataStore.d.ts +19 -0
- package/dist/src/dht/store/LocalDataStore.js +104 -0
- package/dist/src/dht/store/LocalDataStore.js.map +1 -0
- package/dist/src/dht/store/RemoteStore.d.ts +8 -0
- package/dist/src/dht/store/RemoteStore.js +44 -0
- package/dist/src/dht/store/RemoteStore.js.map +1 -0
- package/dist/src/exports.d.ts +19 -0
- package/dist/src/exports.js +41 -0
- package/dist/src/exports.js.map +1 -0
- package/dist/src/helpers/AddressTools.d.ts +2 -0
- package/dist/src/helpers/AddressTools.js +31 -0
- package/dist/src/helpers/AddressTools.js.map +1 -0
- package/dist/src/helpers/PeerID.d.ts +25 -0
- package/dist/src/helpers/PeerID.js +84 -0
- package/dist/src/helpers/PeerID.js.map +1 -0
- package/dist/src/helpers/UUID.d.ts +7 -0
- package/dist/src/helpers/UUID.js +32 -0
- package/dist/src/helpers/UUID.js.map +1 -0
- package/dist/src/helpers/debugHelpers.d.ts +3 -0
- package/dist/src/helpers/debugHelpers.js +11 -0
- package/dist/src/helpers/debugHelpers.js.map +1 -0
- package/dist/src/helpers/errors.d.ts +72 -0
- package/dist/src/helpers/errors.js +95 -0
- package/dist/src/helpers/errors.js.map +1 -0
- package/dist/src/helpers/peerIdFromPeerDescriptor.d.ts +5 -0
- package/dist/src/helpers/peerIdFromPeerDescriptor.js +17 -0
- package/dist/src/helpers/peerIdFromPeerDescriptor.js.map +1 -0
- package/dist/src/helpers/protoClasses.d.ts +2 -0
- package/dist/src/helpers/protoClasses.js +35 -0
- package/dist/src/helpers/protoClasses.js.map +1 -0
- package/dist/src/helpers/protoToString.d.ts +2 -0
- package/dist/src/helpers/protoToString.js +20 -0
- package/dist/src/helpers/protoToString.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/tests.d.ts +39 -0
- package/dist/src/proto/tests.js +34 -0
- package/dist/src/proto/tests.js.map +1 -0
- package/dist/src/rpc-protocol/DhtCallContext.d.ts +12 -0
- package/dist/src/rpc-protocol/DhtCallContext.js +8 -0
- package/dist/src/rpc-protocol/DhtCallContext.js.map +1 -0
- package/dist/src/rpc-protocol/DhtRpcOptions.d.ts +8 -0
- package/dist/src/rpc-protocol/DhtRpcOptions.js +3 -0
- package/dist/src/rpc-protocol/DhtRpcOptions.js.map +1 -0
- package/dist/src/transport/ITransport.d.ts +22 -0
- package/dist/src/transport/ITransport.js +3 -0
- package/dist/src/transport/ITransport.js.map +1 -0
- package/dist/src/transport/ListeningRpcCommunicator.d.ts +6 -0
- package/dist/src/transport/ListeningRpcCommunicator.js +14 -0
- package/dist/src/transport/ListeningRpcCommunicator.js.map +1 -0
- package/dist/src/transport/RoutingRpcCommunicator.d.ts +8 -0
- package/dist/src/transport/RoutingRpcCommunicator.js +52 -0
- package/dist/src/transport/RoutingRpcCommunicator.js.map +1 -0
- package/jest.config.js +2 -0
- package/karma.config.js +20 -0
- package/package.json +64 -0
- package/proto.sh +3 -0
- package/protos/DhtRpc.proto +330 -0
- package/protos/tests.proto +16 -0
- package/src/connection/Connection.ts +23 -0
- package/src/connection/ConnectionLockHandler.ts +105 -0
- package/src/connection/ConnectionManager.ts +676 -0
- package/src/connection/ConnectivityChecker.ts +173 -0
- package/src/connection/Handshaker.ts +92 -0
- package/src/connection/IConnection.ts +47 -0
- package/src/connection/IConnectionSource.ts +6 -0
- package/src/connection/ManagedConnection.ts +398 -0
- package/src/connection/ManagedWebRtcConnection.ts +27 -0
- package/src/connection/RemoteConnectionLocker.ts +88 -0
- package/src/connection/Simulator/Simulator.ts +399 -0
- package/src/connection/Simulator/SimulatorConnection.ts +137 -0
- package/src/connection/Simulator/SimulatorConnector.ts +104 -0
- package/src/connection/Simulator/SimulatorTransport.ts +9 -0
- package/src/connection/Simulator/pings.ts +42 -0
- package/src/connection/WebRTC/BrowserWebRtcConnection.ts +227 -0
- package/src/connection/WebRTC/IWebRtcConnection.ts +24 -0
- package/src/connection/WebRTC/NodeWebRtcConnection.ts +256 -0
- package/src/connection/WebRTC/RemoteWebrtcConnector.ts +93 -0
- package/src/connection/WebRTC/WebRtcConnector.ts +306 -0
- package/src/connection/WebRTC/iceServerAsString.ts +15 -0
- package/src/connection/WebSocket/ClientWebSocket.ts +118 -0
- package/src/connection/WebSocket/RemoteWebSocketConnector.ts +49 -0
- package/src/connection/WebSocket/ServerWebSocket.ts +119 -0
- package/src/connection/WebSocket/WebSocketConnector.ts +264 -0
- package/src/connection/WebSocket/WebSocketServer.ts +97 -0
- package/src/dht/DhtNode.ts +776 -0
- package/src/dht/DhtPeer.ts +96 -0
- package/src/dht/ExternalApi.ts +29 -0
- package/src/dht/RemoteExternalApi.ts +25 -0
- package/src/dht/contact/Contact.ts +36 -0
- package/src/dht/contact/RandomContactList.ts +92 -0
- package/src/dht/contact/Remote.ts +40 -0
- package/src/dht/contact/SortedContactList.ts +196 -0
- package/src/dht/discovery/DiscoverySession.ts +150 -0
- package/src/dht/discovery/PeerDiscovery.ts +162 -0
- package/src/dht/find/RecursiveFindSession.ts +178 -0
- package/src/dht/find/RecursiveFinder.ts +272 -0
- package/src/dht/find/RemoteRecursiveFindSession.ts +33 -0
- package/src/dht/routing/DuplicateDetector.ts +53 -0
- package/src/dht/routing/RemoteRouter.ts +115 -0
- package/src/dht/routing/Router.ts +266 -0
- package/src/dht/routing/RoutingSession.ts +222 -0
- package/src/dht/store/DataStore.ts +321 -0
- package/src/dht/store/LocalDataStore.ts +114 -0
- package/src/dht/store/RemoteStore.ts +58 -0
- package/src/exports.ts +19 -0
- package/src/helpers/AddressTools.ts +26 -0
- package/src/helpers/PeerID.ts +95 -0
- package/src/helpers/UUID.ts +30 -0
- package/src/helpers/debugHelpers.ts +9 -0
- package/src/helpers/errors.ts +49 -0
- package/src/helpers/peerIdFromPeerDescriptor.ts +14 -0
- package/src/helpers/protoClasses.ts +63 -0
- package/src/helpers/protoToString.ts +21 -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/tests.ts +52 -0
- package/src/rpc-protocol/DhtCallContext.ts +15 -0
- package/src/rpc-protocol/DhtRpcOptions.ts +9 -0
- package/src/transport/ITransport.ts +31 -0
- package/src/transport/ListeningRpcCommunicator.ts +14 -0
- package/src/transport/RoutingRpcCommunicator.ts +59 -0
- package/src/types/glogal.d.ts +1 -0
- package/src/types/textencoding.d.ts +7 -0
- package/test/RandomGraphSimulation.ts +52 -0
- package/test/benchmark/KademliaCorrectness.test.ts +115 -0
- package/test/benchmark/RecursiveFind.test.ts +87 -0
- package/test/benchmark/any.test.ts +28 -0
- package/test/benchmark/kademlia-simulation/Contact.ts +32 -0
- package/test/benchmark/kademlia-simulation/KademliaSimulation.ts +94 -0
- package/test/benchmark/kademlia-simulation/SimulationNode.ts +125 -0
- package/test/data/generateGroundTruthData.ts +70 -0
- package/test/end-to-end/Layer0-Layer1.test.ts +87 -0
- package/test/end-to-end/Layer0.test.ts +60 -0
- package/test/end-to-end/Layer0MixedConnectionTypes.test.ts +94 -0
- package/test/end-to-end/Layer0WebRTC-Layer1.test.ts +134 -0
- package/test/end-to-end/Layer0WebRTC.test.ts +98 -0
- package/test/end-to-end/Layer1-Scale-WebRTC.test.ts +69 -0
- package/test/end-to-end/Layer1-Scale-WebSocket.test.ts +73 -0
- package/test/end-to-end/WebSocketConnectionRequest.test.ts +62 -0
- package/test/integration/ConnectionLocking.test.ts +166 -0
- package/test/integration/ConnectionManager.test.ts +291 -0
- package/test/integration/DhtNodeExternalAPI.test.ts +43 -0
- package/test/integration/DhtPeer.test.ts +73 -0
- package/test/integration/DhtRpc.test.ts +131 -0
- package/test/integration/DhtWithMockConnectionLatencies.test.ts +46 -0
- package/test/integration/DhtWithMockConnections.test.ts +46 -0
- package/test/integration/DhtWithRealConnectionLatencies.test.ts +47 -0
- package/test/integration/Layer1-scale.test.ts +200 -0
- package/test/integration/MigrateData.test.ts +203 -0
- package/test/integration/Mock-Layer1-Layer0.test.ts +106 -0
- package/test/integration/MultipleEntryPointJoining.test.ts +105 -0
- package/test/integration/RecursiveFind.test.ts +50 -0
- package/test/integration/RemoteRouter.test.ts +83 -0
- package/test/integration/RemoteStore.test.ts +66 -0
- package/test/integration/RouteMessage.test.ts +254 -0
- package/test/integration/RpcErrors.test.ts +153 -0
- package/test/integration/ScaleDownDht.test.ts +66 -0
- package/test/integration/SimultaneousConnections.test.ts +308 -0
- package/test/integration/Store.test.ts +72 -0
- package/test/integration/StoreAndDelete.test.ts +93 -0
- package/test/integration/StoreOnDhtWithTwoNodes.test.ts +71 -0
- package/test/integration/WebRtcConnectionManagement.test.ts +205 -0
- package/test/integration/WebRtcConnectorRpc.test.ts +145 -0
- package/test/integration/WebSocket.test.ts +64 -0
- package/test/integration/WebSocketConnectionManagement.test.ts +131 -0
- package/test/integration/WebSocketConnectorRpc.test.ts +86 -0
- package/test/kademlia-simulation/data/nodeids.json +13002 -0
- package/test/kademlia-simulation/data/orderedneighbors.json +1001 -0
- package/test/unit/AddressTools.test.ts +40 -0
- package/test/unit/DuplicateDetector.test.ts +29 -0
- package/test/unit/LocalDataStore.test.ts +107 -0
- package/test/unit/PeerID.test.ts +22 -0
- package/test/unit/ProtobufMessage.test.ts +21 -0
- package/test/unit/RandomContactList.test.ts +87 -0
- package/test/unit/RecursiveFinder.test.ts +112 -0
- package/test/unit/Router.test.ts +124 -0
- package/test/unit/SortedContactList.test.ts +127 -0
- package/test/unit/UUID.test.ts +49 -0
- package/test/unit/WebSocketServer.test.ts +42 -0
- package/test/utils/mock/RecursiveFinder.ts +19 -0
- package/test/utils/mock/Router.ts +53 -0
- package/test/utils/mock/Transport.ts +26 -0
- package/test/utils/utils.ts +311 -0
- package/tsconfig.browser.json +15 -0
- package/tsconfig.jest.json +19 -0
- package/tsconfig.json +3 -0
- package/tsconfig.node.json +18 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DataEntry, DeleteDataRequest, DeleteDataResponse, MigrateDataRequest, MigrateDataResponse, PeerDescriptor,
|
|
3
|
+
StoreDataRequest, StoreDataResponse
|
|
4
|
+
} from '../../proto/packages/dht/protos/DhtRpc'
|
|
5
|
+
import { PeerID } from '../../helpers/PeerID'
|
|
6
|
+
import { Any } from '../../proto/google/protobuf/any'
|
|
7
|
+
import { ServerCallContext } from '@protobuf-ts/runtime-rpc'
|
|
8
|
+
import { DhtCallContext } from '../../rpc-protocol/DhtCallContext'
|
|
9
|
+
import { toProtoRpcClient } from '@streamr/proto-rpc'
|
|
10
|
+
import { StoreServiceClient } from '../../proto/packages/dht/protos/DhtRpc.client'
|
|
11
|
+
import { RoutingRpcCommunicator } from '../../transport/RoutingRpcCommunicator'
|
|
12
|
+
import { IRecursiveFinder } from '../find/RecursiveFinder'
|
|
13
|
+
import { isSamePeerDescriptor, peerIdFromPeerDescriptor } from '../../helpers/peerIdFromPeerDescriptor'
|
|
14
|
+
import { Logger } from '@streamr/utils'
|
|
15
|
+
import { LocalDataStore } from './LocalDataStore'
|
|
16
|
+
import { IStoreService } from '../../proto/packages/dht/protos/DhtRpc.server'
|
|
17
|
+
import { RemoteStore } from './RemoteStore'
|
|
18
|
+
import { Timestamp } from '../../proto/google/protobuf/timestamp'
|
|
19
|
+
import EventEmitter from 'eventemitter3'
|
|
20
|
+
import { Events } from '../DhtNode'
|
|
21
|
+
import { SortedContactList } from '../contact/SortedContactList'
|
|
22
|
+
import { Contact } from '../contact/Contact'
|
|
23
|
+
import { DhtPeer } from '../DhtPeer'
|
|
24
|
+
|
|
25
|
+
interface DataStoreConfig {
|
|
26
|
+
rpcCommunicator: RoutingRpcCommunicator
|
|
27
|
+
recursiveFinder: IRecursiveFinder
|
|
28
|
+
ownPeerDescriptor: PeerDescriptor
|
|
29
|
+
localDataStore: LocalDataStore
|
|
30
|
+
serviceId: string
|
|
31
|
+
storeMaxTtl: number
|
|
32
|
+
storeHighestTtl: number
|
|
33
|
+
storeNumberOfCopies: number
|
|
34
|
+
dhtNodeEmitter: EventEmitter<Events>
|
|
35
|
+
getNodesClosestToIdFromBucket: (id: Uint8Array, n?: number) => DhtPeer[]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const logger = new Logger(module)
|
|
39
|
+
|
|
40
|
+
export class DataStore implements IStoreService {
|
|
41
|
+
|
|
42
|
+
private readonly rpcCommunicator: RoutingRpcCommunicator
|
|
43
|
+
private readonly recursiveFinder: IRecursiveFinder
|
|
44
|
+
private readonly ownPeerDescriptor: PeerDescriptor
|
|
45
|
+
private readonly localDataStore: LocalDataStore
|
|
46
|
+
private readonly serviceId: string
|
|
47
|
+
private readonly storeMaxTtl: number
|
|
48
|
+
private readonly storeHighestTtl: number
|
|
49
|
+
private readonly storeNumberOfCopies: number
|
|
50
|
+
private readonly dhtNodeEmitter: EventEmitter<Events>
|
|
51
|
+
private readonly getNodesClosestToIdFromBucket: (id: Uint8Array, n?: number) => DhtPeer[]
|
|
52
|
+
|
|
53
|
+
constructor(config: DataStoreConfig) {
|
|
54
|
+
this.rpcCommunicator = config.rpcCommunicator
|
|
55
|
+
this.recursiveFinder = config.recursiveFinder
|
|
56
|
+
this.ownPeerDescriptor = config.ownPeerDescriptor
|
|
57
|
+
this.localDataStore = config.localDataStore
|
|
58
|
+
this.serviceId = config.serviceId
|
|
59
|
+
this.storeMaxTtl = config.storeMaxTtl
|
|
60
|
+
this.storeHighestTtl = config.storeHighestTtl
|
|
61
|
+
this.storeNumberOfCopies = config.storeNumberOfCopies
|
|
62
|
+
this.dhtNodeEmitter = config.dhtNodeEmitter
|
|
63
|
+
this.getNodesClosestToIdFromBucket = config.getNodesClosestToIdFromBucket
|
|
64
|
+
this.rpcCommunicator!.registerRpcMethod(StoreDataRequest, StoreDataResponse, 'storeData',
|
|
65
|
+
(request: StoreDataRequest, context: ServerCallContext) => this.storeData(request, context))
|
|
66
|
+
this.rpcCommunicator!.registerRpcMethod(MigrateDataRequest, MigrateDataResponse, 'migrateData',
|
|
67
|
+
(request: MigrateDataRequest, context: ServerCallContext) => this.migrateData(request, context))
|
|
68
|
+
this.rpcCommunicator!.registerRpcMethod(DeleteDataRequest, DeleteDataResponse, 'deleteData',
|
|
69
|
+
(request: DeleteDataRequest, context: ServerCallContext) => this.deleteData(request, context))
|
|
70
|
+
|
|
71
|
+
this.dhtNodeEmitter.on('newContact', (peerDescriptor: PeerDescriptor, _closestPeers: PeerDescriptor[]) => {
|
|
72
|
+
this.localDataStore.getStore().forEach((dataMap, _dataKey) => {
|
|
73
|
+
dataMap.forEach((dataEntry) => {
|
|
74
|
+
if (this.shouldMigrateDataToNewNode(dataEntry.dataEntry, peerDescriptor)) {
|
|
75
|
+
this.migrateDataToContact(dataEntry.dataEntry, peerDescriptor)
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private shouldMigrateDataToNewNode(dataEntry: DataEntry, newNode: PeerDescriptor): boolean {
|
|
83
|
+
|
|
84
|
+
const dataId = PeerID.fromValue(dataEntry.kademliaId)
|
|
85
|
+
const newNodeId = PeerID.fromValue(newNode.kademliaId)
|
|
86
|
+
const ownPeerId = PeerID.fromValue(this.ownPeerDescriptor.kademliaId)
|
|
87
|
+
|
|
88
|
+
const closestToData = this.getNodesClosestToIdFromBucket(dataEntry.kademliaId, 10)
|
|
89
|
+
|
|
90
|
+
const sortedList = new SortedContactList<Contact>(dataId, 20, undefined, true)
|
|
91
|
+
sortedList.addContact(new Contact(this.ownPeerDescriptor!))
|
|
92
|
+
|
|
93
|
+
closestToData.forEach((con) => {
|
|
94
|
+
if (!newNodeId.equals(PeerID.fromValue(con.getPeerDescriptor().kademliaId))) {
|
|
95
|
+
sortedList.addContact(new Contact(con.getPeerDescriptor()))
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
if (!sortedList.getAllContacts()[0].getPeerId().equals(ownPeerId!)) {
|
|
100
|
+
// If we are not the closes node to the data, do not migrate
|
|
101
|
+
return false
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const newPeerId = PeerID.fromValue(newNode.kademliaId)
|
|
105
|
+
sortedList.addContact(new Contact(newNode))
|
|
106
|
+
|
|
107
|
+
const sorted = sortedList.getAllContacts()
|
|
108
|
+
|
|
109
|
+
let index = 0
|
|
110
|
+
|
|
111
|
+
for (index = 0; index < sorted.length; index++) {
|
|
112
|
+
if (sorted[index].getPeerId().equals(newPeerId)) {
|
|
113
|
+
break
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// if new node is within the 5 closest nodes to the data
|
|
118
|
+
// do migrate data to it
|
|
119
|
+
|
|
120
|
+
if (index < 5) {
|
|
121
|
+
this.localDataStore.setStale(dataId, dataEntry.storer!, false)
|
|
122
|
+
return true
|
|
123
|
+
} else {
|
|
124
|
+
this.localDataStore.setStale(dataId, dataEntry.storer!, true)
|
|
125
|
+
return false
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private async migrateDataToContact(dataEntry: DataEntry, contact: PeerDescriptor, doNotConnect: boolean = false): Promise<void> {
|
|
130
|
+
const remoteStore = new RemoteStore(
|
|
131
|
+
this.ownPeerDescriptor,
|
|
132
|
+
contact,
|
|
133
|
+
toProtoRpcClient(new StoreServiceClient(this.rpcCommunicator.getRpcClientTransport())),
|
|
134
|
+
this.serviceId
|
|
135
|
+
)
|
|
136
|
+
try {
|
|
137
|
+
const response = await remoteStore.migrateData({ dataEntry }, doNotConnect)
|
|
138
|
+
if (response.error) {
|
|
139
|
+
logger.debug('RemoteStore::migrateData() returned error: ' + response.error)
|
|
140
|
+
}
|
|
141
|
+
} catch (e) {
|
|
142
|
+
logger.debug('RemoteStore::migrateData() threw an exception ' + e)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public async storeDataToDht(key: Uint8Array, data: Any): Promise<PeerDescriptor[]> {
|
|
147
|
+
logger.debug(`Storing data to DHT ${this.serviceId}`)
|
|
148
|
+
const result = await this.recursiveFinder!.startRecursiveFind(key)
|
|
149
|
+
const closestNodes = result.closestNodes
|
|
150
|
+
const successfulNodes: PeerDescriptor[] = []
|
|
151
|
+
const ttl = this.storeHighestTtl // ToDo: make TTL decrease according to some nice curve
|
|
152
|
+
const storerTime = Timestamp.now()
|
|
153
|
+
for (let i = 0; i < closestNodes.length && successfulNodes.length < 5; i++) {
|
|
154
|
+
if (isSamePeerDescriptor(this.ownPeerDescriptor, closestNodes[i])) {
|
|
155
|
+
this.localDataStore.storeEntry({
|
|
156
|
+
kademliaId: key,
|
|
157
|
+
storer: this.ownPeerDescriptor,
|
|
158
|
+
ttl,
|
|
159
|
+
storedAt: Timestamp.now(),
|
|
160
|
+
data,
|
|
161
|
+
stale: false,
|
|
162
|
+
deleted: false,
|
|
163
|
+
storerTime
|
|
164
|
+
})
|
|
165
|
+
successfulNodes.push(closestNodes[i])
|
|
166
|
+
continue
|
|
167
|
+
}
|
|
168
|
+
const remoteStore = new RemoteStore(
|
|
169
|
+
this.ownPeerDescriptor,
|
|
170
|
+
closestNodes[i],
|
|
171
|
+
toProtoRpcClient(new StoreServiceClient(this.rpcCommunicator.getRpcClientTransport())),
|
|
172
|
+
this.serviceId
|
|
173
|
+
)
|
|
174
|
+
try {
|
|
175
|
+
const response = await remoteStore.storeData({ kademliaId: key, data, ttl, storerTime })
|
|
176
|
+
if (!response.error) {
|
|
177
|
+
successfulNodes.push(closestNodes[i])
|
|
178
|
+
logger.trace('remoteStore.storeData() returned success')
|
|
179
|
+
} else {
|
|
180
|
+
logger.debug('remoteStore.storeData() returned error: ' + response.error)
|
|
181
|
+
}
|
|
182
|
+
} catch (e) {
|
|
183
|
+
logger.debug('remoteStore.storeData() threw an exception ' + e)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return successfulNodes
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private selfIsOneOfClosestPeers(dataId: Uint8Array): boolean {
|
|
190
|
+
const ownPeerId = PeerID.fromValue(this.ownPeerDescriptor.kademliaId)
|
|
191
|
+
const closestPeers = this.getNodesClosestToIdFromBucket(dataId, 5)
|
|
192
|
+
const sortedList = new SortedContactList<Contact>(ownPeerId, 5, undefined, true)
|
|
193
|
+
sortedList.addContact(new Contact(this.ownPeerDescriptor))
|
|
194
|
+
closestPeers.forEach((con) => sortedList.addContact(new Contact(con.getPeerDescriptor())))
|
|
195
|
+
return sortedList.getClosestContacts().some((node) => node.getPeerId().equals(ownPeerId))
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public async deleteDataFromDht(key: Uint8Array): Promise<void> {
|
|
199
|
+
logger.debug(`Deleting data from DHT ${this.serviceId}`)
|
|
200
|
+
const result = await this.recursiveFinder!.startRecursiveFind(key)
|
|
201
|
+
const closestNodes = result.closestNodes
|
|
202
|
+
const successfulNodes: PeerDescriptor[] = []
|
|
203
|
+
for (let i = 0; i < closestNodes.length && successfulNodes.length < 5; i++) {
|
|
204
|
+
if (isSamePeerDescriptor(this.ownPeerDescriptor, closestNodes[i])) {
|
|
205
|
+
this.localDataStore.markAsDeleted(key, peerIdFromPeerDescriptor(this.ownPeerDescriptor))
|
|
206
|
+
successfulNodes.push(closestNodes[i])
|
|
207
|
+
continue
|
|
208
|
+
}
|
|
209
|
+
const remoteStore = new RemoteStore(
|
|
210
|
+
this.ownPeerDescriptor,
|
|
211
|
+
closestNodes[i],
|
|
212
|
+
toProtoRpcClient(new StoreServiceClient(this.rpcCommunicator.getRpcClientTransport())),
|
|
213
|
+
this.serviceId
|
|
214
|
+
)
|
|
215
|
+
try {
|
|
216
|
+
const response = await remoteStore.deleteData({ kademliaId: key })
|
|
217
|
+
if (response.deleted) {
|
|
218
|
+
logger.trace('remoteStore.deleteData() returned success')
|
|
219
|
+
} else {
|
|
220
|
+
logger.debug('could not delete data from ' + PeerID.fromValue(closestNodes[i].kademliaId))
|
|
221
|
+
}
|
|
222
|
+
successfulNodes.push(closestNodes[i])
|
|
223
|
+
} catch (e) {
|
|
224
|
+
logger.debug('remoteStore.deleteData() threw an exception ' + e)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// RPC service implementation
|
|
230
|
+
async storeData(request: StoreDataRequest, context: ServerCallContext): Promise<StoreDataResponse> {
|
|
231
|
+
const ttl = Math.min(request.ttl, this.storeMaxTtl)
|
|
232
|
+
const { incomingSourceDescriptor } = context as DhtCallContext
|
|
233
|
+
const { kademliaId, data, storerTime } = request
|
|
234
|
+
this.localDataStore.storeEntry({
|
|
235
|
+
kademliaId: kademliaId,
|
|
236
|
+
storer: incomingSourceDescriptor!,
|
|
237
|
+
ttl,
|
|
238
|
+
storedAt: Timestamp.now(),
|
|
239
|
+
storerTime,
|
|
240
|
+
data,
|
|
241
|
+
stale: !this.selfIsOneOfClosestPeers(kademliaId),
|
|
242
|
+
deleted: false
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
if (!this.selfIsOneOfClosestPeers(kademliaId)) {
|
|
246
|
+
this.localDataStore.setAllEntriesAsStale(PeerID.fromValue(kademliaId))
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
logger.trace(this.ownPeerDescriptor.nodeName + ' storeData()')
|
|
250
|
+
return StoreDataResponse.create()
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// RPC service implementation
|
|
254
|
+
async deleteData(request: DeleteDataRequest, context: ServerCallContext): Promise<DeleteDataResponse> {
|
|
255
|
+
const { incomingSourceDescriptor } = context as DhtCallContext
|
|
256
|
+
const { kademliaId } = request
|
|
257
|
+
const deleted = this.localDataStore.markAsDeleted(kademliaId, peerIdFromPeerDescriptor(incomingSourceDescriptor!))
|
|
258
|
+
return DeleteDataResponse.create({ deleted })
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// RPC service implementation
|
|
262
|
+
public async migrateData(request: MigrateDataRequest, context: ServerCallContext): Promise<MigrateDataResponse> {
|
|
263
|
+
logger.trace(this.ownPeerDescriptor.nodeName + ' server-side migrateData()')
|
|
264
|
+
const dataEntry = request.dataEntry!
|
|
265
|
+
|
|
266
|
+
const wasStored = this.localDataStore.storeEntry(dataEntry)
|
|
267
|
+
|
|
268
|
+
if (wasStored) {
|
|
269
|
+
this.migrateDataToNeighborsIfNeeded((context as DhtCallContext).incomingSourceDescriptor!, request.dataEntry!)
|
|
270
|
+
}
|
|
271
|
+
if (!this.selfIsOneOfClosestPeers(dataEntry.kademliaId)) {
|
|
272
|
+
this.localDataStore.setAllEntriesAsStale(PeerID.fromValue(dataEntry.kademliaId))
|
|
273
|
+
}
|
|
274
|
+
logger.trace(this.ownPeerDescriptor.nodeName + ' server-side migrateData() at end')
|
|
275
|
+
return MigrateDataResponse.create()
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private migrateDataToNeighborsIfNeeded(incomingPeer: PeerDescriptor, dataEntry: DataEntry): void {
|
|
279
|
+
|
|
280
|
+
// sort own contact list according to data id
|
|
281
|
+
const ownPeerId = PeerID.fromValue(this.ownPeerDescriptor!.kademliaId)
|
|
282
|
+
const dataId = PeerID.fromValue(dataEntry.kademliaId)
|
|
283
|
+
const incomingPeerId = PeerID.fromValue(incomingPeer.kademliaId)
|
|
284
|
+
const closestToData = this.getNodesClosestToIdFromBucket(dataEntry.kademliaId, 10)
|
|
285
|
+
|
|
286
|
+
const sortedList = new SortedContactList<Contact>(dataId, 5, undefined, true)
|
|
287
|
+
sortedList.addContact(new Contact(this.ownPeerDescriptor!))
|
|
288
|
+
|
|
289
|
+
closestToData.forEach((con) => {
|
|
290
|
+
sortedList.addContact(new Contact(con.getPeerDescriptor()))
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
if (!sortedList.getAllContacts()[0].getPeerId().equals(ownPeerId)) {
|
|
294
|
+
// If we are not the closest node to the data, migrate only to the
|
|
295
|
+
// closest one to the data
|
|
296
|
+
|
|
297
|
+
const contact = sortedList.getAllContacts()[0]
|
|
298
|
+
const contactPeerId = PeerID.fromValue(contact.getPeerDescriptor().kademliaId)
|
|
299
|
+
if (!incomingPeerId.equals(contactPeerId) && !ownPeerId.equals(contactPeerId)) {
|
|
300
|
+
this.migrateDataToContact(dataEntry, contact.getPeerDescriptor()).then(() => {
|
|
301
|
+
logger.trace('migrateDataToContact() returned when migrating to only the closest contact')
|
|
302
|
+
}).catch((e) => {
|
|
303
|
+
logger.error('migrating data to only the closest contact failed ' + e)
|
|
304
|
+
})
|
|
305
|
+
}
|
|
306
|
+
} else {
|
|
307
|
+
// if we are the closest to the data, migrate to all 5 nearest
|
|
308
|
+
|
|
309
|
+
sortedList.getAllContacts().forEach((contact) => {
|
|
310
|
+
const contactPeerId = PeerID.fromValue(contact.getPeerDescriptor().kademliaId)
|
|
311
|
+
if (!incomingPeerId.equals(contactPeerId) && !ownPeerId.equals(contactPeerId)) {
|
|
312
|
+
this.migrateDataToContact(dataEntry, contact.getPeerDescriptor()).then(() => {
|
|
313
|
+
logger.trace('migrateDataToContact() returned')
|
|
314
|
+
}).catch((e) => {
|
|
315
|
+
logger.error('migrating data to one of the closest contacts failed ' + e)
|
|
316
|
+
})
|
|
317
|
+
}
|
|
318
|
+
})
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { PeerID, PeerIDKey } from '../../helpers/PeerID'
|
|
2
|
+
import { DataEntry, PeerDescriptor } from '../../proto/packages/dht/protos/DhtRpc'
|
|
3
|
+
import { keyFromPeerDescriptor } from '../../helpers/peerIdFromPeerDescriptor'
|
|
4
|
+
|
|
5
|
+
const MIN_TTL = 1 * 1000
|
|
6
|
+
const MAX_TTL = 300 * 1000
|
|
7
|
+
|
|
8
|
+
const createTtlValue = (ttl: number): number => {
|
|
9
|
+
if (ttl < MIN_TTL) {
|
|
10
|
+
return MIN_TTL
|
|
11
|
+
} else if (ttl > MAX_TTL) {
|
|
12
|
+
return MAX_TTL
|
|
13
|
+
} else {
|
|
14
|
+
return ttl
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface LocalDataEntry {
|
|
19
|
+
dataEntry: DataEntry
|
|
20
|
+
ttlTimeout: NodeJS.Timeout
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class LocalDataStore {
|
|
24
|
+
// A map into which each node can store one value per data key
|
|
25
|
+
// The first key is the key of the data, the second key is the
|
|
26
|
+
// PeerID of the storer of the data
|
|
27
|
+
private store: Map<PeerIDKey, Map<PeerIDKey, LocalDataEntry>> = new Map()
|
|
28
|
+
|
|
29
|
+
public storeEntry(dataEntry: DataEntry): boolean {
|
|
30
|
+
const publisherKey = PeerID.fromValue(dataEntry.storer!.kademliaId!).toKey()
|
|
31
|
+
const dataKey = PeerID.fromValue(dataEntry.kademliaId).toKey()
|
|
32
|
+
|
|
33
|
+
if (!this.store.has(dataKey)) {
|
|
34
|
+
this.store.set(dataKey, new Map())
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (this.store.get(dataKey)!.has(publisherKey)) {
|
|
38
|
+
const storedMillis = (dataEntry.storerTime!.seconds * 1000) + (dataEntry.storerTime!.nanos / 1000000)
|
|
39
|
+
const oldLocalEntry = this.store.get(dataKey)!.get(publisherKey)!
|
|
40
|
+
const oldStoredMillis = (oldLocalEntry.dataEntry.storerTime!.seconds * 1000) + (oldLocalEntry.dataEntry.storerTime!.nanos / 1000000)
|
|
41
|
+
|
|
42
|
+
// do nothing if old entry is newer than the one being migrated
|
|
43
|
+
if (oldStoredMillis >= storedMillis) {
|
|
44
|
+
return false
|
|
45
|
+
} else {
|
|
46
|
+
clearTimeout(oldLocalEntry.ttlTimeout)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
this.store.get(dataKey)!.set(publisherKey, {
|
|
50
|
+
dataEntry,
|
|
51
|
+
ttlTimeout: setTimeout(() => {
|
|
52
|
+
this.deleteEntry(PeerID.fromValue(dataEntry.kademliaId), dataEntry.storer!)
|
|
53
|
+
}, createTtlValue(dataEntry.ttl))
|
|
54
|
+
})
|
|
55
|
+
return true
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public markAsDeleted(id: Uint8Array, storer: PeerID): boolean {
|
|
59
|
+
const dataKey = PeerID.fromValue(id).toKey()
|
|
60
|
+
if (!this.store.get(dataKey)?.has(storer.toKey())) {
|
|
61
|
+
return false
|
|
62
|
+
}
|
|
63
|
+
const storedEntry = this.store.get(dataKey)!.get(storer.toKey())
|
|
64
|
+
storedEntry!.dataEntry.deleted = true
|
|
65
|
+
return true
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public getStore(): Map<PeerIDKey, Map<PeerIDKey, LocalDataEntry>> {
|
|
69
|
+
return this.store
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public getEntry(key: PeerID): Map<PeerIDKey, DataEntry> {
|
|
73
|
+
const dataEntries = new Map<PeerIDKey, DataEntry>
|
|
74
|
+
this.store.get(key.toKey())?.forEach((value, key) => {
|
|
75
|
+
dataEntries.set(key, value.dataEntry)
|
|
76
|
+
})
|
|
77
|
+
return dataEntries
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public setStale(key: PeerID, storer: PeerDescriptor, stale: boolean): void {
|
|
81
|
+
const storerKey = keyFromPeerDescriptor(storer)
|
|
82
|
+
const storedEntry = this.store.get(key.toKey())?.get(storerKey)
|
|
83
|
+
if (storedEntry) {
|
|
84
|
+
storedEntry.dataEntry.stale = stale
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public setAllEntriesAsStale(key: PeerID): void {
|
|
89
|
+
this.store.get(key.toKey())?.forEach((value) => {
|
|
90
|
+
value.dataEntry.stale = true
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public deleteEntry(key: PeerID, storer: PeerDescriptor): void {
|
|
95
|
+
const storerKey = keyFromPeerDescriptor(storer)
|
|
96
|
+
const storedEntry = this.store.get(key.toKey())?.get(storerKey)
|
|
97
|
+
if (storedEntry) {
|
|
98
|
+
clearTimeout(storedEntry.ttlTimeout)
|
|
99
|
+
this.store.get(key.toKey())?.delete(storerKey)
|
|
100
|
+
if (this.store.get(key.toKey())?.size === 0) {
|
|
101
|
+
this.store.delete(key.toKey())
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public clear(): void {
|
|
107
|
+
this.store.forEach((value) => {
|
|
108
|
+
value.forEach((value) => {
|
|
109
|
+
clearTimeout(value.ttlTimeout)
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
this.store.clear()
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Remote } from '../contact/Remote'
|
|
2
|
+
import { IStoreServiceClient } from '../../proto/packages/dht/protos/DhtRpc.client'
|
|
3
|
+
import {
|
|
4
|
+
DeleteDataRequest,
|
|
5
|
+
DeleteDataResponse,
|
|
6
|
+
MigrateDataRequest,
|
|
7
|
+
MigrateDataResponse,
|
|
8
|
+
StoreDataRequest,
|
|
9
|
+
StoreDataResponse
|
|
10
|
+
} from '../../proto/packages/dht/protos/DhtRpc'
|
|
11
|
+
import { DhtRpcOptions } from '../../rpc-protocol/DhtRpcOptions'
|
|
12
|
+
import { keyFromPeerDescriptor } from '../../helpers/peerIdFromPeerDescriptor'
|
|
13
|
+
|
|
14
|
+
export class RemoteStore extends Remote<IStoreServiceClient> {
|
|
15
|
+
|
|
16
|
+
async storeData(request: StoreDataRequest): Promise<StoreDataResponse> {
|
|
17
|
+
const options: DhtRpcOptions = {
|
|
18
|
+
sourceDescriptor: this.ownPeerDescriptor,
|
|
19
|
+
targetDescriptor: this.peerDescriptor,
|
|
20
|
+
timeout: 10000
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
return await this.client.storeData(request, options)
|
|
24
|
+
} catch (err) {
|
|
25
|
+
throw Error(
|
|
26
|
+
`Could not store data to ${keyFromPeerDescriptor(this.peerDescriptor)} from ${keyFromPeerDescriptor(this.ownPeerDescriptor)} ${err}`
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async deleteData(request: DeleteDataRequest): Promise<DeleteDataResponse> {
|
|
32
|
+
const options: DhtRpcOptions = {
|
|
33
|
+
sourceDescriptor: this.ownPeerDescriptor,
|
|
34
|
+
targetDescriptor: this.peerDescriptor,
|
|
35
|
+
timeout: 10000
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
return await this.client.deleteData(request, options)
|
|
39
|
+
} catch (err) {
|
|
40
|
+
throw Error(
|
|
41
|
+
`Could not call delete data to ${keyFromPeerDescriptor(this.peerDescriptor)} ${err}`
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async migrateData(request: MigrateDataRequest, doNotConnect: boolean = false): Promise<MigrateDataResponse> {
|
|
47
|
+
|
|
48
|
+
const options: DhtRpcOptions = {
|
|
49
|
+
sourceDescriptor: this.ownPeerDescriptor,
|
|
50
|
+
targetDescriptor: this.peerDescriptor,
|
|
51
|
+
timeout: 10000,
|
|
52
|
+
doNotConnect: doNotConnect
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return this.client.migrateData(request, options)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
}
|
package/src/exports.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { DhtNode, DhtNodeEvents, DhtNodeOptions } from './dht/DhtNode'
|
|
2
|
+
export { ListeningRpcCommunicator } from './transport/ListeningRpcCommunicator'
|
|
3
|
+
export { Simulator, LatencyType } from './connection/Simulator/Simulator'
|
|
4
|
+
export { SimulatorTransport } from './connection/Simulator/SimulatorTransport'
|
|
5
|
+
export { getRandomRegion, getRegionDelayMatrix } from './connection/Simulator/pings'
|
|
6
|
+
export { PeerDescriptor, Message, NodeType, DataEntry } from './proto/packages/dht/protos/DhtRpc'
|
|
7
|
+
export { ITransport } from './transport/ITransport'
|
|
8
|
+
export { ConnectionManager, ConnectionLocker } from './connection/ConnectionManager'
|
|
9
|
+
export { PeerID, PeerIDKey } from './helpers/PeerID'
|
|
10
|
+
export { DhtPeer } from './dht/DhtPeer'
|
|
11
|
+
export { UUID } from './helpers/UUID'
|
|
12
|
+
export { DhtRpcOptions } from './rpc-protocol/DhtRpcOptions'
|
|
13
|
+
export { protoClasses } from './helpers/protoClasses'
|
|
14
|
+
export { SortedContactList } from './dht/contact/SortedContactList'
|
|
15
|
+
export { Contact } from './dht/contact/Contact'
|
|
16
|
+
export { RecursiveFindResult } from './dht/find/RecursiveFinder'
|
|
17
|
+
export { peerIdFromPeerDescriptor, keyFromPeerDescriptor, isSamePeerDescriptor } from './helpers/peerIdFromPeerDescriptor'
|
|
18
|
+
export { IceServer } from './connection/WebRTC/WebRtcConnector'
|
|
19
|
+
export { DhtCallContext } from './rpc-protocol/DhtCallContext'
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import ipaddr from 'ipaddr.js'
|
|
2
|
+
|
|
3
|
+
// IPv4 private address ranges as specified by RFC 1918
|
|
4
|
+
const IPv4PrivateRanges = [
|
|
5
|
+
'10.0.0.0/8',
|
|
6
|
+
'172.16.0.0/12',
|
|
7
|
+
'192.168.0.0/16',
|
|
8
|
+
].map((a) => ipaddr.parseCIDR(a))
|
|
9
|
+
|
|
10
|
+
export function isPrivateIPv4(address: string): boolean {
|
|
11
|
+
if (ipaddr.IPv4.isValid(address)) {
|
|
12
|
+
const ip = ipaddr.IPv4.parse(address)
|
|
13
|
+
for (const range of IPv4PrivateRanges) {
|
|
14
|
+
if (ip.match(range)) {
|
|
15
|
+
return true
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return false
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function getAddressFromIceCandidate(candidate: string): string | undefined {
|
|
24
|
+
const fields = candidate.split(' ').filter((field) => field.length > 0)
|
|
25
|
+
return fields.length >= 5 && ipaddr.isValid(fields[4]) ? fields[4] : undefined
|
|
26
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { BrandedString } from '@streamr/utils'
|
|
2
|
+
import { UUID } from './UUID'
|
|
3
|
+
import { IllegalArguments } from './errors'
|
|
4
|
+
import crypto from 'crypto'
|
|
5
|
+
|
|
6
|
+
export type PeerIDKey = BrandedString<'PeerIDKey'>
|
|
7
|
+
|
|
8
|
+
export class PeerID {
|
|
9
|
+
// avoid creating a new instance for every operation
|
|
10
|
+
private static readonly textEncoder = new TextEncoder()
|
|
11
|
+
private static readonly textDecoder = new TextDecoder()
|
|
12
|
+
|
|
13
|
+
private readonly data!: Uint8Array
|
|
14
|
+
private readonly key: PeerIDKey // precompute often-used form of data
|
|
15
|
+
|
|
16
|
+
protected constructor({ ip, value, stringValue }: { ip?: string, value?: Uint8Array, stringValue?: string } = {}) {
|
|
17
|
+
if (ip) {
|
|
18
|
+
this.data = new Uint8Array(20)
|
|
19
|
+
const ipNum = this.ip2Int(ip)
|
|
20
|
+
const view = new DataView(this.data.buffer)
|
|
21
|
+
view.setInt32(0, ipNum)
|
|
22
|
+
|
|
23
|
+
this.data.set((new UUID()).value, 4)
|
|
24
|
+
} else if (value) {
|
|
25
|
+
this.data = new Uint8Array(value.slice(0))
|
|
26
|
+
} else if (stringValue) {
|
|
27
|
+
const ab = PeerID.textEncoder.encode(stringValue) //toUTF8Array(stringValue)
|
|
28
|
+
this.data = ab
|
|
29
|
+
} else {
|
|
30
|
+
throw new IllegalArguments('Constructor of PeerID must be given either ip, value or stringValue')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.key = Buffer.from(this.data).toString('hex') as PeerIDKey
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static fromIp(ip: string): PeerID {
|
|
37
|
+
return new PeerID({ ip })
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static fromValue(value: Uint8Array): PeerID {
|
|
41
|
+
return new PeerID({ value })
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static fromKey(value: PeerIDKey): PeerID {
|
|
45
|
+
return new PeerID({ value: Buffer.from(value, 'hex') })
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static fromString(stringValue: string): PeerID {
|
|
49
|
+
return new PeerID({ stringValue })
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static generateRandom(): PeerID {
|
|
53
|
+
// generate 160 bit random Uint8array
|
|
54
|
+
const value = new Uint8Array(20)
|
|
55
|
+
crypto.randomFillSync(value)
|
|
56
|
+
return new PeerID({ value })
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// TODO convert to static method?
|
|
60
|
+
// eslint-disable-next-line class-methods-use-this
|
|
61
|
+
private ip2Int(ip: string): number {
|
|
62
|
+
return ip.split('.').map((octet, index, array) => {
|
|
63
|
+
return parseInt(octet) * Math.pow(256, (array.length - index - 1))
|
|
64
|
+
}).reduce((prev, curr) => {
|
|
65
|
+
return prev + curr
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
equals(other: PeerID): boolean {
|
|
70
|
+
return (Buffer.compare(this.data, other.value) === 0)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
toString(): string {
|
|
74
|
+
return PeerID.textDecoder.decode(this.data) //utf8ArrayToString(this.data)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
toKey(): PeerIDKey {
|
|
78
|
+
return this.key
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get value(): Uint8Array {
|
|
82
|
+
return this.data
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
hasSmallerHashThan(other: PeerID): boolean {
|
|
86
|
+
const myId = this.toKey()
|
|
87
|
+
const theirId = other.toKey()
|
|
88
|
+
return PeerID.offeringHash(myId + ',' + theirId) < PeerID.offeringHash(theirId + ',' + myId)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private static offeringHash(idPair: string): number {
|
|
92
|
+
const buffer = crypto.createHash('md5').update(idPair).digest()
|
|
93
|
+
return buffer.readInt32LE(0)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { v4, parse, stringify } from 'uuid'
|
|
2
|
+
|
|
3
|
+
export class UUID {
|
|
4
|
+
private buf: Uint8Array
|
|
5
|
+
|
|
6
|
+
constructor(other?: (UUID | Uint8Array | string)) {
|
|
7
|
+
if (!other) {
|
|
8
|
+
this.buf = new Uint8Array(16)
|
|
9
|
+
v4(null, this.buf)
|
|
10
|
+
} else if (other.constructor === UUID) {
|
|
11
|
+
this.buf = other.buf
|
|
12
|
+
} else if (typeof other === 'string') {
|
|
13
|
+
this.buf = new Uint8Array(parse(other))
|
|
14
|
+
} else {
|
|
15
|
+
this.buf = other as Uint8Array
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
toString(): string {
|
|
20
|
+
return stringify(this.buf)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
equals(other: UUID): boolean {
|
|
24
|
+
return (Buffer.compare(this.buf, other.value) === 0)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get value(): Uint8Array {
|
|
28
|
+
return this.buf
|
|
29
|
+
}
|
|
30
|
+
}
|