@streamr/dht 100.0.0-testnet-three.5 → 100.0.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/README.md +1 -1
- package/dist/package.json +14 -9
- package/dist/src/connection/ConnectionLockHandler.d.ts +2 -2
- package/dist/src/connection/ConnectionLockHandler.js +13 -5
- package/dist/src/connection/ConnectionLockHandler.js.map +1 -1
- package/dist/src/connection/ConnectionManager.d.ts +6 -5
- package/dist/src/connection/ConnectionManager.js +16 -8
- package/dist/src/connection/ConnectionManager.js.map +1 -1
- package/dist/src/connection/ConnectorFacade.js.map +1 -1
- package/dist/src/connection/Handshaker.d.ts +2 -0
- package/dist/src/connection/Handshaker.js +12 -14
- package/dist/src/connection/Handshaker.js.map +1 -1
- package/dist/src/connection/ManagedConnection.js +1 -0
- package/dist/src/connection/ManagedConnection.js.map +1 -1
- package/dist/src/connection/connectivityChecker.d.ts +1 -1
- package/dist/src/connection/connectivityChecker.js +5 -5
- package/dist/src/connection/connectivityChecker.js.map +1 -1
- package/dist/src/connection/connectivityRequestHandler.d.ts +2 -2
- package/dist/src/connection/connectivityRequestHandler.js +6 -7
- package/dist/src/connection/connectivityRequestHandler.js.map +1 -1
- package/dist/src/connection/webrtc/WebrtcConnector.d.ts +1 -0
- package/dist/src/connection/webrtc/WebrtcConnector.js +13 -8
- package/dist/src/connection/webrtc/WebrtcConnector.js.map +1 -1
- package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.d.ts +2 -0
- package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js +4 -6
- package/dist/src/connection/webrtc/WebrtcConnectorRpcLocal.js.map +1 -1
- package/dist/src/connection/websocket/WebsocketConnector.js +24 -21
- package/dist/src/connection/websocket/WebsocketConnector.js.map +1 -1
- package/dist/src/connection/websocket/WebsocketServer.js +25 -35
- package/dist/src/connection/websocket/WebsocketServer.js.map +1 -1
- package/dist/src/connection/websocket/{ServerWebsocket.d.ts → WebsocketServerConnection.d.ts} +4 -5
- package/dist/src/connection/websocket/{ServerWebsocket.js → WebsocketServerConnection.js} +15 -48
- package/dist/src/connection/websocket/WebsocketServerConnection.js.map +1 -0
- package/dist/src/dht/DhtNode.d.ts +15 -7
- package/dist/src/dht/DhtNode.js +63 -21
- package/dist/src/dht/DhtNode.js.map +1 -1
- package/dist/src/dht/DhtNodeRpcLocal.d.ts +5 -1
- package/dist/src/dht/DhtNodeRpcLocal.js +10 -0
- package/dist/src/dht/DhtNodeRpcLocal.js.map +1 -1
- package/dist/src/dht/DhtNodeRpcRemote.d.ts +3 -0
- package/dist/src/dht/DhtNodeRpcRemote.js +15 -0
- package/dist/src/dht/DhtNodeRpcRemote.js.map +1 -1
- package/dist/src/dht/ExternalApiRpcLocal.d.ts +2 -2
- package/dist/src/dht/ExternalApiRpcLocal.js +3 -3
- package/dist/src/dht/ExternalApiRpcLocal.js.map +1 -1
- package/dist/src/dht/ExternalApiRpcRemote.d.ts +1 -1
- package/dist/src/dht/ExternalApiRpcRemote.js +2 -2
- package/dist/src/dht/ExternalApiRpcRemote.js.map +1 -1
- package/dist/src/dht/PeerManager.d.ts +12 -0
- package/dist/src/dht/PeerManager.js +30 -5
- package/dist/src/dht/PeerManager.js.map +1 -1
- package/dist/src/dht/contact/RingContactList.d.ts +31 -0
- package/dist/src/dht/contact/RingContactList.js +133 -0
- package/dist/src/dht/contact/RingContactList.js.map +1 -0
- package/dist/src/dht/contact/ringIdentifiers.d.ts +16 -0
- package/dist/src/dht/contact/ringIdentifiers.js +54 -0
- package/dist/src/dht/contact/ringIdentifiers.js.map +1 -0
- package/dist/src/dht/discovery/PeerDiscovery.d.ts +4 -0
- package/dist/src/dht/discovery/PeerDiscovery.js +35 -0
- package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
- package/dist/src/dht/discovery/RingDiscoverySession.d.ts +29 -0
- package/dist/src/dht/discovery/RingDiscoverySession.js +123 -0
- package/dist/src/dht/discovery/RingDiscoverySession.js.map +1 -0
- package/dist/src/dht/recursive-operation/RecursiveOperationSession.js +0 -1
- package/dist/src/dht/recursive-operation/RecursiveOperationSession.js.map +1 -1
- package/dist/src/dht/routing/Router.d.ts +5 -2
- package/dist/src/dht/routing/Router.js +17 -3
- package/dist/src/dht/routing/Router.js.map +1 -1
- package/dist/src/dht/routing/RouterRpcLocal.d.ts +2 -3
- package/dist/src/dht/routing/RouterRpcLocal.js +2 -2
- package/dist/src/dht/routing/RouterRpcLocal.js.map +1 -1
- package/dist/src/dht/routing/RoutingSession.d.ts +8 -6
- package/dist/src/dht/routing/RoutingSession.js +42 -40
- package/dist/src/dht/routing/RoutingSession.js.map +1 -1
- package/dist/src/dht/routing/RoutingTablesCache.d.ts +24 -0
- package/dist/src/dht/routing/RoutingTablesCache.js +46 -0
- package/dist/src/dht/routing/RoutingTablesCache.js.map +1 -0
- package/dist/src/dht/store/StoreManager.js +1 -1
- package/dist/src/dht/store/StoreManager.js.map +1 -1
- package/dist/src/exports.d.ts +1 -0
- package/dist/src/exports.js.map +1 -1
- package/dist/src/helpers/createPeerDescriptor.d.ts +1 -1
- package/dist/src/helpers/createPeerDescriptor.js +2 -1
- package/dist/src/helpers/createPeerDescriptor.js.map +1 -1
- package/dist/src/helpers/version.d.ts +6 -0
- package/dist/src/helpers/version.js +38 -0
- package/dist/src/helpers/version.js.map +1 -0
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.d.ts +16 -6
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.js +11 -4
- package/dist/src/proto/packages/dht/protos/DhtRpc.client.js.map +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +98 -87
- package/dist/src/proto/packages/dht/protos/DhtRpc.js +45 -49
- package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -1
- package/dist/src/proto/packages/dht/protos/DhtRpc.server.d.ts +10 -4
- package/dist/src/transport/RoutingRpcCommunicator.js +0 -2
- package/dist/src/transport/RoutingRpcCommunicator.js.map +1 -1
- package/package.json +14 -9
- package/protos/DhtRpc.proto +21 -21
- package/src/connection/ConnectionLockHandler.ts +13 -5
- package/src/connection/ConnectionManager.ts +20 -12
- package/src/connection/ConnectorFacade.ts +0 -1
- package/src/connection/Handshaker.ts +14 -17
- package/src/connection/ManagedConnection.ts +1 -0
- package/src/connection/connectivityChecker.ts +6 -7
- package/src/connection/connectivityRequestHandler.ts +12 -12
- package/src/connection/webrtc/NodeWebrtcConnection.ts +1 -1
- package/src/connection/webrtc/WebrtcConnector.ts +14 -8
- package/src/connection/webrtc/WebrtcConnectorRpcLocal.ts +5 -5
- package/src/connection/websocket/WebsocketConnector.ts +25 -26
- package/src/connection/websocket/WebsocketServer.ts +27 -42
- package/src/connection/websocket/{ServerWebsocket.ts → WebsocketServerConnection.ts} +14 -55
- package/src/dht/DhtNode.ts +85 -40
- package/src/dht/DhtNodeRpcLocal.ts +16 -0
- package/src/dht/DhtNodeRpcRemote.ts +18 -0
- package/src/dht/ExternalApiRpcLocal.ts +5 -5
- package/src/dht/ExternalApiRpcRemote.ts +4 -4
- package/src/dht/PeerManager.ts +48 -12
- package/src/dht/contact/RingContactList.ts +151 -0
- package/src/dht/contact/ringIdentifiers.ts +62 -0
- package/src/dht/discovery/PeerDiscovery.ts +37 -0
- package/src/dht/discovery/RingDiscoverySession.ts +160 -0
- package/src/dht/recursive-operation/RecursiveOperationSession.ts +1 -3
- package/src/dht/routing/Router.ts +22 -6
- package/src/dht/routing/RouterRpcLocal.ts +4 -5
- package/src/dht/routing/RoutingSession.ts +50 -44
- package/src/dht/routing/RoutingTablesCache.ts +58 -0
- package/src/dht/store/StoreManager.ts +1 -1
- package/src/exports.ts +1 -0
- package/src/helpers/createPeerDescriptor.ts +2 -1
- package/src/helpers/version.ts +32 -0
- package/src/proto/packages/dht/protos/DhtRpc.client.ts +22 -9
- package/src/proto/packages/dht/protos/DhtRpc.server.ts +10 -4
- package/src/proto/packages/dht/protos/DhtRpc.ts +122 -100
- package/src/transport/RoutingRpcCommunicator.ts +1 -2
- package/test/benchmark/Find.test.ts +3 -4
- package/test/benchmark/KademliaCorrectness.test.ts +14 -8
- package/test/benchmark/RingCorrectness.test.ts +157 -0
- package/test/benchmark/hybrid-network-simulation/RingContactList.test.ts +72 -0
- package/test/data/generateGroundTruthData.ts +2 -2
- package/test/end-to-end/memory-leak.test.ts +1 -2
- package/test/integration/ConnectionManager.test.ts +28 -10
- package/test/integration/ConnectivityChecking.test.ts +3 -15
- package/test/integration/DhtNodeExternalAPI.test.ts +6 -6
- package/test/integration/Find.test.ts +4 -4
- package/test/integration/Layer1-scale.test.ts +0 -1
- package/test/integration/ReplicateData.test.ts +1 -1
- package/test/integration/RouteMessage.test.ts +1 -6
- package/test/integration/RouterRpcRemote.test.ts +1 -3
- package/test/integration/SimultaneousConnections.test.ts +9 -10
- package/test/integration/Store.test.ts +2 -2
- package/test/integration/StoreAndDelete.test.ts +3 -3
- package/test/integration/StoreOnDhtWithThreeNodes.test.ts +5 -5
- package/test/integration/StoreOnDhtWithTwoNodes.test.ts +3 -3
- package/test/integration/WebrtcConnectionManagement.test.ts +3 -9
- package/test/integration/WebsocketConnectionManagement.test.ts +1 -6
- package/test/integration/rpc-connections-over-webrpc.test.ts +1 -2
- package/test/unit/PeerManager.test.ts +5 -2
- package/test/unit/RecursiveOperationManager.test.ts +14 -8
- package/test/unit/RecursiveOperationSession.test.ts +1 -1
- package/test/unit/Router.test.ts +2 -3
- package/test/unit/RoutingSession.test.ts +8 -3
- package/test/unit/connectivityRequestHandler.test.ts +5 -9
- package/test/unit/createPeerDescriptor.test.ts +12 -6
- package/test/unit/version.test.ts +18 -0
- package/test/utils/mock/Router.ts +9 -0
- package/test/utils/utils.ts +43 -10
- package/tsconfig.jest.json +2 -1
- package/tsconfig.node.json +2 -1
- package/dist/src/connection/websocket/ServerWebsocket.js.map +0 -1
- package/dist/src/helpers/versionCompatibility.d.ts +0 -2
- package/dist/src/helpers/versionCompatibility.js +0 -18
- package/dist/src/helpers/versionCompatibility.js.map +0 -1
- package/src/helpers/versionCompatibility.ts +0 -13
- package/test/unit/versionCompatibility.test.ts +0 -16
|
@@ -13,29 +13,30 @@ import { EXISTING_CONNECTION_TIMEOUT } from '../contact/RpcRemote'
|
|
|
13
13
|
import { getPreviousPeer } from './getPreviousPeer'
|
|
14
14
|
import { DhtAddress, areEqualPeerDescriptors, getDhtAddressFromRaw, getNodeIdFromPeerDescriptor } from '../../identifiers'
|
|
15
15
|
import { pull } from 'lodash'
|
|
16
|
+
import { RoutingTable, RoutingTablesCache } from './RoutingTablesCache'
|
|
16
17
|
|
|
17
18
|
const logger = new Logger(module)
|
|
18
19
|
|
|
19
20
|
const MAX_FAILED_HOPS = 2
|
|
20
|
-
const
|
|
21
|
+
const ROUTING_TABLE_MAX_SIZE = 20
|
|
21
22
|
|
|
22
|
-
class
|
|
23
|
+
export class RoutingRemoteContact extends Contact {
|
|
23
24
|
|
|
24
25
|
private routerRpcRemote: RouterRpcRemote
|
|
25
26
|
private recursiveOperationRpcRemote: RecursiveOperationRpcRemote
|
|
26
27
|
|
|
27
|
-
constructor(peer:
|
|
28
|
-
super(peer
|
|
28
|
+
constructor(peer: PeerDescriptor, localPeerDescriptor: PeerDescriptor, rpcCommunicator: RoutingRpcCommunicator) {
|
|
29
|
+
super(peer)
|
|
29
30
|
this.routerRpcRemote = new RouterRpcRemote(
|
|
30
31
|
localPeerDescriptor,
|
|
31
|
-
peer
|
|
32
|
+
peer,
|
|
32
33
|
rpcCommunicator,
|
|
33
34
|
RouterRpcClient,
|
|
34
35
|
EXISTING_CONNECTION_TIMEOUT
|
|
35
36
|
)
|
|
36
37
|
this.recursiveOperationRpcRemote = new RecursiveOperationRpcRemote(
|
|
37
38
|
localPeerDescriptor,
|
|
38
|
-
peer
|
|
39
|
+
peer,
|
|
39
40
|
rpcCommunicator,
|
|
40
41
|
RecursiveOperationRpcClient,
|
|
41
42
|
EXISTING_CONNECTION_TIMEOUT
|
|
@@ -71,14 +72,15 @@ interface RoutingSessionConfig {
|
|
|
71
72
|
connections: Map<DhtAddress, DhtNodeRpcRemote>
|
|
72
73
|
parallelism: number
|
|
73
74
|
mode: RoutingMode
|
|
74
|
-
excludedNodeIds
|
|
75
|
+
excludedNodeIds: Set<DhtAddress>
|
|
76
|
+
routingTablesCache: RoutingTablesCache
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
export class RoutingSession extends EventEmitter<RoutingSessionEvents> {
|
|
78
80
|
|
|
79
81
|
public readonly sessionId = v4()
|
|
80
82
|
private ongoingRequests: Set<DhtAddress> = new Set()
|
|
81
|
-
private
|
|
83
|
+
private contactedPeers: Set<DhtAddress> = new Set()
|
|
82
84
|
private failedHopCounter = 0
|
|
83
85
|
private successfulHopCounter = 0
|
|
84
86
|
private stopped = false
|
|
@@ -87,16 +89,6 @@ export class RoutingSession extends EventEmitter<RoutingSessionEvents> {
|
|
|
87
89
|
constructor(config: RoutingSessionConfig) {
|
|
88
90
|
super()
|
|
89
91
|
this.config = config
|
|
90
|
-
const previousPeer = getPreviousPeer(config.routedMessage)
|
|
91
|
-
const previousId = previousPeer ? getNodeIdFromPeerDescriptor(previousPeer) : undefined
|
|
92
|
-
this.contactList = new SortedContactList({
|
|
93
|
-
referenceId: getDhtAddressFromRaw(config.routedMessage.target),
|
|
94
|
-
maxSize: CONTACT_LIST_MAX_SIZE,
|
|
95
|
-
allowToContainReferenceId: true,
|
|
96
|
-
nodeIdDistanceLimit: previousId,
|
|
97
|
-
excludedNodeIds: config.excludedNodeIds,
|
|
98
|
-
emitEvents: false
|
|
99
|
-
})
|
|
100
92
|
}
|
|
101
93
|
|
|
102
94
|
private onRequestFailed(nodeId: DhtAddress) {
|
|
@@ -108,14 +100,17 @@ export class RoutingSession extends EventEmitter<RoutingSessionEvents> {
|
|
|
108
100
|
this.ongoingRequests.delete(nodeId)
|
|
109
101
|
}
|
|
110
102
|
this.deleteParallelRootIfSource(nodeId)
|
|
103
|
+
this.failedHopCounter += 1
|
|
104
|
+
if (this.failedHopCounter >= MAX_FAILED_HOPS) {
|
|
105
|
+
logger.trace(`Stopping routing after ${MAX_FAILED_HOPS} failed attempts for sessionId: ${this.sessionId}`)
|
|
106
|
+
this.emitFailure()
|
|
107
|
+
return
|
|
108
|
+
}
|
|
111
109
|
const contacts = this.updateAndGetRoutablePeers()
|
|
112
110
|
if (contacts.length === 0 && this.ongoingRequests.size === 0) {
|
|
113
111
|
logger.trace('routing failed, emitting routingFailed sessionId: ' + this.sessionId)
|
|
114
|
-
// TODO should call this.stop() so that we do cleanup? (after the emitFailure call)
|
|
115
|
-
this.stopped = true
|
|
116
112
|
this.emitFailure()
|
|
117
113
|
} else {
|
|
118
|
-
this.failedHopCounter += 1
|
|
119
114
|
logger.trace('routing failed, retrying to route sessionId: ' + this.sessionId + ' failedHopCounter: ' + this.failedHopCounter)
|
|
120
115
|
this.sendMoreRequests(contacts)
|
|
121
116
|
}
|
|
@@ -135,17 +130,19 @@ export class RoutingSession extends EventEmitter<RoutingSessionEvents> {
|
|
|
135
130
|
return
|
|
136
131
|
}
|
|
137
132
|
this.successfulHopCounter += 1
|
|
133
|
+
if (this.successfulHopCounter >= this.config.parallelism) {
|
|
134
|
+
this.emit('routingSucceeded')
|
|
135
|
+
return
|
|
136
|
+
}
|
|
138
137
|
const contacts = this.updateAndGetRoutablePeers()
|
|
139
|
-
if (
|
|
140
|
-
// TODO should call this.stop() so that we do cleanup? (after the routingSucceeded call)
|
|
141
|
-
this.stopped = true
|
|
138
|
+
if (contacts.length === 0) {
|
|
142
139
|
this.emit('routingSucceeded')
|
|
143
140
|
} else if (contacts.length > 0 && this.ongoingRequests.size === 0) {
|
|
144
141
|
this.sendMoreRequests(contacts)
|
|
145
142
|
}
|
|
146
143
|
}
|
|
147
144
|
|
|
148
|
-
private async sendRouteMessageRequest(contact:
|
|
145
|
+
private async sendRouteMessageRequest(contact: RoutingRemoteContact): Promise<boolean> {
|
|
149
146
|
if (this.stopped) {
|
|
150
147
|
return false
|
|
151
148
|
}
|
|
@@ -162,21 +159,36 @@ export class RoutingSession extends EventEmitter<RoutingSessionEvents> {
|
|
|
162
159
|
}
|
|
163
160
|
}
|
|
164
161
|
|
|
165
|
-
updateAndGetRoutablePeers():
|
|
162
|
+
updateAndGetRoutablePeers(): RoutingRemoteContact[] {
|
|
166
163
|
logger.trace('getRoutablePeers() sessionId: ' + this.sessionId)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
164
|
+
const previousPeer = getPreviousPeer(this.config.routedMessage)
|
|
165
|
+
const previousId = previousPeer ? getNodeIdFromPeerDescriptor(previousPeer) : undefined
|
|
166
|
+
const targetId = getDhtAddressFromRaw(this.config.routedMessage.target)
|
|
167
|
+
let routingTable: RoutingTable
|
|
168
|
+
if (this.config.routingTablesCache.has(targetId, previousId)) {
|
|
169
|
+
routingTable = this.config.routingTablesCache.get(targetId, previousId)!
|
|
170
|
+
} else {
|
|
171
|
+
routingTable = new SortedContactList<RoutingRemoteContact>({
|
|
172
|
+
referenceId: getDhtAddressFromRaw(this.config.routedMessage.target),
|
|
173
|
+
maxSize: ROUTING_TABLE_MAX_SIZE,
|
|
174
|
+
allowToContainReferenceId: true,
|
|
175
|
+
nodeIdDistanceLimit: previousId,
|
|
176
|
+
emitEvents: false
|
|
177
|
+
})
|
|
178
|
+
const contacts = Array.from(this.config.connections.values())
|
|
179
|
+
.map((peer) => new RoutingRemoteContact(
|
|
180
|
+
peer.getPeerDescriptor(),
|
|
181
|
+
this.config.localPeerDescriptor,
|
|
182
|
+
this.config.rpcCommunicator
|
|
183
|
+
))
|
|
184
|
+
routingTable.addContacts(contacts)
|
|
185
|
+
this.config.routingTablesCache.set(targetId, routingTable, previousId)
|
|
186
|
+
}
|
|
187
|
+
return routingTable.getAllContacts()
|
|
188
|
+
.filter((contact) => !this.contactedPeers.has(contact.getNodeId()) && !this.config.excludedNodeIds.has(contact.getNodeId()))
|
|
177
189
|
}
|
|
178
190
|
|
|
179
|
-
sendMoreRequests(uncontacted:
|
|
191
|
+
sendMoreRequests(uncontacted: RoutingRemoteContact[]): void {
|
|
180
192
|
logger.trace('sendMoreRequests() sessionId: ' + this.sessionId)
|
|
181
193
|
if (this.stopped) {
|
|
182
194
|
return
|
|
@@ -185,16 +197,11 @@ export class RoutingSession extends EventEmitter<RoutingSessionEvents> {
|
|
|
185
197
|
this.emitFailure()
|
|
186
198
|
return
|
|
187
199
|
}
|
|
188
|
-
if (this.failedHopCounter >= MAX_FAILED_HOPS) {
|
|
189
|
-
logger.trace(`Stopping routing after ${MAX_FAILED_HOPS} failed attempts for sessionId: ${this.sessionId}`)
|
|
190
|
-
this.emitFailure()
|
|
191
|
-
return
|
|
192
|
-
}
|
|
193
200
|
while ((this.ongoingRequests.size < this.config.parallelism) && (uncontacted.length > 0) && !this.stopped) {
|
|
194
201
|
const nextPeer = uncontacted.shift()
|
|
195
202
|
// eslint-disable-next-line max-len
|
|
196
203
|
logger.trace(`Sending routeMessage request to contact: ${getNodeIdFromPeerDescriptor(nextPeer!.getPeerDescriptor())} (sessionId=${this.sessionId})`)
|
|
197
|
-
this.
|
|
204
|
+
this.contactedPeers.add(nextPeer!.getNodeId())
|
|
198
205
|
this.ongoingRequests.add(nextPeer!.getNodeId())
|
|
199
206
|
this.addParallelRootIfSource(nextPeer!.getNodeId())
|
|
200
207
|
setImmediate(async () => {
|
|
@@ -234,7 +241,6 @@ export class RoutingSession extends EventEmitter<RoutingSessionEvents> {
|
|
|
234
241
|
|
|
235
242
|
public stop(): void {
|
|
236
243
|
this.stopped = true
|
|
237
|
-
this.contactList.stop()
|
|
238
244
|
this.emit('stopped')
|
|
239
245
|
this.removeAllListeners()
|
|
240
246
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { DhtAddress } from '../../identifiers'
|
|
2
|
+
import { SortedContactList } from '../contact/SortedContactList'
|
|
3
|
+
import { RoutingRemoteContact } from './RoutingSession'
|
|
4
|
+
import { LRUCache } from 'lru-cache'
|
|
5
|
+
|
|
6
|
+
type RoutingTableID = string
|
|
7
|
+
export type RoutingTable = Pick<SortedContactList<RoutingRemoteContact>, 'getAllContacts' | 'addContacts' | 'addContact' | 'removeContact' | 'stop'>
|
|
8
|
+
|
|
9
|
+
const createRoutingTableId = (targetId: DhtAddress, previousId?: DhtAddress): RoutingTableID => {
|
|
10
|
+
return targetId + (previousId ? previousId : '')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const DEFAULT_LRU_OPTIONS = {
|
|
14
|
+
max: 1000,
|
|
15
|
+
maxAge: 15 * 1000
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* RoutingTablesCache is a cache for routing tables.
|
|
20
|
+
* It is used to store the routing tables for a specific targetId and previousId.
|
|
21
|
+
* Storing the previousId is important as it is used as a minimum distance for the contacts in the table.
|
|
22
|
+
* Calculating a RoutingTable from scratch is an O(n log n) operation (n = number of connections of a node)
|
|
23
|
+
* However,
|
|
24
|
+
* - Adding a contact to a RoutingTable is an O(log n) operation.
|
|
25
|
+
* - Deleting a contact from a RoutingTable is an O(1) operation.
|
|
26
|
+
* Thus, holding the most frequently used routing tables in memory to be updated on
|
|
27
|
+
* connections and disconnections is hugely beneficial in terms of performance.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
export class RoutingTablesCache {
|
|
31
|
+
|
|
32
|
+
private readonly tables: LRUCache<RoutingTableID, RoutingTable> = new LRUCache(DEFAULT_LRU_OPTIONS)
|
|
33
|
+
|
|
34
|
+
get(targetId: DhtAddress, previousId?: DhtAddress): RoutingTable | undefined {
|
|
35
|
+
return this.tables.get(createRoutingTableId(targetId, previousId))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
set(targetId: DhtAddress, table: RoutingTable, previousId?: DhtAddress): void {
|
|
39
|
+
this.tables.set(createRoutingTableId(targetId, previousId), table)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
has(targetId: DhtAddress, previousId?: DhtAddress): boolean {
|
|
43
|
+
return this.tables.has(createRoutingTableId(targetId, previousId))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
onNodeDisconnected(nodeId: DhtAddress): void {
|
|
47
|
+
this.tables.forEach((table) => table.removeContact(nodeId))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
onNodeConnected(remote: RoutingRemoteContact): void {
|
|
51
|
+
this.tables.forEach((table) => table.addContact(remote))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
reset(): void {
|
|
55
|
+
this.tables.forEach((table) => table.stop())
|
|
56
|
+
this.tables.clear()
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -98,7 +98,7 @@ export class StoreManager {
|
|
|
98
98
|
|
|
99
99
|
public async storeDataToDht(key: DhtAddress, data: Any, creator: DhtAddress): Promise<PeerDescriptor[]> {
|
|
100
100
|
logger.debug(`Storing data to DHT ${this.config.serviceId}`)
|
|
101
|
-
const result = await this.config.recursiveOperationManager.execute(key, RecursiveOperation.
|
|
101
|
+
const result = await this.config.recursiveOperationManager.execute(key, RecursiveOperation.FIND_CLOSEST_NODES)
|
|
102
102
|
const closestNodes = result.closestNodes
|
|
103
103
|
const successfulNodes: PeerDescriptor[] = []
|
|
104
104
|
const ttl = this.config.highestTtl // ToDo: make TTL decrease according to some nice curve
|
package/src/exports.ts
CHANGED
|
@@ -17,6 +17,7 @@ export { ClientWebsocket } from './connection/websocket/ClientWebsocket'
|
|
|
17
17
|
export { ManagedConnection } from './connection/ManagedConnection'
|
|
18
18
|
export { ConnectionType } from './connection/IConnection'
|
|
19
19
|
export { ServiceID } from './types/ServiceID'
|
|
20
|
+
export { RingContacts } from './dht/contact/RingContactList'
|
|
20
21
|
export {
|
|
21
22
|
DhtAddress,
|
|
22
23
|
DhtAddressRaw,
|
|
@@ -29,7 +29,7 @@ const calculateNodeIdRaw = (ipAddress: number, privateKey: Uint8Array): DhtAddre
|
|
|
29
29
|
return nodeIdRaw
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export const createPeerDescriptor = (connectivityResponse: ConnectivityResponse, nodeId?: DhtAddress): PeerDescriptor => {
|
|
32
|
+
export const createPeerDescriptor = (connectivityResponse: ConnectivityResponse, region: number, nodeId?: DhtAddress): PeerDescriptor => {
|
|
33
33
|
const privateKey = crypto.randomBytes(32)
|
|
34
34
|
const publicKey = crypto.randomBytes(20) // TODO calculate publicKey from privateKey
|
|
35
35
|
let nodeIdRaw: DhtAddressRaw
|
|
@@ -42,6 +42,7 @@ export const createPeerDescriptor = (connectivityResponse: ConnectivityResponse,
|
|
|
42
42
|
nodeId: nodeIdRaw,
|
|
43
43
|
type: isBrowserEnvironment() ? NodeType.BROWSER : NodeType.NODEJS,
|
|
44
44
|
ipAddress: connectivityResponse.ipAddress,
|
|
45
|
+
region,
|
|
45
46
|
publicKey
|
|
46
47
|
}
|
|
47
48
|
if (connectivityResponse.websocket) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const LOCAL_PROTOCOL_VERSION = '1.0'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* When two nodes negotiate whether they are compatible or not, it is up to the
|
|
5
|
+
* newer version to decide if it supports the old version or not.
|
|
6
|
+
*
|
|
7
|
+
* The older version assumes optimistically that it may be supported by the newer
|
|
8
|
+
* version. It can't know for sure, but the other node will tell if it is not
|
|
9
|
+
* supported (e.g. rejecting the handshake with UNSUPPORTED_VERSION error).
|
|
10
|
+
*/
|
|
11
|
+
export const isMaybeSupportedVersion = (remoteVersion: string): boolean => {
|
|
12
|
+
const localMajor = parseVersion(LOCAL_PROTOCOL_VERSION)!.major
|
|
13
|
+
const remoteMajor = parseVersion(remoteVersion)?.major
|
|
14
|
+
if ((remoteMajor === undefined) || (remoteMajor < localMajor)) {
|
|
15
|
+
return false
|
|
16
|
+
} else {
|
|
17
|
+
// TODO implement proper checking when there are new protocol versions
|
|
18
|
+
return true
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const parseVersion = (version: string): { major: number, minor: number } | undefined => {
|
|
23
|
+
const parts = version.split('.')
|
|
24
|
+
if (parts.length === 2) {
|
|
25
|
+
const values = parts.map((p) => Number(p))
|
|
26
|
+
if (!values.some((v) => isNaN(v))) {
|
|
27
|
+
return { major: values[0], minor: values[1] }
|
|
28
|
+
}
|
|
29
|
+
} else {
|
|
30
|
+
return undefined
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
import { ExternalApiRpc } from "./DhtRpc";
|
|
5
5
|
import type { ExternalStoreDataResponse } from "./DhtRpc";
|
|
6
6
|
import type { ExternalStoreDataRequest } from "./DhtRpc";
|
|
7
|
-
import type {
|
|
8
|
-
import type {
|
|
7
|
+
import type { ExternalFetchDataResponse } from "./DhtRpc";
|
|
8
|
+
import type { ExternalFetchDataRequest } from "./DhtRpc";
|
|
9
9
|
import { ConnectionLockRpc } from "./DhtRpc";
|
|
10
10
|
import type { DisconnectNotice } from "./DhtRpc";
|
|
11
11
|
import type { UnlockRequest } from "./DhtRpc";
|
|
@@ -35,6 +35,8 @@ import type { Empty } from "../../../google/protobuf/empty";
|
|
|
35
35
|
import type { LeaveNotice } from "./DhtRpc";
|
|
36
36
|
import type { PingResponse } from "./DhtRpc";
|
|
37
37
|
import type { PingRequest } from "./DhtRpc";
|
|
38
|
+
import type { ClosestRingPeersResponse } from "./DhtRpc";
|
|
39
|
+
import type { ClosestRingPeersRequest } from "./DhtRpc";
|
|
38
40
|
import { stackIntercept } from "@protobuf-ts/runtime-rpc";
|
|
39
41
|
import type { ClosestPeersResponse } from "./DhtRpc";
|
|
40
42
|
import type { ClosestPeersRequest } from "./DhtRpc";
|
|
@@ -48,6 +50,10 @@ export interface IDhtNodeRpcClient {
|
|
|
48
50
|
* @generated from protobuf rpc: getClosestPeers(dht.ClosestPeersRequest) returns (dht.ClosestPeersResponse);
|
|
49
51
|
*/
|
|
50
52
|
getClosestPeers(input: ClosestPeersRequest, options?: RpcOptions): UnaryCall<ClosestPeersRequest, ClosestPeersResponse>;
|
|
53
|
+
/**
|
|
54
|
+
* @generated from protobuf rpc: getClosestRingPeers(dht.ClosestRingPeersRequest) returns (dht.ClosestRingPeersResponse);
|
|
55
|
+
*/
|
|
56
|
+
getClosestRingPeers(input: ClosestRingPeersRequest, options?: RpcOptions): UnaryCall<ClosestRingPeersRequest, ClosestRingPeersResponse>;
|
|
51
57
|
/**
|
|
52
58
|
* @generated from protobuf rpc: ping(dht.PingRequest) returns (dht.PingResponse);
|
|
53
59
|
*/
|
|
@@ -73,18 +79,25 @@ export class DhtNodeRpcClient implements IDhtNodeRpcClient, ServiceInfo {
|
|
|
73
79
|
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
|
74
80
|
return stackIntercept<ClosestPeersRequest, ClosestPeersResponse>("unary", this._transport, method, opt, input);
|
|
75
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* @generated from protobuf rpc: getClosestRingPeers(dht.ClosestRingPeersRequest) returns (dht.ClosestRingPeersResponse);
|
|
84
|
+
*/
|
|
85
|
+
getClosestRingPeers(input: ClosestRingPeersRequest, options?: RpcOptions): UnaryCall<ClosestRingPeersRequest, ClosestRingPeersResponse> {
|
|
86
|
+
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
|
87
|
+
return stackIntercept<ClosestRingPeersRequest, ClosestRingPeersResponse>("unary", this._transport, method, opt, input);
|
|
88
|
+
}
|
|
76
89
|
/**
|
|
77
90
|
* @generated from protobuf rpc: ping(dht.PingRequest) returns (dht.PingResponse);
|
|
78
91
|
*/
|
|
79
92
|
ping(input: PingRequest, options?: RpcOptions): UnaryCall<PingRequest, PingResponse> {
|
|
80
|
-
const method = this.methods[
|
|
93
|
+
const method = this.methods[2], opt = this._transport.mergeOptions(options);
|
|
81
94
|
return stackIntercept<PingRequest, PingResponse>("unary", this._transport, method, opt, input);
|
|
82
95
|
}
|
|
83
96
|
/**
|
|
84
97
|
* @generated from protobuf rpc: leaveNotice(dht.LeaveNotice) returns (google.protobuf.Empty);
|
|
85
98
|
*/
|
|
86
99
|
leaveNotice(input: LeaveNotice, options?: RpcOptions): UnaryCall<LeaveNotice, Empty> {
|
|
87
|
-
const method = this.methods[
|
|
100
|
+
const method = this.methods[3], opt = this._transport.mergeOptions(options);
|
|
88
101
|
return stackIntercept<LeaveNotice, Empty>("unary", this._transport, method, opt, input);
|
|
89
102
|
}
|
|
90
103
|
}
|
|
@@ -352,9 +365,9 @@ export class ConnectionLockRpcClient implements IConnectionLockRpcClient, Servic
|
|
|
352
365
|
*/
|
|
353
366
|
export interface IExternalApiRpcClient {
|
|
354
367
|
/**
|
|
355
|
-
* @generated from protobuf rpc:
|
|
368
|
+
* @generated from protobuf rpc: externalFetchData(dht.ExternalFetchDataRequest) returns (dht.ExternalFetchDataResponse);
|
|
356
369
|
*/
|
|
357
|
-
|
|
370
|
+
externalFetchData(input: ExternalFetchDataRequest, options?: RpcOptions): UnaryCall<ExternalFetchDataRequest, ExternalFetchDataResponse>;
|
|
358
371
|
/**
|
|
359
372
|
* @generated from protobuf rpc: externalStoreData(dht.ExternalStoreDataRequest) returns (dht.ExternalStoreDataResponse);
|
|
360
373
|
*/
|
|
@@ -370,11 +383,11 @@ export class ExternalApiRpcClient implements IExternalApiRpcClient, ServiceInfo
|
|
|
370
383
|
constructor(private readonly _transport: RpcTransport) {
|
|
371
384
|
}
|
|
372
385
|
/**
|
|
373
|
-
* @generated from protobuf rpc:
|
|
386
|
+
* @generated from protobuf rpc: externalFetchData(dht.ExternalFetchDataRequest) returns (dht.ExternalFetchDataResponse);
|
|
374
387
|
*/
|
|
375
|
-
|
|
388
|
+
externalFetchData(input: ExternalFetchDataRequest, options?: RpcOptions): UnaryCall<ExternalFetchDataRequest, ExternalFetchDataResponse> {
|
|
376
389
|
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
|
377
|
-
return stackIntercept<
|
|
390
|
+
return stackIntercept<ExternalFetchDataRequest, ExternalFetchDataResponse>("unary", this._transport, method, opt, input);
|
|
378
391
|
}
|
|
379
392
|
/**
|
|
380
393
|
* @generated from protobuf rpc: externalStoreData(dht.ExternalStoreDataRequest) returns (dht.ExternalStoreDataResponse);
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
// tslint:disable
|
|
4
4
|
import { ExternalStoreDataResponse } from "./DhtRpc";
|
|
5
5
|
import { ExternalStoreDataRequest } from "./DhtRpc";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { ExternalFetchDataResponse } from "./DhtRpc";
|
|
7
|
+
import { ExternalFetchDataRequest } from "./DhtRpc";
|
|
8
8
|
import { DisconnectNotice } from "./DhtRpc";
|
|
9
9
|
import { UnlockRequest } from "./DhtRpc";
|
|
10
10
|
import { LockResponse } from "./DhtRpc";
|
|
@@ -24,6 +24,8 @@ import { Empty } from "../../../google/protobuf/empty";
|
|
|
24
24
|
import { LeaveNotice } from "./DhtRpc";
|
|
25
25
|
import { PingResponse } from "./DhtRpc";
|
|
26
26
|
import { PingRequest } from "./DhtRpc";
|
|
27
|
+
import { ClosestRingPeersResponse } from "./DhtRpc";
|
|
28
|
+
import { ClosestRingPeersRequest } from "./DhtRpc";
|
|
27
29
|
import { ClosestPeersResponse } from "./DhtRpc";
|
|
28
30
|
import { ClosestPeersRequest } from "./DhtRpc";
|
|
29
31
|
import { ServerCallContext } from "@protobuf-ts/runtime-rpc";
|
|
@@ -35,6 +37,10 @@ export interface IDhtNodeRpc<T = ServerCallContext> {
|
|
|
35
37
|
* @generated from protobuf rpc: getClosestPeers(dht.ClosestPeersRequest) returns (dht.ClosestPeersResponse);
|
|
36
38
|
*/
|
|
37
39
|
getClosestPeers(request: ClosestPeersRequest, context: T): Promise<ClosestPeersResponse>;
|
|
40
|
+
/**
|
|
41
|
+
* @generated from protobuf rpc: getClosestRingPeers(dht.ClosestRingPeersRequest) returns (dht.ClosestRingPeersResponse);
|
|
42
|
+
*/
|
|
43
|
+
getClosestRingPeers(request: ClosestRingPeersRequest, context: T): Promise<ClosestRingPeersResponse>;
|
|
38
44
|
/**
|
|
39
45
|
* @generated from protobuf rpc: ping(dht.PingRequest) returns (dht.PingResponse);
|
|
40
46
|
*/
|
|
@@ -140,9 +146,9 @@ export interface IConnectionLockRpc<T = ServerCallContext> {
|
|
|
140
146
|
*/
|
|
141
147
|
export interface IExternalApiRpc<T = ServerCallContext> {
|
|
142
148
|
/**
|
|
143
|
-
* @generated from protobuf rpc:
|
|
149
|
+
* @generated from protobuf rpc: externalFetchData(dht.ExternalFetchDataRequest) returns (dht.ExternalFetchDataResponse);
|
|
144
150
|
*/
|
|
145
|
-
|
|
151
|
+
externalFetchData(request: ExternalFetchDataRequest, context: T): Promise<ExternalFetchDataResponse>;
|
|
146
152
|
/**
|
|
147
153
|
* @generated from protobuf rpc: externalStoreData(dht.ExternalStoreDataRequest) returns (dht.ExternalStoreDataResponse);
|
|
148
154
|
*/
|