@streamr/trackerless-network 103.1.2-rc.0 → 103.2.0-experiment.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/dist/exports.cjs +4489 -0
- package/dist/exports.cjs.map +1 -0
- package/dist/exports.d.ts +1391 -0
- package/dist/exports.js +4477 -0
- package/dist/exports.js.map +1 -0
- package/package.json +25 -18
- package/dist/generated/google/protobuf/any.d.ts +0 -180
- package/dist/generated/google/protobuf/any.js +0 -155
- package/dist/generated/google/protobuf/any.js.map +0 -1
- package/dist/generated/google/protobuf/empty.d.ts +0 -31
- package/dist/generated/google/protobuf/empty.js +0 -45
- package/dist/generated/google/protobuf/empty.js.map +0 -1
- package/dist/generated/google/protobuf/timestamp.d.ts +0 -156
- package/dist/generated/google/protobuf/timestamp.js +0 -136
- package/dist/generated/google/protobuf/timestamp.js.map +0 -1
- package/dist/generated/packages/dht/protos/DhtRpc.client.d.ts +0 -371
- package/dist/generated/packages/dht/protos/DhtRpc.client.js +0 -292
- package/dist/generated/packages/dht/protos/DhtRpc.client.js.map +0 -1
- package/dist/generated/packages/dht/protos/DhtRpc.d.ts +0 -1031
- package/dist/generated/packages/dht/protos/DhtRpc.js +0 -702
- package/dist/generated/packages/dht/protos/DhtRpc.js.map +0 -1
- package/dist/generated/packages/dht/protos/DhtRpc.server.d.ts +0 -168
- package/dist/generated/packages/dht/protos/DhtRpc.server.js +0 -3
- package/dist/generated/packages/dht/protos/DhtRpc.server.js.map +0 -1
- package/dist/generated/packages/proto-rpc/protos/ProtoRpc.d.ts +0 -87
- package/dist/generated/packages/proto-rpc/protos/ProtoRpc.js +0 -66
- package/dist/generated/packages/proto-rpc/protos/ProtoRpc.js.map +0 -1
- package/dist/generated/packages/trackerless-network/protos/NetworkRpc.client.d.ts +0 -237
- package/dist/generated/packages/trackerless-network/protos/NetworkRpc.client.js +0 -190
- package/dist/generated/packages/trackerless-network/protos/NetworkRpc.client.js.map +0 -1
- package/dist/generated/packages/trackerless-network/protos/NetworkRpc.d.ts +0 -687
- package/dist/generated/packages/trackerless-network/protos/NetworkRpc.js +0 -479
- package/dist/generated/packages/trackerless-network/protos/NetworkRpc.js.map +0 -1
- package/dist/generated/packages/trackerless-network/protos/NetworkRpc.server.d.ts +0 -102
- package/dist/generated/packages/trackerless-network/protos/NetworkRpc.server.js +0 -3
- package/dist/generated/packages/trackerless-network/protos/NetworkRpc.server.js.map +0 -1
- package/dist/package.json +0 -56
- package/dist/src/ContentDeliveryManager.d.ts +0 -82
- package/dist/src/ContentDeliveryManager.js +0 -325
- package/dist/src/ContentDeliveryManager.js.map +0 -1
- package/dist/src/NetworkNode.d.ts +0 -44
- package/dist/src/NetworkNode.js +0 -98
- package/dist/src/NetworkNode.js.map +0 -1
- package/dist/src/NetworkStack.d.ts +0 -36
- package/dist/src/NetworkStack.js +0 -165
- package/dist/src/NetworkStack.js.map +0 -1
- package/dist/src/NodeInfoClient.d.ts +0 -9
- package/dist/src/NodeInfoClient.js +0 -21
- package/dist/src/NodeInfoClient.js.map +0 -1
- package/dist/src/NodeInfoRpcLocal.d.ts +0 -12
- package/dist/src/NodeInfoRpcLocal.js +0 -22
- package/dist/src/NodeInfoRpcLocal.js.map +0 -1
- package/dist/src/NodeInfoRpcRemote.d.ts +0 -6
- package/dist/src/NodeInfoRpcRemote.js +0 -11
- package/dist/src/NodeInfoRpcRemote.js.map +0 -1
- package/dist/src/StreamPartNetworkSplitAvoidance.d.ts +0 -18
- package/dist/src/StreamPartNetworkSplitAvoidance.js +0 -74
- package/dist/src/StreamPartNetworkSplitAvoidance.js.map +0 -1
- package/dist/src/StreamPartReconnect.d.ts +0 -11
- package/dist/src/StreamPartReconnect.js +0 -37
- package/dist/src/StreamPartReconnect.js.map +0 -1
- package/dist/src/content-delivery-layer/ContentDeliveryLayerNode.d.ts +0 -78
- package/dist/src/content-delivery-layer/ContentDeliveryLayerNode.js +0 -240
- package/dist/src/content-delivery-layer/ContentDeliveryLayerNode.js.map +0 -1
- package/dist/src/content-delivery-layer/ContentDeliveryRpcLocal.d.ts +0 -23
- package/dist/src/content-delivery-layer/ContentDeliveryRpcLocal.js +0 -40
- package/dist/src/content-delivery-layer/ContentDeliveryRpcLocal.js.map +0 -1
- package/dist/src/content-delivery-layer/ContentDeliveryRpcRemote.d.ts +0 -11
- package/dist/src/content-delivery-layer/ContentDeliveryRpcRemote.js +0 -38
- package/dist/src/content-delivery-layer/ContentDeliveryRpcRemote.js.map +0 -1
- package/dist/src/content-delivery-layer/DuplicateMessageDetector.d.ts +0 -55
- package/dist/src/content-delivery-layer/DuplicateMessageDetector.js +0 -159
- package/dist/src/content-delivery-layer/DuplicateMessageDetector.js.map +0 -1
- package/dist/src/content-delivery-layer/NodeList.d.ts +0 -26
- package/dist/src/content-delivery-layer/NodeList.js +0 -93
- package/dist/src/content-delivery-layer/NodeList.js.map +0 -1
- package/dist/src/content-delivery-layer/createContentDeliveryLayerNode.d.ts +0 -14
- package/dist/src/content-delivery-layer/createContentDeliveryLayerNode.js +0 -129
- package/dist/src/content-delivery-layer/createContentDeliveryLayerNode.js.map +0 -1
- package/dist/src/content-delivery-layer/formStreamPartDeliveryServiceId.d.ts +0 -3
- package/dist/src/content-delivery-layer/formStreamPartDeliveryServiceId.js +0 -9
- package/dist/src/content-delivery-layer/formStreamPartDeliveryServiceId.js.map +0 -1
- package/dist/src/content-delivery-layer/inspection/InspectSession.d.ts +0 -19
- package/dist/src/content-delivery-layer/inspection/InspectSession.js +0 -43
- package/dist/src/content-delivery-layer/inspection/InspectSession.js.map +0 -1
- package/dist/src/content-delivery-layer/inspection/Inspector.d.ts +0 -30
- package/dist/src/content-delivery-layer/inspection/Inspector.js +0 -75
- package/dist/src/content-delivery-layer/inspection/Inspector.js.map +0 -1
- package/dist/src/content-delivery-layer/neighbor-discovery/HandshakeRpcLocal.d.ts +0 -29
- package/dist/src/content-delivery-layer/neighbor-discovery/HandshakeRpcLocal.js +0 -106
- package/dist/src/content-delivery-layer/neighbor-discovery/HandshakeRpcLocal.js.map +0 -1
- package/dist/src/content-delivery-layer/neighbor-discovery/HandshakeRpcRemote.d.ts +0 -14
- package/dist/src/content-delivery-layer/neighbor-discovery/HandshakeRpcRemote.js +0 -55
- package/dist/src/content-delivery-layer/neighbor-discovery/HandshakeRpcRemote.js.map +0 -1
- package/dist/src/content-delivery-layer/neighbor-discovery/Handshaker.d.ts +0 -32
- package/dist/src/content-delivery-layer/neighbor-discovery/Handshaker.js +0 -149
- package/dist/src/content-delivery-layer/neighbor-discovery/Handshaker.js.map +0 -1
- package/dist/src/content-delivery-layer/neighbor-discovery/NeighborFinder.d.ts +0 -22
- package/dist/src/content-delivery-layer/neighbor-discovery/NeighborFinder.js +0 -64
- package/dist/src/content-delivery-layer/neighbor-discovery/NeighborFinder.js.map +0 -1
- package/dist/src/content-delivery-layer/neighbor-discovery/NeighborUpdateManager.d.ts +0 -27
- package/dist/src/content-delivery-layer/neighbor-discovery/NeighborUpdateManager.js +0 -47
- package/dist/src/content-delivery-layer/neighbor-discovery/NeighborUpdateManager.js.map +0 -1
- package/dist/src/content-delivery-layer/neighbor-discovery/NeighborUpdateRpcLocal.d.ts +0 -25
- package/dist/src/content-delivery-layer/neighbor-discovery/NeighborUpdateRpcLocal.js +0 -52
- package/dist/src/content-delivery-layer/neighbor-discovery/NeighborUpdateRpcLocal.js.map +0 -1
- package/dist/src/content-delivery-layer/neighbor-discovery/NeighborUpdateRpcRemote.d.ts +0 -11
- package/dist/src/content-delivery-layer/neighbor-discovery/NeighborUpdateRpcRemote.js +0 -31
- package/dist/src/content-delivery-layer/neighbor-discovery/NeighborUpdateRpcRemote.js.map +0 -1
- package/dist/src/content-delivery-layer/plumtree/PausedNeighbors.d.ts +0 -12
- package/dist/src/content-delivery-layer/plumtree/PausedNeighbors.js +0 -50
- package/dist/src/content-delivery-layer/plumtree/PausedNeighbors.js.map +0 -1
- package/dist/src/content-delivery-layer/plumtree/PlumtreeManager.d.ts +0 -37
- package/dist/src/content-delivery-layer/plumtree/PlumtreeManager.js +0 -141
- package/dist/src/content-delivery-layer/plumtree/PlumtreeManager.js.map +0 -1
- package/dist/src/content-delivery-layer/plumtree/PlumtreeRpcLocal.d.ts +0 -20
- package/dist/src/content-delivery-layer/plumtree/PlumtreeRpcLocal.js +0 -37
- package/dist/src/content-delivery-layer/plumtree/PlumtreeRpcLocal.js.map +0 -1
- package/dist/src/content-delivery-layer/plumtree/PlumtreeRpcRemote.d.ts +0 -8
- package/dist/src/content-delivery-layer/plumtree/PlumtreeRpcRemote.js +0 -26
- package/dist/src/content-delivery-layer/plumtree/PlumtreeRpcRemote.js.map +0 -1
- package/dist/src/content-delivery-layer/propagation/FifoMapWithTTL.d.ts +0 -29
- package/dist/src/content-delivery-layer/propagation/FifoMapWithTTL.js +0 -93
- package/dist/src/content-delivery-layer/propagation/FifoMapWithTTL.js.map +0 -1
- package/dist/src/content-delivery-layer/propagation/Propagation.d.ts +0 -35
- package/dist/src/content-delivery-layer/propagation/Propagation.js +0 -68
- package/dist/src/content-delivery-layer/propagation/Propagation.js.map +0 -1
- package/dist/src/content-delivery-layer/propagation/PropagationTaskStore.d.ts +0 -22
- package/dist/src/content-delivery-layer/propagation/PropagationTaskStore.js +0 -33
- package/dist/src/content-delivery-layer/propagation/PropagationTaskStore.js.map +0 -1
- package/dist/src/content-delivery-layer/proxy/ProxyClient.d.ts +0 -46
- package/dist/src/content-delivery-layer/proxy/ProxyClient.js +0 -214
- package/dist/src/content-delivery-layer/proxy/ProxyClient.js.map +0 -1
- package/dist/src/content-delivery-layer/proxy/ProxyConnectionRpcLocal.d.ts +0 -34
- package/dist/src/content-delivery-layer/proxy/ProxyConnectionRpcLocal.js +0 -72
- package/dist/src/content-delivery-layer/proxy/ProxyConnectionRpcLocal.js.map +0 -1
- package/dist/src/content-delivery-layer/proxy/ProxyConnectionRpcRemote.d.ts +0 -7
- package/dist/src/content-delivery-layer/proxy/ProxyConnectionRpcRemote.js +0 -27
- package/dist/src/content-delivery-layer/proxy/ProxyConnectionRpcRemote.js.map +0 -1
- package/dist/src/content-delivery-layer/temporary-connection/TemporaryConnectionRpcLocal.d.ts +0 -26
- package/dist/src/content-delivery-layer/temporary-connection/TemporaryConnectionRpcLocal.js +0 -45
- package/dist/src/content-delivery-layer/temporary-connection/TemporaryConnectionRpcLocal.js.map +0 -1
- package/dist/src/content-delivery-layer/temporary-connection/TemporaryConnectionRpcRemote.d.ts +0 -6
- package/dist/src/content-delivery-layer/temporary-connection/TemporaryConnectionRpcRemote.js +0 -31
- package/dist/src/content-delivery-layer/temporary-connection/TemporaryConnectionRpcRemote.js.map +0 -1
- package/dist/src/control-layer/ControlLayerNode.d.ts +0 -16
- package/dist/src/control-layer/ControlLayerNode.js +0 -3
- package/dist/src/control-layer/ControlLayerNode.js.map +0 -1
- package/dist/src/control-layer/ExternalNetworkRpc.d.ts +0 -16
- package/dist/src/control-layer/ExternalNetworkRpc.js +0 -23
- package/dist/src/control-layer/ExternalNetworkRpc.js.map +0 -1
- package/dist/src/control-layer/PeerDescriptorStoreManager.d.ts +0 -28
- package/dist/src/control-layer/PeerDescriptorStoreManager.js +0 -78
- package/dist/src/control-layer/PeerDescriptorStoreManager.js.map +0 -1
- package/dist/src/discovery-layer/DiscoveryLayerNode.d.ts +0 -28
- package/dist/src/discovery-layer/DiscoveryLayerNode.js +0 -3
- package/dist/src/discovery-layer/DiscoveryLayerNode.js.map +0 -1
- package/dist/src/exports.d.ts +0 -6
- package/dist/src/exports.js +0 -24
- package/dist/src/exports.js.map +0 -1
- package/dist/src/types.d.ts +0 -6
- package/dist/src/types.js +0 -3
- package/dist/src/types.js.map +0 -1
- package/dist/src/utils.d.ts +0 -3
- package/dist/src/utils.js +0 -17
- package/dist/src/utils.js.map +0 -1
- package/dist/test/benchmark/first-message.d.ts +0 -1
- package/dist/test/benchmark/first-message.js +0 -139
- package/dist/test/benchmark/first-message.js.map +0 -1
- package/dist/test/utils/utils.d.ts +0 -15
- package/dist/test/utils/utils.js +0 -106
- package/dist/test/utils/utils.js.map +0 -1
package/dist/exports.cjs
ADDED
|
@@ -0,0 +1,4489 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var dht = require('@streamr/dht');
|
|
4
|
+
var protoRpc = require('@streamr/proto-rpc');
|
|
5
|
+
var utils = require('@streamr/utils');
|
|
6
|
+
var pull = require('lodash/pull');
|
|
7
|
+
var eventemitter3 = require('eventemitter3');
|
|
8
|
+
var sampleSize = require('lodash/sampleSize');
|
|
9
|
+
var runtime = require('@protobuf-ts/runtime');
|
|
10
|
+
var runtimeRpc = require('@protobuf-ts/runtime-rpc');
|
|
11
|
+
var uuid = require('uuid');
|
|
12
|
+
var sample = require('lodash/sample');
|
|
13
|
+
var yallist = require('yallist');
|
|
14
|
+
|
|
15
|
+
const SERVICE_ID$1 = 'external-network-service';
|
|
16
|
+
class ExternalNetworkRpc {
|
|
17
|
+
rpcCommunicator;
|
|
18
|
+
constructor(transport) {
|
|
19
|
+
this.rpcCommunicator = new dht.ListeningRpcCommunicator(SERVICE_ID$1, transport);
|
|
20
|
+
}
|
|
21
|
+
registerRpcMethod(request, response, name, fn) {
|
|
22
|
+
this.rpcCommunicator.registerRpcMethod(request, response, name, fn);
|
|
23
|
+
}
|
|
24
|
+
createRpcClient(clientClass) {
|
|
25
|
+
return protoRpc.toProtoRpcClient(new clientClass(this.rpcCommunicator.getRpcClientTransport()));
|
|
26
|
+
}
|
|
27
|
+
destroy() {
|
|
28
|
+
this.rpcCommunicator.destroy();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var version = "103.2.0-experiment.0";
|
|
33
|
+
|
|
34
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
35
|
+
class Any$Type extends runtime.MessageType {
|
|
36
|
+
constructor() {
|
|
37
|
+
super("google.protobuf.Any", [
|
|
38
|
+
{ no: 1, name: "type_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
39
|
+
{ no: 2, name: "value", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Pack the message into a new `Any`.
|
|
44
|
+
*
|
|
45
|
+
* Uses 'type.googleapis.com/full.type.name' as the type URL.
|
|
46
|
+
*/
|
|
47
|
+
pack(message, type) {
|
|
48
|
+
return {
|
|
49
|
+
typeUrl: this.typeNameToUrl(type.typeName), value: type.toBinary(message),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Unpack the message from the `Any`.
|
|
54
|
+
*/
|
|
55
|
+
unpack(any, type, options) {
|
|
56
|
+
if (!this.contains(any, type))
|
|
57
|
+
throw new Error("Cannot unpack google.protobuf.Any with typeUrl '" + any.typeUrl + "' as " + type.typeName + ".");
|
|
58
|
+
return type.fromBinary(any.value, options);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Does the given `Any` contain a packed message of the given type?
|
|
62
|
+
*/
|
|
63
|
+
contains(any, type) {
|
|
64
|
+
if (!any.typeUrl.length)
|
|
65
|
+
return false;
|
|
66
|
+
let wants = typeof type == "string" ? type : type.typeName;
|
|
67
|
+
let has = this.typeUrlToName(any.typeUrl);
|
|
68
|
+
return wants === has;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Convert the message to canonical JSON value.
|
|
72
|
+
*
|
|
73
|
+
* You have to provide the `typeRegistry` option so that the
|
|
74
|
+
* packed message can be converted to JSON.
|
|
75
|
+
*
|
|
76
|
+
* The `typeRegistry` option is also required to read
|
|
77
|
+
* `google.protobuf.Any` from JSON format.
|
|
78
|
+
*/
|
|
79
|
+
internalJsonWrite(any, options) {
|
|
80
|
+
if (any.typeUrl === "")
|
|
81
|
+
return {};
|
|
82
|
+
let typeName = this.typeUrlToName(any.typeUrl);
|
|
83
|
+
let opt = runtime.jsonWriteOptions(options);
|
|
84
|
+
let type = opt.typeRegistry?.find(t => t.typeName === typeName);
|
|
85
|
+
if (!type)
|
|
86
|
+
throw new globalThis.Error("Unable to convert google.protobuf.Any with typeUrl '" + any.typeUrl + "' to JSON. The specified type " + typeName + " is not available in the type registry.");
|
|
87
|
+
let value = type.fromBinary(any.value, { readUnknownField: false });
|
|
88
|
+
let json = type.internalJsonWrite(value, opt);
|
|
89
|
+
if (typeName.startsWith("google.protobuf.") || !runtime.isJsonObject(json))
|
|
90
|
+
json = { value: json };
|
|
91
|
+
json["@type"] = any.typeUrl;
|
|
92
|
+
return json;
|
|
93
|
+
}
|
|
94
|
+
internalJsonRead(json, options, target) {
|
|
95
|
+
if (!runtime.isJsonObject(json))
|
|
96
|
+
throw new globalThis.Error("Unable to parse google.protobuf.Any from JSON " + runtime.typeofJsonValue(json) + ".");
|
|
97
|
+
if (typeof json["@type"] != "string" || json["@type"] == "")
|
|
98
|
+
return this.create();
|
|
99
|
+
let typeName = this.typeUrlToName(json["@type"]);
|
|
100
|
+
let type = options?.typeRegistry?.find(t => t.typeName == typeName);
|
|
101
|
+
if (!type)
|
|
102
|
+
throw new globalThis.Error("Unable to parse google.protobuf.Any from JSON. The specified type " + typeName + " is not available in the type registry.");
|
|
103
|
+
let value;
|
|
104
|
+
if (typeName.startsWith("google.protobuf.") && json.hasOwnProperty("value"))
|
|
105
|
+
value = type.fromJson(json["value"], options);
|
|
106
|
+
else {
|
|
107
|
+
let copy = Object.assign({}, json);
|
|
108
|
+
delete copy["@type"];
|
|
109
|
+
value = type.fromJson(copy, options);
|
|
110
|
+
}
|
|
111
|
+
if (target === undefined)
|
|
112
|
+
target = this.create();
|
|
113
|
+
target.typeUrl = json["@type"];
|
|
114
|
+
target.value = type.toBinary(value);
|
|
115
|
+
return target;
|
|
116
|
+
}
|
|
117
|
+
typeNameToUrl(name) {
|
|
118
|
+
if (!name.length)
|
|
119
|
+
throw new Error("invalid type name: " + name);
|
|
120
|
+
return "type.googleapis.com/" + name;
|
|
121
|
+
}
|
|
122
|
+
typeUrlToName(url) {
|
|
123
|
+
if (!url.length)
|
|
124
|
+
throw new Error("invalid type url: " + url);
|
|
125
|
+
let slash = url.lastIndexOf("/");
|
|
126
|
+
let name = slash > 0 ? url.substring(slash + 1) : url;
|
|
127
|
+
if (!name.length)
|
|
128
|
+
throw new Error("invalid type url: " + url);
|
|
129
|
+
return name;
|
|
130
|
+
}
|
|
131
|
+
create(value) {
|
|
132
|
+
const message = globalThis.Object.create((this.messagePrototype));
|
|
133
|
+
message.typeUrl = "";
|
|
134
|
+
message.value = new Uint8Array(0);
|
|
135
|
+
if (value !== undefined)
|
|
136
|
+
runtime.reflectionMergePartial(this, message, value);
|
|
137
|
+
return message;
|
|
138
|
+
}
|
|
139
|
+
internalBinaryRead(reader, length, options, target) {
|
|
140
|
+
let message = target ?? this.create(), end = reader.pos + length;
|
|
141
|
+
while (reader.pos < end) {
|
|
142
|
+
let [fieldNo, wireType] = reader.tag();
|
|
143
|
+
switch (fieldNo) {
|
|
144
|
+
case /* string type_url */ 1:
|
|
145
|
+
message.typeUrl = reader.string();
|
|
146
|
+
break;
|
|
147
|
+
case /* bytes value */ 2:
|
|
148
|
+
message.value = reader.bytes();
|
|
149
|
+
break;
|
|
150
|
+
default:
|
|
151
|
+
let u = options.readUnknownField;
|
|
152
|
+
if (u === "throw")
|
|
153
|
+
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
|
154
|
+
let d = reader.skip(wireType);
|
|
155
|
+
if (u !== false)
|
|
156
|
+
(u === true ? runtime.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return message;
|
|
160
|
+
}
|
|
161
|
+
internalBinaryWrite(message, writer, options) {
|
|
162
|
+
/* string type_url = 1; */
|
|
163
|
+
if (message.typeUrl !== "")
|
|
164
|
+
writer.tag(1, runtime.WireType.LengthDelimited).string(message.typeUrl);
|
|
165
|
+
/* bytes value = 2; */
|
|
166
|
+
if (message.value.length)
|
|
167
|
+
writer.tag(2, runtime.WireType.LengthDelimited).bytes(message.value);
|
|
168
|
+
let u = options.writeUnknownFields;
|
|
169
|
+
if (u !== false)
|
|
170
|
+
(u == true ? runtime.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
|
171
|
+
return writer;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* @generated MessageType for protobuf message google.protobuf.Any
|
|
176
|
+
*/
|
|
177
|
+
const Any = new Any$Type();
|
|
178
|
+
|
|
179
|
+
const parsePeerDescriptor = (dataEntries) => {
|
|
180
|
+
return dataEntries.filter((entry) => !entry.deleted).map((entry) => Any.unpack(entry.data, dht.PeerDescriptor));
|
|
181
|
+
};
|
|
182
|
+
const logger$h = new utils.Logger('PeerDescriptorStoreManager');
|
|
183
|
+
const MAX_NODE_COUNT = 8;
|
|
184
|
+
/**
|
|
185
|
+
* For each key there is usually 0-MAX_NODE_COUNT PeerDescriptors stored in the DHT. If there are fewer node,
|
|
186
|
+
* the peer descriptor of the local node is stored to the DHT.
|
|
187
|
+
*/
|
|
188
|
+
class PeerDescriptorStoreManager {
|
|
189
|
+
abortController;
|
|
190
|
+
options;
|
|
191
|
+
isLocalNodeStored_ = false;
|
|
192
|
+
constructor(options) {
|
|
193
|
+
this.options = options;
|
|
194
|
+
this.abortController = new AbortController();
|
|
195
|
+
}
|
|
196
|
+
async fetchNodes() {
|
|
197
|
+
logger$h.trace('Fetch data', { key: this.options.key });
|
|
198
|
+
try {
|
|
199
|
+
const result = await this.options.fetchDataFromDht(this.options.key);
|
|
200
|
+
return parsePeerDescriptor(result);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return [];
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async storeAndKeepLocalNode() {
|
|
207
|
+
if (this.abortController.signal.aborted) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
211
|
+
this.isLocalNodeStored_ = true;
|
|
212
|
+
await this.storeLocalNode();
|
|
213
|
+
await this.keepLocalNode();
|
|
214
|
+
}
|
|
215
|
+
async storeLocalNode() {
|
|
216
|
+
const localPeerDescriptor = this.options.localPeerDescriptor;
|
|
217
|
+
const dataToStore = Any.pack(localPeerDescriptor, dht.PeerDescriptor);
|
|
218
|
+
try {
|
|
219
|
+
await this.options.storeDataToDht(this.options.key, dataToStore);
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
logger$h.warn('Failed to store local node', { key: this.options.key });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
async keepLocalNode() {
|
|
226
|
+
await utils.scheduleAtInterval(async () => {
|
|
227
|
+
logger$h.trace('Attempting to keep local node', { key: this.options.key });
|
|
228
|
+
try {
|
|
229
|
+
const discovered = await this.fetchNodes();
|
|
230
|
+
if (discovered.length < MAX_NODE_COUNT
|
|
231
|
+
|| discovered.some((peerDescriptor) => dht.areEqualPeerDescriptors(peerDescriptor, this.options.localPeerDescriptor))) {
|
|
232
|
+
await this.storeLocalNode();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
logger$h.debug('Failed to keep local node', { key: this.options.key });
|
|
237
|
+
}
|
|
238
|
+
}, this.options.storeInterval ?? 60000, false, this.abortController.signal);
|
|
239
|
+
}
|
|
240
|
+
isLocalNodeStored() {
|
|
241
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
242
|
+
return this.isLocalNodeStored_;
|
|
243
|
+
}
|
|
244
|
+
async destroy() {
|
|
245
|
+
this.abortController.abort();
|
|
246
|
+
await this.options.deleteDataFromDht(this.options.key, false);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/*
|
|
251
|
+
* Tries to find new neighbors if we currently have less than MIN_NEIGHBOR_COUNT neigbors. It does so by
|
|
252
|
+
* rejoining the stream's control layer network.
|
|
253
|
+
*
|
|
254
|
+
* This way we can avoid some network split scenarios. The functionality is most relevant for small stream
|
|
255
|
+
* networks.
|
|
256
|
+
*/
|
|
257
|
+
const logger$g = new utils.Logger('StreamPartNetworkSplitAvoidance');
|
|
258
|
+
const exponentialRunOff = async (task, description, abortSignal, baseDelay = 500, maxAttempts = 6) => {
|
|
259
|
+
for (let i = 1; i <= maxAttempts; i++) {
|
|
260
|
+
if (abortSignal.aborted) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const factor = 2 ** i;
|
|
264
|
+
const delay = baseDelay * factor;
|
|
265
|
+
try {
|
|
266
|
+
await task();
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
logger$g.trace(`${description} failed, retrying in ${delay} ms`);
|
|
270
|
+
}
|
|
271
|
+
try { // Abort controller throws unexpected errors in destroy?
|
|
272
|
+
await utils.wait(delay, abortSignal);
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
276
|
+
logger$g.trace(`${err}`); // TODO Do we need logging?
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
const MIN_NEIGHBOR_COUNT = 4;
|
|
281
|
+
class StreamPartNetworkSplitAvoidance {
|
|
282
|
+
abortController;
|
|
283
|
+
options;
|
|
284
|
+
excludedNodes = new Set();
|
|
285
|
+
running = false;
|
|
286
|
+
constructor(options) {
|
|
287
|
+
this.options = options;
|
|
288
|
+
this.abortController = new AbortController();
|
|
289
|
+
}
|
|
290
|
+
async avoidNetworkSplit() {
|
|
291
|
+
this.running = true;
|
|
292
|
+
await exponentialRunOff(async () => {
|
|
293
|
+
const discoveredEntrypoints = await this.options.discoverEntryPoints();
|
|
294
|
+
const filteredEntryPoints = discoveredEntrypoints.filter((peer) => !this.excludedNodes.has(dht.toNodeId(peer)));
|
|
295
|
+
await this.options.discoveryLayerNode.joinDht(filteredEntryPoints, false, false);
|
|
296
|
+
if (this.options.discoveryLayerNode.getNeighborCount() < MIN_NEIGHBOR_COUNT) {
|
|
297
|
+
// Filter out nodes that are not neighbors as those nodes are assumed to be offline
|
|
298
|
+
const newExcludes = filteredEntryPoints
|
|
299
|
+
.filter((peer) => !this.options.discoveryLayerNode.getNeighbors()
|
|
300
|
+
.some((neighbor) => dht.areEqualPeerDescriptors(neighbor, peer)))
|
|
301
|
+
.map((peer) => dht.toNodeId(peer));
|
|
302
|
+
newExcludes.forEach((node) => this.excludedNodes.add(node));
|
|
303
|
+
throw new Error(`Network split is still possible`);
|
|
304
|
+
}
|
|
305
|
+
}, 'avoid network split', this.abortController.signal, this.options.exponentialRunOfBaseDelay);
|
|
306
|
+
this.running = false;
|
|
307
|
+
this.excludedNodes.clear();
|
|
308
|
+
logger$g.trace(`Network split avoided`);
|
|
309
|
+
}
|
|
310
|
+
isRunning() {
|
|
311
|
+
return this.running;
|
|
312
|
+
}
|
|
313
|
+
destroy() {
|
|
314
|
+
this.abortController.abort();
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const DEFAULT_RECONNECT_INTERVAL = 30 * 1000;
|
|
319
|
+
class StreamPartReconnect {
|
|
320
|
+
abortController;
|
|
321
|
+
discoveryLayerNode;
|
|
322
|
+
peerDescriptorStoreManager;
|
|
323
|
+
constructor(discoveryLayerNode, peerDescriptorStoreManager) {
|
|
324
|
+
this.discoveryLayerNode = discoveryLayerNode;
|
|
325
|
+
this.peerDescriptorStoreManager = peerDescriptorStoreManager;
|
|
326
|
+
}
|
|
327
|
+
async reconnect(timeout = DEFAULT_RECONNECT_INTERVAL) {
|
|
328
|
+
this.abortController = new AbortController();
|
|
329
|
+
await utils.scheduleAtInterval(async () => {
|
|
330
|
+
const entryPoints = await this.peerDescriptorStoreManager.fetchNodes();
|
|
331
|
+
await this.discoveryLayerNode.joinDht(entryPoints);
|
|
332
|
+
// Is is necessary to store the node as an entry point here?
|
|
333
|
+
if (!this.peerDescriptorStoreManager.isLocalNodeStored() && entryPoints.length < MAX_NODE_COUNT) {
|
|
334
|
+
await this.peerDescriptorStoreManager.storeAndKeepLocalNode();
|
|
335
|
+
}
|
|
336
|
+
if (this.discoveryLayerNode.getNeighborCount() > 0) {
|
|
337
|
+
this.abortController.abort();
|
|
338
|
+
}
|
|
339
|
+
}, timeout, true, this.abortController.signal);
|
|
340
|
+
}
|
|
341
|
+
isRunning() {
|
|
342
|
+
return this.abortController ? !this.abortController.signal.aborted : false;
|
|
343
|
+
}
|
|
344
|
+
destroy() {
|
|
345
|
+
this.abortController?.abort();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
350
|
+
class Empty$Type extends runtime.MessageType {
|
|
351
|
+
constructor() {
|
|
352
|
+
super("google.protobuf.Empty", []);
|
|
353
|
+
}
|
|
354
|
+
create(value) {
|
|
355
|
+
const message = globalThis.Object.create((this.messagePrototype));
|
|
356
|
+
if (value !== undefined)
|
|
357
|
+
runtime.reflectionMergePartial(this, message, value);
|
|
358
|
+
return message;
|
|
359
|
+
}
|
|
360
|
+
internalBinaryRead(reader, length, options, target) {
|
|
361
|
+
let message = target ?? this.create(), end = reader.pos + length;
|
|
362
|
+
while (reader.pos < end) {
|
|
363
|
+
let [fieldNo, wireType] = reader.tag();
|
|
364
|
+
switch (fieldNo) {
|
|
365
|
+
default:
|
|
366
|
+
let u = options.readUnknownField;
|
|
367
|
+
if (u === "throw")
|
|
368
|
+
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
|
369
|
+
let d = reader.skip(wireType);
|
|
370
|
+
if (u !== false)
|
|
371
|
+
(u === true ? runtime.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return message;
|
|
375
|
+
}
|
|
376
|
+
internalBinaryWrite(message, writer, options) {
|
|
377
|
+
let u = options.writeUnknownFields;
|
|
378
|
+
if (u !== false)
|
|
379
|
+
(u == true ? runtime.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
|
380
|
+
return writer;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* @generated MessageType for protobuf message google.protobuf.Empty
|
|
385
|
+
*/
|
|
386
|
+
const Empty = new Empty$Type();
|
|
387
|
+
|
|
388
|
+
// @generated by protobuf-ts 2.11.1 with parameter server_generic,generate_dependencies,long_type_number
|
|
389
|
+
// @generated from protobuf file "packages/proto-rpc/protos/ProtoRpc.proto" (package "protorpc", syntax proto3)
|
|
390
|
+
// tslint:disable
|
|
391
|
+
/**
|
|
392
|
+
* @generated from protobuf enum protorpc.RpcErrorType
|
|
393
|
+
*/
|
|
394
|
+
var RpcErrorType;
|
|
395
|
+
(function (RpcErrorType) {
|
|
396
|
+
/**
|
|
397
|
+
* @generated from protobuf enum value: SERVER_TIMEOUT = 0;
|
|
398
|
+
*/
|
|
399
|
+
RpcErrorType[RpcErrorType["SERVER_TIMEOUT"] = 0] = "SERVER_TIMEOUT";
|
|
400
|
+
/**
|
|
401
|
+
* @generated from protobuf enum value: CLIENT_TIMEOUT = 1;
|
|
402
|
+
*/
|
|
403
|
+
RpcErrorType[RpcErrorType["CLIENT_TIMEOUT"] = 1] = "CLIENT_TIMEOUT";
|
|
404
|
+
/**
|
|
405
|
+
* @generated from protobuf enum value: UNKNOWN_RPC_METHOD = 2;
|
|
406
|
+
*/
|
|
407
|
+
RpcErrorType[RpcErrorType["UNKNOWN_RPC_METHOD"] = 2] = "UNKNOWN_RPC_METHOD";
|
|
408
|
+
/**
|
|
409
|
+
* @generated from protobuf enum value: CLIENT_ERROR = 3;
|
|
410
|
+
*/
|
|
411
|
+
RpcErrorType[RpcErrorType["CLIENT_ERROR"] = 3] = "CLIENT_ERROR";
|
|
412
|
+
/**
|
|
413
|
+
* @generated from protobuf enum value: SERVER_ERROR = 4;
|
|
414
|
+
*/
|
|
415
|
+
RpcErrorType[RpcErrorType["SERVER_ERROR"] = 4] = "SERVER_ERROR";
|
|
416
|
+
})(RpcErrorType || (RpcErrorType = {}));
|
|
417
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
418
|
+
class RpcMessage$Type extends runtime.MessageType {
|
|
419
|
+
constructor() {
|
|
420
|
+
super("protorpc.RpcMessage", [
|
|
421
|
+
{ no: 1, name: "header", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "scalar", T: 9 /*ScalarType.STRING*/ } },
|
|
422
|
+
{ no: 2, name: "body", kind: "message", T: () => Any },
|
|
423
|
+
{ no: 3, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
424
|
+
{ no: 4, name: "errorType", kind: "enum", opt: true, T: () => ["protorpc.RpcErrorType", RpcErrorType] },
|
|
425
|
+
{ no: 5, name: "errorClassName", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
|
|
426
|
+
{ no: 6, name: "errorCode", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
|
|
427
|
+
{ no: 7, name: "errorMessage", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }
|
|
428
|
+
]);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* @generated MessageType for protobuf message protorpc.RpcMessage
|
|
433
|
+
*/
|
|
434
|
+
const RpcMessage = new RpcMessage$Type();
|
|
435
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
436
|
+
class Mnfo2uhnf92hvqi2nviouq2hv9puhq$Type extends runtime.MessageType {
|
|
437
|
+
constructor() {
|
|
438
|
+
super("protorpc.Mnfo2uhnf92hvqi2nviouq2hv9puhq", [
|
|
439
|
+
{ no: 1, name: "empty", kind: "message", T: () => Empty }
|
|
440
|
+
]);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* @generated MessageType for protobuf message protorpc.Mnfo2uhnf92hvqi2nviouq2hv9puhq
|
|
445
|
+
*/
|
|
446
|
+
new Mnfo2uhnf92hvqi2nviouq2hv9puhq$Type();
|
|
447
|
+
|
|
448
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
449
|
+
class Timestamp$Type extends runtime.MessageType {
|
|
450
|
+
constructor() {
|
|
451
|
+
super("google.protobuf.Timestamp", [
|
|
452
|
+
{ no: 1, name: "seconds", kind: "scalar", T: 3 /*ScalarType.INT64*/, L: 2 /*LongType.NUMBER*/ },
|
|
453
|
+
{ no: 2, name: "nanos", kind: "scalar", T: 5 /*ScalarType.INT32*/ }
|
|
454
|
+
]);
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Creates a new `Timestamp` for the current time.
|
|
458
|
+
*/
|
|
459
|
+
now() {
|
|
460
|
+
const msg = this.create();
|
|
461
|
+
const ms = Date.now();
|
|
462
|
+
msg.seconds = runtime.PbLong.from(Math.floor(ms / 1000)).toNumber();
|
|
463
|
+
msg.nanos = (ms % 1000) * 1000000;
|
|
464
|
+
return msg;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Converts a `Timestamp` to a JavaScript Date.
|
|
468
|
+
*/
|
|
469
|
+
toDate(message) {
|
|
470
|
+
return new Date(runtime.PbLong.from(message.seconds).toNumber() * 1000 + Math.ceil(message.nanos / 1000000));
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Converts a JavaScript Date to a `Timestamp`.
|
|
474
|
+
*/
|
|
475
|
+
fromDate(date) {
|
|
476
|
+
const msg = this.create();
|
|
477
|
+
const ms = date.getTime();
|
|
478
|
+
msg.seconds = runtime.PbLong.from(Math.floor(ms / 1000)).toNumber();
|
|
479
|
+
msg.nanos = ((ms % 1000) + (ms < 0 && ms % 1000 !== 0 ? 1000 : 0)) * 1000000;
|
|
480
|
+
return msg;
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* In JSON format, the `Timestamp` type is encoded as a string
|
|
484
|
+
* in the RFC 3339 format.
|
|
485
|
+
*/
|
|
486
|
+
internalJsonWrite(message, options) {
|
|
487
|
+
let ms = runtime.PbLong.from(message.seconds).toNumber() * 1000;
|
|
488
|
+
if (ms < Date.parse("0001-01-01T00:00:00Z") || ms > Date.parse("9999-12-31T23:59:59Z"))
|
|
489
|
+
throw new Error("Unable to encode Timestamp to JSON. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.");
|
|
490
|
+
if (message.nanos < 0)
|
|
491
|
+
throw new Error("Unable to encode invalid Timestamp to JSON. Nanos must not be negative.");
|
|
492
|
+
let z = "Z";
|
|
493
|
+
if (message.nanos > 0) {
|
|
494
|
+
let nanosStr = (message.nanos + 1000000000).toString().substring(1);
|
|
495
|
+
if (nanosStr.substring(3) === "000000")
|
|
496
|
+
z = "." + nanosStr.substring(0, 3) + "Z";
|
|
497
|
+
else if (nanosStr.substring(6) === "000")
|
|
498
|
+
z = "." + nanosStr.substring(0, 6) + "Z";
|
|
499
|
+
else
|
|
500
|
+
z = "." + nanosStr + "Z";
|
|
501
|
+
}
|
|
502
|
+
return new Date(ms).toISOString().replace(".000Z", z);
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* In JSON format, the `Timestamp` type is encoded as a string
|
|
506
|
+
* in the RFC 3339 format.
|
|
507
|
+
*/
|
|
508
|
+
internalJsonRead(json, options, target) {
|
|
509
|
+
if (typeof json !== "string")
|
|
510
|
+
throw new Error("Unable to parse Timestamp from JSON " + runtime.typeofJsonValue(json) + ".");
|
|
511
|
+
let matches = json.match(/^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(?:Z|\.([0-9]{3,9})Z|([+-][0-9][0-9]:[0-9][0-9]))$/);
|
|
512
|
+
if (!matches)
|
|
513
|
+
throw new Error("Unable to parse Timestamp from JSON. Invalid format.");
|
|
514
|
+
let ms = Date.parse(matches[1] + "-" + matches[2] + "-" + matches[3] + "T" + matches[4] + ":" + matches[5] + ":" + matches[6] + (matches[8] ? matches[8] : "Z"));
|
|
515
|
+
if (Number.isNaN(ms))
|
|
516
|
+
throw new Error("Unable to parse Timestamp from JSON. Invalid value.");
|
|
517
|
+
if (ms < Date.parse("0001-01-01T00:00:00Z") || ms > Date.parse("9999-12-31T23:59:59Z"))
|
|
518
|
+
throw new globalThis.Error("Unable to parse Timestamp from JSON. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.");
|
|
519
|
+
if (!target)
|
|
520
|
+
target = this.create();
|
|
521
|
+
target.seconds = runtime.PbLong.from(ms / 1000).toNumber();
|
|
522
|
+
target.nanos = 0;
|
|
523
|
+
if (matches[7])
|
|
524
|
+
target.nanos = (parseInt("1" + matches[7] + "0".repeat(9 - matches[7].length)) - 1000000000);
|
|
525
|
+
return target;
|
|
526
|
+
}
|
|
527
|
+
create(value) {
|
|
528
|
+
const message = globalThis.Object.create((this.messagePrototype));
|
|
529
|
+
message.seconds = 0;
|
|
530
|
+
message.nanos = 0;
|
|
531
|
+
if (value !== undefined)
|
|
532
|
+
runtime.reflectionMergePartial(this, message, value);
|
|
533
|
+
return message;
|
|
534
|
+
}
|
|
535
|
+
internalBinaryRead(reader, length, options, target) {
|
|
536
|
+
let message = target ?? this.create(), end = reader.pos + length;
|
|
537
|
+
while (reader.pos < end) {
|
|
538
|
+
let [fieldNo, wireType] = reader.tag();
|
|
539
|
+
switch (fieldNo) {
|
|
540
|
+
case /* int64 seconds */ 1:
|
|
541
|
+
message.seconds = reader.int64().toNumber();
|
|
542
|
+
break;
|
|
543
|
+
case /* int32 nanos */ 2:
|
|
544
|
+
message.nanos = reader.int32();
|
|
545
|
+
break;
|
|
546
|
+
default:
|
|
547
|
+
let u = options.readUnknownField;
|
|
548
|
+
if (u === "throw")
|
|
549
|
+
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
|
550
|
+
let d = reader.skip(wireType);
|
|
551
|
+
if (u !== false)
|
|
552
|
+
(u === true ? runtime.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return message;
|
|
556
|
+
}
|
|
557
|
+
internalBinaryWrite(message, writer, options) {
|
|
558
|
+
/* int64 seconds = 1; */
|
|
559
|
+
if (message.seconds !== 0)
|
|
560
|
+
writer.tag(1, runtime.WireType.Varint).int64(message.seconds);
|
|
561
|
+
/* int32 nanos = 2; */
|
|
562
|
+
if (message.nanos !== 0)
|
|
563
|
+
writer.tag(2, runtime.WireType.Varint).int32(message.nanos);
|
|
564
|
+
let u = options.writeUnknownFields;
|
|
565
|
+
if (u !== false)
|
|
566
|
+
(u == true ? runtime.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
|
567
|
+
return writer;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* @generated MessageType for protobuf message google.protobuf.Timestamp
|
|
572
|
+
*/
|
|
573
|
+
const Timestamp = new Timestamp$Type();
|
|
574
|
+
|
|
575
|
+
// @generated by protobuf-ts 2.11.1 with parameter server_generic,generate_dependencies,long_type_number
|
|
576
|
+
// @generated from protobuf file "packages/dht/protos/DhtRpc.proto" (package "dht", syntax proto3)
|
|
577
|
+
// tslint:disable
|
|
578
|
+
/**
|
|
579
|
+
* @generated from protobuf enum dht.RecursiveOperation
|
|
580
|
+
*/
|
|
581
|
+
var RecursiveOperation;
|
|
582
|
+
(function (RecursiveOperation) {
|
|
583
|
+
/**
|
|
584
|
+
* @generated from protobuf enum value: FIND_CLOSEST_NODES = 0;
|
|
585
|
+
*/
|
|
586
|
+
RecursiveOperation[RecursiveOperation["FIND_CLOSEST_NODES"] = 0] = "FIND_CLOSEST_NODES";
|
|
587
|
+
/**
|
|
588
|
+
* @generated from protobuf enum value: FETCH_DATA = 1;
|
|
589
|
+
*/
|
|
590
|
+
RecursiveOperation[RecursiveOperation["FETCH_DATA"] = 1] = "FETCH_DATA";
|
|
591
|
+
/**
|
|
592
|
+
* @generated from protobuf enum value: DELETE_DATA = 2;
|
|
593
|
+
*/
|
|
594
|
+
RecursiveOperation[RecursiveOperation["DELETE_DATA"] = 2] = "DELETE_DATA";
|
|
595
|
+
})(RecursiveOperation || (RecursiveOperation = {}));
|
|
596
|
+
/**
|
|
597
|
+
* @generated from protobuf enum dht.NodeType
|
|
598
|
+
*/
|
|
599
|
+
var NodeType;
|
|
600
|
+
(function (NodeType) {
|
|
601
|
+
/**
|
|
602
|
+
* @generated from protobuf enum value: NODEJS = 0;
|
|
603
|
+
*/
|
|
604
|
+
NodeType[NodeType["NODEJS"] = 0] = "NODEJS";
|
|
605
|
+
/**
|
|
606
|
+
* @generated from protobuf enum value: BROWSER = 1;
|
|
607
|
+
*/
|
|
608
|
+
NodeType[NodeType["BROWSER"] = 1] = "BROWSER";
|
|
609
|
+
})(NodeType || (NodeType = {}));
|
|
610
|
+
/**
|
|
611
|
+
* @generated from protobuf enum dht.RpcResponseError
|
|
612
|
+
*/
|
|
613
|
+
var RpcResponseError;
|
|
614
|
+
(function (RpcResponseError) {
|
|
615
|
+
/**
|
|
616
|
+
* @generated from protobuf enum value: SERVER_TIMOUT = 0;
|
|
617
|
+
*/
|
|
618
|
+
RpcResponseError[RpcResponseError["SERVER_TIMOUT"] = 0] = "SERVER_TIMOUT";
|
|
619
|
+
/**
|
|
620
|
+
* @generated from protobuf enum value: CLIENT_TIMEOUT = 1;
|
|
621
|
+
*/
|
|
622
|
+
RpcResponseError[RpcResponseError["CLIENT_TIMEOUT"] = 1] = "CLIENT_TIMEOUT";
|
|
623
|
+
/**
|
|
624
|
+
* @generated from protobuf enum value: SERVER_ERROR = 2;
|
|
625
|
+
*/
|
|
626
|
+
RpcResponseError[RpcResponseError["SERVER_ERROR"] = 2] = "SERVER_ERROR";
|
|
627
|
+
/**
|
|
628
|
+
* @generated from protobuf enum value: UNKNOWN_RPC_METHOD = 3;
|
|
629
|
+
*/
|
|
630
|
+
RpcResponseError[RpcResponseError["UNKNOWN_RPC_METHOD"] = 3] = "UNKNOWN_RPC_METHOD";
|
|
631
|
+
})(RpcResponseError || (RpcResponseError = {}));
|
|
632
|
+
/**
|
|
633
|
+
* @generated from protobuf enum dht.RouteMessageError
|
|
634
|
+
*/
|
|
635
|
+
var RouteMessageError;
|
|
636
|
+
(function (RouteMessageError) {
|
|
637
|
+
/**
|
|
638
|
+
* @generated from protobuf enum value: NO_TARGETS = 0;
|
|
639
|
+
*/
|
|
640
|
+
RouteMessageError[RouteMessageError["NO_TARGETS"] = 0] = "NO_TARGETS";
|
|
641
|
+
/**
|
|
642
|
+
* @generated from protobuf enum value: DUPLICATE = 1;
|
|
643
|
+
*/
|
|
644
|
+
RouteMessageError[RouteMessageError["DUPLICATE"] = 1] = "DUPLICATE";
|
|
645
|
+
/**
|
|
646
|
+
* TODO: can this be removed? If DhtNode is already stopped the server side requests
|
|
647
|
+
* should not be processed
|
|
648
|
+
*
|
|
649
|
+
* @generated from protobuf enum value: STOPPED = 2;
|
|
650
|
+
*/
|
|
651
|
+
RouteMessageError[RouteMessageError["STOPPED"] = 2] = "STOPPED";
|
|
652
|
+
})(RouteMessageError || (RouteMessageError = {}));
|
|
653
|
+
/**
|
|
654
|
+
* @generated from protobuf enum dht.HandshakeError
|
|
655
|
+
*/
|
|
656
|
+
var HandshakeError;
|
|
657
|
+
(function (HandshakeError) {
|
|
658
|
+
/**
|
|
659
|
+
* @generated from protobuf enum value: DUPLICATE_CONNECTION = 0;
|
|
660
|
+
*/
|
|
661
|
+
HandshakeError[HandshakeError["DUPLICATE_CONNECTION"] = 0] = "DUPLICATE_CONNECTION";
|
|
662
|
+
/**
|
|
663
|
+
* @generated from protobuf enum value: INVALID_TARGET_PEER_DESCRIPTOR = 1;
|
|
664
|
+
*/
|
|
665
|
+
HandshakeError[HandshakeError["INVALID_TARGET_PEER_DESCRIPTOR"] = 1] = "INVALID_TARGET_PEER_DESCRIPTOR";
|
|
666
|
+
/**
|
|
667
|
+
* @generated from protobuf enum value: UNSUPPORTED_PROTOCOL_VERSION = 2;
|
|
668
|
+
*/
|
|
669
|
+
HandshakeError[HandshakeError["UNSUPPORTED_PROTOCOL_VERSION"] = 2] = "UNSUPPORTED_PROTOCOL_VERSION";
|
|
670
|
+
})(HandshakeError || (HandshakeError = {}));
|
|
671
|
+
/**
|
|
672
|
+
* @generated from protobuf enum dht.DisconnectMode
|
|
673
|
+
*/
|
|
674
|
+
var DisconnectMode;
|
|
675
|
+
(function (DisconnectMode) {
|
|
676
|
+
/**
|
|
677
|
+
* @generated from protobuf enum value: NORMAL = 0;
|
|
678
|
+
*/
|
|
679
|
+
DisconnectMode[DisconnectMode["NORMAL"] = 0] = "NORMAL";
|
|
680
|
+
/**
|
|
681
|
+
* @generated from protobuf enum value: LEAVING = 1;
|
|
682
|
+
*/
|
|
683
|
+
DisconnectMode[DisconnectMode["LEAVING"] = 1] = "LEAVING";
|
|
684
|
+
})(DisconnectMode || (DisconnectMode = {}));
|
|
685
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
686
|
+
class StoreDataRequest$Type extends runtime.MessageType {
|
|
687
|
+
constructor() {
|
|
688
|
+
super("dht.StoreDataRequest", [
|
|
689
|
+
{ no: 1, name: "key", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
690
|
+
{ no: 2, name: "data", kind: "message", T: () => Any },
|
|
691
|
+
{ no: 3, name: "creator", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
692
|
+
{ no: 4, name: "createdAt", kind: "message", T: () => Timestamp },
|
|
693
|
+
{ no: 5, name: "ttl", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }
|
|
694
|
+
]);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* @generated MessageType for protobuf message dht.StoreDataRequest
|
|
699
|
+
*/
|
|
700
|
+
const StoreDataRequest = new StoreDataRequest$Type();
|
|
701
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
702
|
+
class StoreDataResponse$Type extends runtime.MessageType {
|
|
703
|
+
constructor() {
|
|
704
|
+
super("dht.StoreDataResponse", []);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* @generated MessageType for protobuf message dht.StoreDataResponse
|
|
709
|
+
*/
|
|
710
|
+
const StoreDataResponse = new StoreDataResponse$Type();
|
|
711
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
712
|
+
class ExternalStoreDataRequest$Type extends runtime.MessageType {
|
|
713
|
+
constructor() {
|
|
714
|
+
super("dht.ExternalStoreDataRequest", [
|
|
715
|
+
{ no: 1, name: "key", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
716
|
+
{ no: 2, name: "data", kind: "message", T: () => Any }
|
|
717
|
+
]);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* @generated MessageType for protobuf message dht.ExternalStoreDataRequest
|
|
722
|
+
*/
|
|
723
|
+
const ExternalStoreDataRequest = new ExternalStoreDataRequest$Type();
|
|
724
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
725
|
+
class ExternalStoreDataResponse$Type extends runtime.MessageType {
|
|
726
|
+
constructor() {
|
|
727
|
+
super("dht.ExternalStoreDataResponse", [
|
|
728
|
+
{ no: 1, name: "storers", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => PeerDescriptor }
|
|
729
|
+
]);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* @generated MessageType for protobuf message dht.ExternalStoreDataResponse
|
|
734
|
+
*/
|
|
735
|
+
const ExternalStoreDataResponse = new ExternalStoreDataResponse$Type();
|
|
736
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
737
|
+
class ReplicateDataRequest$Type extends runtime.MessageType {
|
|
738
|
+
constructor() {
|
|
739
|
+
super("dht.ReplicateDataRequest", [
|
|
740
|
+
{ no: 1, name: "entry", kind: "message", T: () => DataEntry }
|
|
741
|
+
]);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* @generated MessageType for protobuf message dht.ReplicateDataRequest
|
|
746
|
+
*/
|
|
747
|
+
const ReplicateDataRequest = new ReplicateDataRequest$Type();
|
|
748
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
749
|
+
class DataEntry$Type extends runtime.MessageType {
|
|
750
|
+
constructor() {
|
|
751
|
+
super("dht.DataEntry", [
|
|
752
|
+
{ no: 1, name: "key", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
753
|
+
{ no: 2, name: "data", kind: "message", T: () => Any },
|
|
754
|
+
{ no: 3, name: "creator", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
755
|
+
{ no: 4, name: "createdAt", kind: "message", T: () => Timestamp },
|
|
756
|
+
{ no: 5, name: "storedAt", kind: "message", T: () => Timestamp },
|
|
757
|
+
{ no: 6, name: "ttl", kind: "scalar", T: 13 /*ScalarType.UINT32*/ },
|
|
758
|
+
{ no: 7, name: "stale", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
|
759
|
+
{ no: 8, name: "deleted", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
|
|
760
|
+
]);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* @generated MessageType for protobuf message dht.DataEntry
|
|
765
|
+
*/
|
|
766
|
+
const DataEntry = new DataEntry$Type();
|
|
767
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
768
|
+
class ClosestPeersRequest$Type extends runtime.MessageType {
|
|
769
|
+
constructor() {
|
|
770
|
+
super("dht.ClosestPeersRequest", [
|
|
771
|
+
{ no: 1, name: "nodeId", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
772
|
+
{ no: 2, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
773
|
+
]);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* @generated MessageType for protobuf message dht.ClosestPeersRequest
|
|
778
|
+
*/
|
|
779
|
+
const ClosestPeersRequest = new ClosestPeersRequest$Type();
|
|
780
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
781
|
+
class ClosestPeersResponse$Type extends runtime.MessageType {
|
|
782
|
+
constructor() {
|
|
783
|
+
super("dht.ClosestPeersResponse", [
|
|
784
|
+
{ no: 1, name: "peers", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => PeerDescriptor },
|
|
785
|
+
{ no: 2, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
786
|
+
]);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* @generated MessageType for protobuf message dht.ClosestPeersResponse
|
|
791
|
+
*/
|
|
792
|
+
const ClosestPeersResponse = new ClosestPeersResponse$Type();
|
|
793
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
794
|
+
class ClosestRingPeersRequest$Type extends runtime.MessageType {
|
|
795
|
+
constructor() {
|
|
796
|
+
super("dht.ClosestRingPeersRequest", [
|
|
797
|
+
{ no: 1, name: "ringId", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
798
|
+
{ no: 2, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
799
|
+
]);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* @generated MessageType for protobuf message dht.ClosestRingPeersRequest
|
|
804
|
+
*/
|
|
805
|
+
const ClosestRingPeersRequest = new ClosestRingPeersRequest$Type();
|
|
806
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
807
|
+
class ClosestRingPeersResponse$Type extends runtime.MessageType {
|
|
808
|
+
constructor() {
|
|
809
|
+
super("dht.ClosestRingPeersResponse", [
|
|
810
|
+
{ no: 1, name: "leftPeers", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => PeerDescriptor },
|
|
811
|
+
{ no: 2, name: "rightPeers", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => PeerDescriptor },
|
|
812
|
+
{ no: 3, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
813
|
+
]);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* @generated MessageType for protobuf message dht.ClosestRingPeersResponse
|
|
818
|
+
*/
|
|
819
|
+
const ClosestRingPeersResponse = new ClosestRingPeersResponse$Type();
|
|
820
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
821
|
+
class RecursiveOperationRequest$Type extends runtime.MessageType {
|
|
822
|
+
constructor() {
|
|
823
|
+
super("dht.RecursiveOperationRequest", [
|
|
824
|
+
{ no: 1, name: "sessionId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
825
|
+
{ no: 2, name: "operation", kind: "enum", T: () => ["dht.RecursiveOperation", RecursiveOperation] }
|
|
826
|
+
]);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* @generated MessageType for protobuf message dht.RecursiveOperationRequest
|
|
831
|
+
*/
|
|
832
|
+
const RecursiveOperationRequest = new RecursiveOperationRequest$Type();
|
|
833
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
834
|
+
class RecursiveOperationResponse$Type extends runtime.MessageType {
|
|
835
|
+
constructor() {
|
|
836
|
+
super("dht.RecursiveOperationResponse", [
|
|
837
|
+
{ no: 1, name: "closestConnectedNodes", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => PeerDescriptor },
|
|
838
|
+
{ no: 2, name: "dataEntries", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => DataEntry },
|
|
839
|
+
{ no: 3, name: "noCloserNodesFound", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
|
840
|
+
{ no: 4, name: "routingPath", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => PeerDescriptor }
|
|
841
|
+
]);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* @generated MessageType for protobuf message dht.RecursiveOperationResponse
|
|
846
|
+
*/
|
|
847
|
+
const RecursiveOperationResponse = new RecursiveOperationResponse$Type();
|
|
848
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
849
|
+
class PingRequest$Type extends runtime.MessageType {
|
|
850
|
+
constructor() {
|
|
851
|
+
super("dht.PingRequest", [
|
|
852
|
+
{ no: 1, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
853
|
+
]);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* @generated MessageType for protobuf message dht.PingRequest
|
|
858
|
+
*/
|
|
859
|
+
const PingRequest = new PingRequest$Type();
|
|
860
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
861
|
+
class PingResponse$Type extends runtime.MessageType {
|
|
862
|
+
constructor() {
|
|
863
|
+
super("dht.PingResponse", [
|
|
864
|
+
{ no: 1, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
865
|
+
]);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* @generated MessageType for protobuf message dht.PingResponse
|
|
870
|
+
*/
|
|
871
|
+
const PingResponse = new PingResponse$Type();
|
|
872
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
873
|
+
class LeaveNotice$Type extends runtime.MessageType {
|
|
874
|
+
constructor() {
|
|
875
|
+
super("dht.LeaveNotice", []);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* @generated MessageType for protobuf message dht.LeaveNotice
|
|
880
|
+
*/
|
|
881
|
+
const LeaveNotice = new LeaveNotice$Type();
|
|
882
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
883
|
+
class PeerDescriptor$Type extends runtime.MessageType {
|
|
884
|
+
constructor() {
|
|
885
|
+
super("dht.PeerDescriptor", [
|
|
886
|
+
{ no: 1, name: "nodeId", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
887
|
+
{ no: 2, name: "type", kind: "enum", T: () => ["dht.NodeType", NodeType] },
|
|
888
|
+
{ no: 3, name: "udp", kind: "message", T: () => ConnectivityMethod },
|
|
889
|
+
{ no: 4, name: "tcp", kind: "message", T: () => ConnectivityMethod },
|
|
890
|
+
{ no: 5, name: "websocket", kind: "message", T: () => ConnectivityMethod },
|
|
891
|
+
{ no: 6, name: "region", kind: "scalar", opt: true, T: 13 /*ScalarType.UINT32*/ },
|
|
892
|
+
{ no: 7, name: "ipAddress", kind: "scalar", opt: true, T: 13 /*ScalarType.UINT32*/ },
|
|
893
|
+
{ no: 8, name: "publicKey", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ },
|
|
894
|
+
{ no: 9, name: "signature", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ }
|
|
895
|
+
]);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* @generated MessageType for protobuf message dht.PeerDescriptor
|
|
900
|
+
*/
|
|
901
|
+
const PeerDescriptor = new PeerDescriptor$Type();
|
|
902
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
903
|
+
class ConnectivityMethod$Type extends runtime.MessageType {
|
|
904
|
+
constructor() {
|
|
905
|
+
super("dht.ConnectivityMethod", [
|
|
906
|
+
{ no: 1, name: "port", kind: "scalar", T: 13 /*ScalarType.UINT32*/ },
|
|
907
|
+
{ no: 2, name: "host", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
908
|
+
{ no: 3, name: "tls", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
|
|
909
|
+
]);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* @generated MessageType for protobuf message dht.ConnectivityMethod
|
|
914
|
+
*/
|
|
915
|
+
const ConnectivityMethod = new ConnectivityMethod$Type();
|
|
916
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
917
|
+
class RouteMessageWrapper$Type extends runtime.MessageType {
|
|
918
|
+
constructor() {
|
|
919
|
+
super("dht.RouteMessageWrapper", [
|
|
920
|
+
{ no: 1, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
921
|
+
{ no: 2, name: "sourcePeer", kind: "message", T: () => PeerDescriptor },
|
|
922
|
+
{ no: 3, name: "target", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
923
|
+
{ no: 4, name: "message", kind: "message", T: () => Message },
|
|
924
|
+
{ no: 5, name: "reachableThrough", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => PeerDescriptor },
|
|
925
|
+
{ no: 6, name: "routingPath", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => PeerDescriptor },
|
|
926
|
+
{ no: 7, name: "parallelRootNodeIds", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }
|
|
927
|
+
]);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
/**
|
|
931
|
+
* @generated MessageType for protobuf message dht.RouteMessageWrapper
|
|
932
|
+
*/
|
|
933
|
+
const RouteMessageWrapper = new RouteMessageWrapper$Type();
|
|
934
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
935
|
+
class RouteMessageAck$Type extends runtime.MessageType {
|
|
936
|
+
constructor() {
|
|
937
|
+
super("dht.RouteMessageAck", [
|
|
938
|
+
{ no: 1, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
939
|
+
{ no: 2, name: "error", kind: "enum", opt: true, T: () => ["dht.RouteMessageError", RouteMessageError] }
|
|
940
|
+
]);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* @generated MessageType for protobuf message dht.RouteMessageAck
|
|
945
|
+
*/
|
|
946
|
+
const RouteMessageAck = new RouteMessageAck$Type();
|
|
947
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
948
|
+
class ConnectivityRequest$Type extends runtime.MessageType {
|
|
949
|
+
constructor() {
|
|
950
|
+
super("dht.ConnectivityRequest", [
|
|
951
|
+
{ no: 1, name: "port", kind: "scalar", T: 13 /*ScalarType.UINT32*/ },
|
|
952
|
+
{ no: 2, name: "tls", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
|
953
|
+
{ no: 3, name: "host", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
|
|
954
|
+
{ no: 4, name: "allowSelfSignedCertificate", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
|
|
955
|
+
]);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* @generated MessageType for protobuf message dht.ConnectivityRequest
|
|
960
|
+
*/
|
|
961
|
+
const ConnectivityRequest = new ConnectivityRequest$Type();
|
|
962
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
963
|
+
class ConnectivityResponse$Type extends runtime.MessageType {
|
|
964
|
+
constructor() {
|
|
965
|
+
super("dht.ConnectivityResponse", [
|
|
966
|
+
{ no: 1, name: "host", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
967
|
+
{ no: 2, name: "natType", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
968
|
+
{ no: 3, name: "websocket", kind: "message", T: () => ConnectivityMethod },
|
|
969
|
+
{ no: 4, name: "ipAddress", kind: "scalar", T: 13 /*ScalarType.UINT32*/ },
|
|
970
|
+
{ no: 5, name: "protocolVersion", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
971
|
+
{ no: 6, name: "latitude", kind: "scalar", opt: true, T: 1 /*ScalarType.DOUBLE*/ },
|
|
972
|
+
{ no: 7, name: "longitude", kind: "scalar", opt: true, T: 1 /*ScalarType.DOUBLE*/ }
|
|
973
|
+
]);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* @generated MessageType for protobuf message dht.ConnectivityResponse
|
|
978
|
+
*/
|
|
979
|
+
const ConnectivityResponse = new ConnectivityResponse$Type();
|
|
980
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
981
|
+
class HandshakeRequest$Type extends runtime.MessageType {
|
|
982
|
+
constructor() {
|
|
983
|
+
super("dht.HandshakeRequest", [
|
|
984
|
+
{ no: 1, name: "sourcePeerDescriptor", kind: "message", T: () => PeerDescriptor },
|
|
985
|
+
{ no: 2, name: "targetPeerDescriptor", kind: "message", T: () => PeerDescriptor },
|
|
986
|
+
{ no: 3, name: "protocolVersion", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
987
|
+
{ no: 4, name: "applicationVersion", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
988
|
+
]);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* @generated MessageType for protobuf message dht.HandshakeRequest
|
|
993
|
+
*/
|
|
994
|
+
const HandshakeRequest = new HandshakeRequest$Type();
|
|
995
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
996
|
+
class HandshakeResponse$Type extends runtime.MessageType {
|
|
997
|
+
constructor() {
|
|
998
|
+
super("dht.HandshakeResponse", [
|
|
999
|
+
{ no: 1, name: "sourcePeerDescriptor", kind: "message", T: () => PeerDescriptor },
|
|
1000
|
+
{ no: 2, name: "error", kind: "enum", opt: true, T: () => ["dht.HandshakeError", HandshakeError] },
|
|
1001
|
+
{ no: 3, name: "protocolVersion", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1002
|
+
{ no: 4, name: "applicationVersion", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
1003
|
+
]);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* @generated MessageType for protobuf message dht.HandshakeResponse
|
|
1008
|
+
*/
|
|
1009
|
+
const HandshakeResponse = new HandshakeResponse$Type();
|
|
1010
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1011
|
+
class Message$Type extends runtime.MessageType {
|
|
1012
|
+
constructor() {
|
|
1013
|
+
super("dht.Message", [
|
|
1014
|
+
{ no: 1, name: "messageId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1015
|
+
{ no: 2, name: "sourceDescriptor", kind: "message", T: () => PeerDescriptor },
|
|
1016
|
+
{ no: 3, name: "targetDescriptor", kind: "message", T: () => PeerDescriptor },
|
|
1017
|
+
{ no: 4, name: "serviceId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1018
|
+
{ no: 5, name: "rpcMessage", kind: "message", oneof: "body", T: () => RpcMessage },
|
|
1019
|
+
{ no: 6, name: "connectivityRequest", kind: "message", oneof: "body", T: () => ConnectivityRequest },
|
|
1020
|
+
{ no: 7, name: "connectivityResponse", kind: "message", oneof: "body", T: () => ConnectivityResponse },
|
|
1021
|
+
{ no: 8, name: "handshakeRequest", kind: "message", oneof: "body", T: () => HandshakeRequest },
|
|
1022
|
+
{ no: 9, name: "handshakeResponse", kind: "message", oneof: "body", T: () => HandshakeResponse },
|
|
1023
|
+
{ no: 10, name: "recursiveOperationRequest", kind: "message", oneof: "body", T: () => RecursiveOperationRequest }
|
|
1024
|
+
]);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
/**
|
|
1028
|
+
* @generated MessageType for protobuf message dht.Message
|
|
1029
|
+
*/
|
|
1030
|
+
const Message = new Message$Type();
|
|
1031
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1032
|
+
class WebsocketConnectionRequest$Type extends runtime.MessageType {
|
|
1033
|
+
constructor() {
|
|
1034
|
+
super("dht.WebsocketConnectionRequest", []);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* @generated MessageType for protobuf message dht.WebsocketConnectionRequest
|
|
1039
|
+
*/
|
|
1040
|
+
const WebsocketConnectionRequest = new WebsocketConnectionRequest$Type();
|
|
1041
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1042
|
+
class WebrtcConnectionRequest$Type extends runtime.MessageType {
|
|
1043
|
+
constructor() {
|
|
1044
|
+
super("dht.WebrtcConnectionRequest", []);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* @generated MessageType for protobuf message dht.WebrtcConnectionRequest
|
|
1049
|
+
*/
|
|
1050
|
+
const WebrtcConnectionRequest = new WebrtcConnectionRequest$Type();
|
|
1051
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1052
|
+
class RtcOffer$Type extends runtime.MessageType {
|
|
1053
|
+
constructor() {
|
|
1054
|
+
super("dht.RtcOffer", [
|
|
1055
|
+
{ no: 1, name: "description", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1056
|
+
{ no: 2, name: "connectionId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
1057
|
+
]);
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* @generated MessageType for protobuf message dht.RtcOffer
|
|
1062
|
+
*/
|
|
1063
|
+
const RtcOffer = new RtcOffer$Type();
|
|
1064
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1065
|
+
class RtcAnswer$Type extends runtime.MessageType {
|
|
1066
|
+
constructor() {
|
|
1067
|
+
super("dht.RtcAnswer", [
|
|
1068
|
+
{ no: 1, name: "description", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1069
|
+
{ no: 2, name: "connectionId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
1070
|
+
]);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* @generated MessageType for protobuf message dht.RtcAnswer
|
|
1075
|
+
*/
|
|
1076
|
+
const RtcAnswer = new RtcAnswer$Type();
|
|
1077
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1078
|
+
class IceCandidate$Type extends runtime.MessageType {
|
|
1079
|
+
constructor() {
|
|
1080
|
+
super("dht.IceCandidate", [
|
|
1081
|
+
{ no: 1, name: "candidate", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1082
|
+
{ no: 2, name: "mid", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1083
|
+
{ no: 3, name: "connectionId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
1084
|
+
]);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
/**
|
|
1088
|
+
* @generated MessageType for protobuf message dht.IceCandidate
|
|
1089
|
+
*/
|
|
1090
|
+
const IceCandidate = new IceCandidate$Type();
|
|
1091
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1092
|
+
class LockRequest$Type extends runtime.MessageType {
|
|
1093
|
+
constructor() {
|
|
1094
|
+
super("dht.LockRequest", [
|
|
1095
|
+
{ no: 1, name: "lockId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
1096
|
+
]);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* @generated MessageType for protobuf message dht.LockRequest
|
|
1101
|
+
*/
|
|
1102
|
+
const LockRequest = new LockRequest$Type();
|
|
1103
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1104
|
+
class UnlockRequest$Type extends runtime.MessageType {
|
|
1105
|
+
constructor() {
|
|
1106
|
+
super("dht.UnlockRequest", [
|
|
1107
|
+
{ no: 1, name: "lockId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
1108
|
+
]);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* @generated MessageType for protobuf message dht.UnlockRequest
|
|
1113
|
+
*/
|
|
1114
|
+
const UnlockRequest = new UnlockRequest$Type();
|
|
1115
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1116
|
+
class LockResponse$Type extends runtime.MessageType {
|
|
1117
|
+
constructor() {
|
|
1118
|
+
super("dht.LockResponse", [
|
|
1119
|
+
{ no: 1, name: "accepted", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
|
|
1120
|
+
]);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* @generated MessageType for protobuf message dht.LockResponse
|
|
1125
|
+
*/
|
|
1126
|
+
const LockResponse = new LockResponse$Type();
|
|
1127
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1128
|
+
class DisconnectNotice$Type extends runtime.MessageType {
|
|
1129
|
+
constructor() {
|
|
1130
|
+
super("dht.DisconnectNotice", [
|
|
1131
|
+
{ no: 1, name: "disconnectMode", kind: "enum", T: () => ["dht.DisconnectMode", DisconnectMode] }
|
|
1132
|
+
]);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* @generated MessageType for protobuf message dht.DisconnectNotice
|
|
1137
|
+
*/
|
|
1138
|
+
const DisconnectNotice = new DisconnectNotice$Type();
|
|
1139
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1140
|
+
class SetPrivateRequest$Type extends runtime.MessageType {
|
|
1141
|
+
constructor() {
|
|
1142
|
+
super("dht.SetPrivateRequest", [
|
|
1143
|
+
{ no: 1, name: "isPrivate", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
|
|
1144
|
+
]);
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* @generated MessageType for protobuf message dht.SetPrivateRequest
|
|
1149
|
+
*/
|
|
1150
|
+
const SetPrivateRequest = new SetPrivateRequest$Type();
|
|
1151
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1152
|
+
class ExternalFetchDataRequest$Type extends runtime.MessageType {
|
|
1153
|
+
constructor() {
|
|
1154
|
+
super("dht.ExternalFetchDataRequest", [
|
|
1155
|
+
{ no: 1, name: "key", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }
|
|
1156
|
+
]);
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
/**
|
|
1160
|
+
* @generated MessageType for protobuf message dht.ExternalFetchDataRequest
|
|
1161
|
+
*/
|
|
1162
|
+
const ExternalFetchDataRequest = new ExternalFetchDataRequest$Type();
|
|
1163
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1164
|
+
class ExternalFetchDataResponse$Type extends runtime.MessageType {
|
|
1165
|
+
constructor() {
|
|
1166
|
+
super("dht.ExternalFetchDataResponse", [
|
|
1167
|
+
{ no: 1, name: "entries", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => DataEntry }
|
|
1168
|
+
]);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* @generated MessageType for protobuf message dht.ExternalFetchDataResponse
|
|
1173
|
+
*/
|
|
1174
|
+
const ExternalFetchDataResponse = new ExternalFetchDataResponse$Type();
|
|
1175
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1176
|
+
class ExternalFindClosestNodesRequest$Type extends runtime.MessageType {
|
|
1177
|
+
constructor() {
|
|
1178
|
+
super("dht.ExternalFindClosestNodesRequest", [
|
|
1179
|
+
{ no: 1, name: "nodeId", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }
|
|
1180
|
+
]);
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* @generated MessageType for protobuf message dht.ExternalFindClosestNodesRequest
|
|
1185
|
+
*/
|
|
1186
|
+
const ExternalFindClosestNodesRequest = new ExternalFindClosestNodesRequest$Type();
|
|
1187
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1188
|
+
class ExternalFindClosestNodesResponse$Type extends runtime.MessageType {
|
|
1189
|
+
constructor() {
|
|
1190
|
+
super("dht.ExternalFindClosestNodesResponse", [
|
|
1191
|
+
{ no: 1, name: "closestNodes", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => PeerDescriptor }
|
|
1192
|
+
]);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
/**
|
|
1196
|
+
* @generated MessageType for protobuf message dht.ExternalFindClosestNodesResponse
|
|
1197
|
+
*/
|
|
1198
|
+
const ExternalFindClosestNodesResponse = new ExternalFindClosestNodesResponse$Type();
|
|
1199
|
+
/**
|
|
1200
|
+
* @generated ServiceType for protobuf service dht.DhtNodeRpc
|
|
1201
|
+
*/
|
|
1202
|
+
new runtimeRpc.ServiceType("dht.DhtNodeRpc", [
|
|
1203
|
+
{ name: "getClosestPeers", options: {}, I: ClosestPeersRequest, O: ClosestPeersResponse },
|
|
1204
|
+
{ name: "getClosestRingPeers", options: {}, I: ClosestRingPeersRequest, O: ClosestRingPeersResponse },
|
|
1205
|
+
{ name: "ping", options: {}, I: PingRequest, O: PingResponse },
|
|
1206
|
+
{ name: "leaveNotice", options: {}, I: LeaveNotice, O: Empty }
|
|
1207
|
+
]);
|
|
1208
|
+
/**
|
|
1209
|
+
* @generated ServiceType for protobuf service dht.RouterRpc
|
|
1210
|
+
*/
|
|
1211
|
+
new runtimeRpc.ServiceType("dht.RouterRpc", [
|
|
1212
|
+
{ name: "routeMessage", options: {}, I: RouteMessageWrapper, O: RouteMessageAck },
|
|
1213
|
+
{ name: "forwardMessage", options: {}, I: RouteMessageWrapper, O: RouteMessageAck }
|
|
1214
|
+
]);
|
|
1215
|
+
/**
|
|
1216
|
+
* @generated ServiceType for protobuf service dht.RecursiveOperationRpc
|
|
1217
|
+
*/
|
|
1218
|
+
new runtimeRpc.ServiceType("dht.RecursiveOperationRpc", [
|
|
1219
|
+
{ name: "routeRequest", options: {}, I: RouteMessageWrapper, O: RouteMessageAck }
|
|
1220
|
+
]);
|
|
1221
|
+
/**
|
|
1222
|
+
* @generated ServiceType for protobuf service dht.StoreRpc
|
|
1223
|
+
*/
|
|
1224
|
+
new runtimeRpc.ServiceType("dht.StoreRpc", [
|
|
1225
|
+
{ name: "storeData", options: {}, I: StoreDataRequest, O: StoreDataResponse },
|
|
1226
|
+
{ name: "replicateData", options: {}, I: ReplicateDataRequest, O: Empty }
|
|
1227
|
+
]);
|
|
1228
|
+
/**
|
|
1229
|
+
* @generated ServiceType for protobuf service dht.RecursiveOperationSessionRpc
|
|
1230
|
+
*/
|
|
1231
|
+
new runtimeRpc.ServiceType("dht.RecursiveOperationSessionRpc", [
|
|
1232
|
+
{ name: "sendResponse", options: {}, I: RecursiveOperationResponse, O: Empty }
|
|
1233
|
+
]);
|
|
1234
|
+
/**
|
|
1235
|
+
* @generated ServiceType for protobuf service dht.WebsocketClientConnectorRpc
|
|
1236
|
+
*/
|
|
1237
|
+
new runtimeRpc.ServiceType("dht.WebsocketClientConnectorRpc", [
|
|
1238
|
+
{ name: "requestConnection", options: {}, I: WebsocketConnectionRequest, O: Empty }
|
|
1239
|
+
]);
|
|
1240
|
+
/**
|
|
1241
|
+
* @generated ServiceType for protobuf service dht.WebrtcConnectorRpc
|
|
1242
|
+
*/
|
|
1243
|
+
new runtimeRpc.ServiceType("dht.WebrtcConnectorRpc", [
|
|
1244
|
+
{ name: "requestConnection", options: {}, I: WebrtcConnectionRequest, O: Empty },
|
|
1245
|
+
{ name: "rtcOffer", options: {}, I: RtcOffer, O: Empty },
|
|
1246
|
+
{ name: "rtcAnswer", options: {}, I: RtcAnswer, O: Empty },
|
|
1247
|
+
{ name: "iceCandidate", options: {}, I: IceCandidate, O: Empty }
|
|
1248
|
+
]);
|
|
1249
|
+
/**
|
|
1250
|
+
* @generated ServiceType for protobuf service dht.ConnectionLockRpc
|
|
1251
|
+
*/
|
|
1252
|
+
new runtimeRpc.ServiceType("dht.ConnectionLockRpc", [
|
|
1253
|
+
{ name: "lockRequest", options: {}, I: LockRequest, O: LockResponse },
|
|
1254
|
+
{ name: "unlockRequest", options: {}, I: UnlockRequest, O: Empty },
|
|
1255
|
+
{ name: "gracefulDisconnect", options: {}, I: DisconnectNotice, O: Empty },
|
|
1256
|
+
{ name: "setPrivate", options: {}, I: SetPrivateRequest, O: Empty }
|
|
1257
|
+
]);
|
|
1258
|
+
/**
|
|
1259
|
+
* @generated ServiceType for protobuf service dht.ExternalApiRpc
|
|
1260
|
+
*/
|
|
1261
|
+
new runtimeRpc.ServiceType("dht.ExternalApiRpc", [
|
|
1262
|
+
{ name: "externalFetchData", options: {}, I: ExternalFetchDataRequest, O: ExternalFetchDataResponse },
|
|
1263
|
+
{ name: "externalStoreData", options: {}, I: ExternalStoreDataRequest, O: ExternalStoreDataResponse },
|
|
1264
|
+
{ name: "externalFindClosestNodes", options: {}, I: ExternalFindClosestNodesRequest, O: ExternalFindClosestNodesResponse }
|
|
1265
|
+
]);
|
|
1266
|
+
|
|
1267
|
+
// @generated by protobuf-ts 2.11.1 with parameter server_generic,generate_dependencies,long_type_number
|
|
1268
|
+
// @generated from protobuf file "packages/trackerless-network/protos/NetworkRpc.proto" (syntax proto3)
|
|
1269
|
+
// tslint:disable
|
|
1270
|
+
/**
|
|
1271
|
+
* @generated from protobuf enum ContentType
|
|
1272
|
+
*/
|
|
1273
|
+
exports.ContentType = void 0;
|
|
1274
|
+
(function (ContentType) {
|
|
1275
|
+
/**
|
|
1276
|
+
* @generated from protobuf enum value: JSON = 0;
|
|
1277
|
+
*/
|
|
1278
|
+
ContentType[ContentType["JSON"] = 0] = "JSON";
|
|
1279
|
+
/**
|
|
1280
|
+
* @generated from protobuf enum value: BINARY = 1;
|
|
1281
|
+
*/
|
|
1282
|
+
ContentType[ContentType["BINARY"] = 1] = "BINARY";
|
|
1283
|
+
})(exports.ContentType || (exports.ContentType = {}));
|
|
1284
|
+
/**
|
|
1285
|
+
* @generated from protobuf enum EncryptionType
|
|
1286
|
+
*/
|
|
1287
|
+
exports.EncryptionType = void 0;
|
|
1288
|
+
(function (EncryptionType) {
|
|
1289
|
+
/**
|
|
1290
|
+
* @generated from protobuf enum value: NONE = 0;
|
|
1291
|
+
*/
|
|
1292
|
+
EncryptionType[EncryptionType["NONE"] = 0] = "NONE";
|
|
1293
|
+
/**
|
|
1294
|
+
* @generated from protobuf enum value: AES = 1;
|
|
1295
|
+
*/
|
|
1296
|
+
EncryptionType[EncryptionType["AES"] = 1] = "AES";
|
|
1297
|
+
})(exports.EncryptionType || (exports.EncryptionType = {}));
|
|
1298
|
+
/**
|
|
1299
|
+
* @generated from protobuf enum AsymmetricEncryptionType
|
|
1300
|
+
*/
|
|
1301
|
+
exports.AsymmetricEncryptionType = void 0;
|
|
1302
|
+
(function (AsymmetricEncryptionType) {
|
|
1303
|
+
/**
|
|
1304
|
+
* default
|
|
1305
|
+
*
|
|
1306
|
+
* @generated from protobuf enum value: RSA = 0;
|
|
1307
|
+
*/
|
|
1308
|
+
AsymmetricEncryptionType[AsymmetricEncryptionType["RSA"] = 0] = "RSA";
|
|
1309
|
+
/**
|
|
1310
|
+
* @generated from protobuf enum value: ML_KEM = 1;
|
|
1311
|
+
*/
|
|
1312
|
+
AsymmetricEncryptionType[AsymmetricEncryptionType["ML_KEM"] = 1] = "ML_KEM";
|
|
1313
|
+
})(exports.AsymmetricEncryptionType || (exports.AsymmetricEncryptionType = {}));
|
|
1314
|
+
/**
|
|
1315
|
+
* @generated from protobuf enum SignatureType
|
|
1316
|
+
*/
|
|
1317
|
+
exports.SignatureType = void 0;
|
|
1318
|
+
(function (SignatureType) {
|
|
1319
|
+
/**
|
|
1320
|
+
* @generated from protobuf enum value: ECDSA_SECP256K1_LEGACY = 0;
|
|
1321
|
+
*/
|
|
1322
|
+
SignatureType[SignatureType["ECDSA_SECP256K1_LEGACY"] = 0] = "ECDSA_SECP256K1_LEGACY";
|
|
1323
|
+
/**
|
|
1324
|
+
* @generated from protobuf enum value: ECDSA_SECP256K1_EVM = 1;
|
|
1325
|
+
*/
|
|
1326
|
+
SignatureType[SignatureType["ECDSA_SECP256K1_EVM"] = 1] = "ECDSA_SECP256K1_EVM";
|
|
1327
|
+
/**
|
|
1328
|
+
* @generated from protobuf enum value: ERC_1271 = 2;
|
|
1329
|
+
*/
|
|
1330
|
+
SignatureType[SignatureType["ERC_1271"] = 2] = "ERC_1271";
|
|
1331
|
+
/**
|
|
1332
|
+
* @generated from protobuf enum value: ML_DSA_87 = 3;
|
|
1333
|
+
*/
|
|
1334
|
+
SignatureType[SignatureType["ML_DSA_87"] = 3] = "ML_DSA_87";
|
|
1335
|
+
/**
|
|
1336
|
+
* @generated from protobuf enum value: ECDSA_SECP256R1 = 4;
|
|
1337
|
+
*/
|
|
1338
|
+
SignatureType[SignatureType["ECDSA_SECP256R1"] = 4] = "ECDSA_SECP256R1";
|
|
1339
|
+
})(exports.SignatureType || (exports.SignatureType = {}));
|
|
1340
|
+
/**
|
|
1341
|
+
* @generated from protobuf enum ProxyDirection
|
|
1342
|
+
*/
|
|
1343
|
+
exports.ProxyDirection = void 0;
|
|
1344
|
+
(function (ProxyDirection) {
|
|
1345
|
+
/**
|
|
1346
|
+
* @generated from protobuf enum value: PUBLISH = 0;
|
|
1347
|
+
*/
|
|
1348
|
+
ProxyDirection[ProxyDirection["PUBLISH"] = 0] = "PUBLISH";
|
|
1349
|
+
/**
|
|
1350
|
+
* @generated from protobuf enum value: SUBSCRIBE = 1;
|
|
1351
|
+
*/
|
|
1352
|
+
ProxyDirection[ProxyDirection["SUBSCRIBE"] = 1] = "SUBSCRIBE";
|
|
1353
|
+
})(exports.ProxyDirection || (exports.ProxyDirection = {}));
|
|
1354
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1355
|
+
class MessageID$Type extends runtime.MessageType {
|
|
1356
|
+
constructor() {
|
|
1357
|
+
super("MessageID", [
|
|
1358
|
+
{ no: 1, name: "streamId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1359
|
+
{ no: 2, name: "streamPartition", kind: "scalar", T: 5 /*ScalarType.INT32*/ },
|
|
1360
|
+
{ no: 3, name: "timestamp", kind: "scalar", T: 3 /*ScalarType.INT64*/, L: 2 /*LongType.NUMBER*/ },
|
|
1361
|
+
{ no: 4, name: "sequenceNumber", kind: "scalar", T: 5 /*ScalarType.INT32*/ },
|
|
1362
|
+
{ no: 5, name: "publisherId", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
1363
|
+
{ no: 6, name: "messageChainId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
1364
|
+
]);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* @generated MessageType for protobuf message MessageID
|
|
1369
|
+
*/
|
|
1370
|
+
const MessageID = new MessageID$Type();
|
|
1371
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1372
|
+
class MessageRef$Type extends runtime.MessageType {
|
|
1373
|
+
constructor() {
|
|
1374
|
+
super("MessageRef", [
|
|
1375
|
+
{ no: 1, name: "timestamp", kind: "scalar", T: 3 /*ScalarType.INT64*/, L: 2 /*LongType.NUMBER*/ },
|
|
1376
|
+
{ no: 2, name: "sequenceNumber", kind: "scalar", T: 5 /*ScalarType.INT32*/ }
|
|
1377
|
+
]);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
/**
|
|
1381
|
+
* @generated MessageType for protobuf message MessageRef
|
|
1382
|
+
*/
|
|
1383
|
+
const MessageRef = new MessageRef$Type();
|
|
1384
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1385
|
+
class StreamMessage$Type extends runtime.MessageType {
|
|
1386
|
+
constructor() {
|
|
1387
|
+
super("StreamMessage", [
|
|
1388
|
+
{ no: 1, name: "messageId", kind: "message", T: () => MessageID },
|
|
1389
|
+
{ no: 2, name: "previousMessageRef", kind: "message", T: () => MessageRef },
|
|
1390
|
+
{ no: 3, name: "signature", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
1391
|
+
{ no: 4, name: "signatureType", kind: "enum", T: () => ["SignatureType", exports.SignatureType] },
|
|
1392
|
+
{ no: 5, name: "contentMessage", kind: "message", oneof: "body", T: () => ContentMessage },
|
|
1393
|
+
{ no: 6, name: "groupKeyRequest", kind: "message", oneof: "body", T: () => GroupKeyRequest },
|
|
1394
|
+
{ no: 7, name: "groupKeyResponse", kind: "message", oneof: "body", T: () => GroupKeyResponse }
|
|
1395
|
+
]);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
/**
|
|
1399
|
+
* @generated MessageType for protobuf message StreamMessage
|
|
1400
|
+
*/
|
|
1401
|
+
const StreamMessage = new StreamMessage$Type();
|
|
1402
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1403
|
+
class ContentMessage$Type extends runtime.MessageType {
|
|
1404
|
+
constructor() {
|
|
1405
|
+
super("ContentMessage", [
|
|
1406
|
+
{ no: 1, name: "content", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
1407
|
+
{ no: 2, name: "contentType", kind: "enum", T: () => ["ContentType", exports.ContentType] },
|
|
1408
|
+
{ no: 3, name: "encryptionType", kind: "enum", T: () => ["EncryptionType", exports.EncryptionType] },
|
|
1409
|
+
{ no: 4, name: "groupKeyId", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ },
|
|
1410
|
+
{ no: 5, name: "newGroupKey", kind: "message", T: () => EncryptedGroupKey }
|
|
1411
|
+
]);
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
/**
|
|
1415
|
+
* @generated MessageType for protobuf message ContentMessage
|
|
1416
|
+
*/
|
|
1417
|
+
const ContentMessage = new ContentMessage$Type();
|
|
1418
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1419
|
+
class GroupKeyRequest$Type extends runtime.MessageType {
|
|
1420
|
+
constructor() {
|
|
1421
|
+
super("GroupKeyRequest", [
|
|
1422
|
+
{ no: 1, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1423
|
+
{ no: 2, name: "recipientId", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
1424
|
+
{ no: 3, name: "publicKey", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
1425
|
+
{ no: 4, name: "groupKeyIds", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ },
|
|
1426
|
+
{ no: 5, name: "encryptionType", kind: "enum", T: () => ["AsymmetricEncryptionType", exports.AsymmetricEncryptionType] }
|
|
1427
|
+
]);
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
/**
|
|
1431
|
+
* @generated MessageType for protobuf message GroupKeyRequest
|
|
1432
|
+
*/
|
|
1433
|
+
const GroupKeyRequest = new GroupKeyRequest$Type();
|
|
1434
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1435
|
+
class GroupKeyResponse$Type extends runtime.MessageType {
|
|
1436
|
+
constructor() {
|
|
1437
|
+
super("GroupKeyResponse", [
|
|
1438
|
+
{ no: 1, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1439
|
+
{ no: 2, name: "recipientId", kind: "scalar", T: 12 /*ScalarType.BYTES*/ },
|
|
1440
|
+
{ no: 3, name: "groupKeys", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => EncryptedGroupKey },
|
|
1441
|
+
{ no: 4, name: "encryptionType", kind: "enum", T: () => ["AsymmetricEncryptionType", exports.AsymmetricEncryptionType] }
|
|
1442
|
+
]);
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
/**
|
|
1446
|
+
* @generated MessageType for protobuf message GroupKeyResponse
|
|
1447
|
+
*/
|
|
1448
|
+
const GroupKeyResponse = new GroupKeyResponse$Type();
|
|
1449
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1450
|
+
class EncryptedGroupKey$Type extends runtime.MessageType {
|
|
1451
|
+
constructor() {
|
|
1452
|
+
super("EncryptedGroupKey", [
|
|
1453
|
+
{ no: 1, name: "id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1454
|
+
{ no: 2, name: "data", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }
|
|
1455
|
+
]);
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* @generated MessageType for protobuf message EncryptedGroupKey
|
|
1460
|
+
*/
|
|
1461
|
+
const EncryptedGroupKey = new EncryptedGroupKey$Type();
|
|
1462
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1463
|
+
class StreamPartHandshakeRequest$Type extends runtime.MessageType {
|
|
1464
|
+
constructor() {
|
|
1465
|
+
super("StreamPartHandshakeRequest", [
|
|
1466
|
+
{ no: 1, name: "streamPartId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1467
|
+
{ no: 2, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1468
|
+
{ no: 3, name: "concurrentHandshakeNodeId", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ },
|
|
1469
|
+
{ no: 4, name: "neighborNodeIds", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 12 /*ScalarType.BYTES*/ },
|
|
1470
|
+
{ no: 5, name: "interleaveNodeId", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ }
|
|
1471
|
+
]);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
/**
|
|
1475
|
+
* @generated MessageType for protobuf message StreamPartHandshakeRequest
|
|
1476
|
+
*/
|
|
1477
|
+
const StreamPartHandshakeRequest = new StreamPartHandshakeRequest$Type();
|
|
1478
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1479
|
+
class StreamPartHandshakeResponse$Type extends runtime.MessageType {
|
|
1480
|
+
constructor() {
|
|
1481
|
+
super("StreamPartHandshakeResponse", [
|
|
1482
|
+
{ no: 1, name: "accepted", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
|
1483
|
+
{ no: 2, name: "requestId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1484
|
+
{ no: 3, name: "interleaveTargetDescriptor", kind: "message", T: () => PeerDescriptor }
|
|
1485
|
+
]);
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
/**
|
|
1489
|
+
* @generated MessageType for protobuf message StreamPartHandshakeResponse
|
|
1490
|
+
*/
|
|
1491
|
+
const StreamPartHandshakeResponse = new StreamPartHandshakeResponse$Type();
|
|
1492
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1493
|
+
class InterleaveRequest$Type extends runtime.MessageType {
|
|
1494
|
+
constructor() {
|
|
1495
|
+
super("InterleaveRequest", [
|
|
1496
|
+
{ no: 1, name: "interleaveTargetDescriptor", kind: "message", T: () => PeerDescriptor }
|
|
1497
|
+
]);
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
/**
|
|
1501
|
+
* @generated MessageType for protobuf message InterleaveRequest
|
|
1502
|
+
*/
|
|
1503
|
+
const InterleaveRequest = new InterleaveRequest$Type();
|
|
1504
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1505
|
+
class InterleaveResponse$Type extends runtime.MessageType {
|
|
1506
|
+
constructor() {
|
|
1507
|
+
super("InterleaveResponse", [
|
|
1508
|
+
{ no: 1, name: "accepted", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
|
|
1509
|
+
]);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
/**
|
|
1513
|
+
* @generated MessageType for protobuf message InterleaveResponse
|
|
1514
|
+
*/
|
|
1515
|
+
const InterleaveResponse = new InterleaveResponse$Type();
|
|
1516
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1517
|
+
class LeaveStreamPartNotice$Type extends runtime.MessageType {
|
|
1518
|
+
constructor() {
|
|
1519
|
+
super("LeaveStreamPartNotice", [
|
|
1520
|
+
{ no: 1, name: "streamPartId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1521
|
+
{ no: 2, name: "isEntryPoint", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
|
|
1522
|
+
]);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
/**
|
|
1526
|
+
* @generated MessageType for protobuf message LeaveStreamPartNotice
|
|
1527
|
+
*/
|
|
1528
|
+
const LeaveStreamPartNotice = new LeaveStreamPartNotice$Type();
|
|
1529
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1530
|
+
class NeighborUpdate$Type extends runtime.MessageType {
|
|
1531
|
+
constructor() {
|
|
1532
|
+
super("NeighborUpdate", [
|
|
1533
|
+
{ no: 1, name: "streamPartId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1534
|
+
{ no: 2, name: "removeMe", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
|
1535
|
+
{ no: 3, name: "neighborDescriptors", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => PeerDescriptor }
|
|
1536
|
+
]);
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
/**
|
|
1540
|
+
* @generated MessageType for protobuf message NeighborUpdate
|
|
1541
|
+
*/
|
|
1542
|
+
const NeighborUpdate = new NeighborUpdate$Type();
|
|
1543
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1544
|
+
class ProxyConnectionRequest$Type extends runtime.MessageType {
|
|
1545
|
+
constructor() {
|
|
1546
|
+
super("ProxyConnectionRequest", [
|
|
1547
|
+
{ no: 1, name: "direction", kind: "enum", opt: true, T: () => ["ProxyDirection", exports.ProxyDirection] },
|
|
1548
|
+
{ no: 2, name: "userId", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }
|
|
1549
|
+
]);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
/**
|
|
1553
|
+
* @generated MessageType for protobuf message ProxyConnectionRequest
|
|
1554
|
+
*/
|
|
1555
|
+
const ProxyConnectionRequest = new ProxyConnectionRequest$Type();
|
|
1556
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1557
|
+
class ProxyConnectionResponse$Type extends runtime.MessageType {
|
|
1558
|
+
constructor() {
|
|
1559
|
+
super("ProxyConnectionResponse", [
|
|
1560
|
+
{ no: 1, name: "accepted", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
|
|
1561
|
+
]);
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
/**
|
|
1565
|
+
* @generated MessageType for protobuf message ProxyConnectionResponse
|
|
1566
|
+
*/
|
|
1567
|
+
const ProxyConnectionResponse = new ProxyConnectionResponse$Type();
|
|
1568
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1569
|
+
class TemporaryConnectionRequest$Type extends runtime.MessageType {
|
|
1570
|
+
constructor() {
|
|
1571
|
+
super("TemporaryConnectionRequest", []);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
/**
|
|
1575
|
+
* @generated MessageType for protobuf message TemporaryConnectionRequest
|
|
1576
|
+
*/
|
|
1577
|
+
const TemporaryConnectionRequest = new TemporaryConnectionRequest$Type();
|
|
1578
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1579
|
+
class TemporaryConnectionResponse$Type extends runtime.MessageType {
|
|
1580
|
+
constructor() {
|
|
1581
|
+
super("TemporaryConnectionResponse", [
|
|
1582
|
+
{ no: 1, name: "accepted", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
|
|
1583
|
+
]);
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
/**
|
|
1587
|
+
* @generated MessageType for protobuf message TemporaryConnectionResponse
|
|
1588
|
+
*/
|
|
1589
|
+
const TemporaryConnectionResponse = new TemporaryConnectionResponse$Type();
|
|
1590
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1591
|
+
class CloseTemporaryConnection$Type extends runtime.MessageType {
|
|
1592
|
+
constructor() {
|
|
1593
|
+
super("CloseTemporaryConnection", []);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
/**
|
|
1597
|
+
* @generated MessageType for protobuf message CloseTemporaryConnection
|
|
1598
|
+
*/
|
|
1599
|
+
const CloseTemporaryConnection = new CloseTemporaryConnection$Type();
|
|
1600
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1601
|
+
class StreamPartitionInfo$Type extends runtime.MessageType {
|
|
1602
|
+
constructor() {
|
|
1603
|
+
super("StreamPartitionInfo", [
|
|
1604
|
+
{ no: 1, name: "id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1605
|
+
{ no: 2, name: "controlLayerNeighbors", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => PeerDescriptor },
|
|
1606
|
+
{ no: 3, name: "deprecatedContentDeliveryLayerNeighbors", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => PeerDescriptor },
|
|
1607
|
+
{ no: 4, name: "contentDeliveryLayerNeighbors", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => ContentDeliveryLayerNeighborInfo }
|
|
1608
|
+
]);
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
/**
|
|
1612
|
+
* @generated MessageType for protobuf message StreamPartitionInfo
|
|
1613
|
+
*/
|
|
1614
|
+
const StreamPartitionInfo = new StreamPartitionInfo$Type();
|
|
1615
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1616
|
+
class ContentDeliveryLayerNeighborInfo$Type extends runtime.MessageType {
|
|
1617
|
+
constructor() {
|
|
1618
|
+
super("ContentDeliveryLayerNeighborInfo", [
|
|
1619
|
+
{ no: 1, name: "peerDescriptor", kind: "message", T: () => PeerDescriptor },
|
|
1620
|
+
{ no: 2, name: "rtt", kind: "scalar", opt: true, T: 5 /*ScalarType.INT32*/ }
|
|
1621
|
+
]);
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
/**
|
|
1625
|
+
* @generated MessageType for protobuf message ContentDeliveryLayerNeighborInfo
|
|
1626
|
+
*/
|
|
1627
|
+
const ContentDeliveryLayerNeighborInfo = new ContentDeliveryLayerNeighborInfo$Type();
|
|
1628
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1629
|
+
class ControlLayerInfo$Type extends runtime.MessageType {
|
|
1630
|
+
constructor() {
|
|
1631
|
+
super("ControlLayerInfo", [
|
|
1632
|
+
{ no: 1, name: "neighbors", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => PeerDescriptor },
|
|
1633
|
+
{ no: 2, name: "connections", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => PeerDescriptor }
|
|
1634
|
+
]);
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
/**
|
|
1638
|
+
* @generated MessageType for protobuf message ControlLayerInfo
|
|
1639
|
+
*/
|
|
1640
|
+
const ControlLayerInfo = new ControlLayerInfo$Type();
|
|
1641
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1642
|
+
class NodeInfoRequest$Type extends runtime.MessageType {
|
|
1643
|
+
constructor() {
|
|
1644
|
+
super("NodeInfoRequest", []);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
/**
|
|
1648
|
+
* @generated MessageType for protobuf message NodeInfoRequest
|
|
1649
|
+
*/
|
|
1650
|
+
const NodeInfoRequest = new NodeInfoRequest$Type();
|
|
1651
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1652
|
+
class NodeInfoResponse$Type extends runtime.MessageType {
|
|
1653
|
+
constructor() {
|
|
1654
|
+
super("NodeInfoResponse", [
|
|
1655
|
+
{ no: 1, name: "peerDescriptor", kind: "message", T: () => PeerDescriptor },
|
|
1656
|
+
{ no: 2, name: "streamPartitions", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => StreamPartitionInfo },
|
|
1657
|
+
{ no: 3, name: "controlLayer", kind: "message", T: () => ControlLayerInfo },
|
|
1658
|
+
{ no: 4, name: "applicationVersion", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
1659
|
+
]);
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
/**
|
|
1663
|
+
* @generated MessageType for protobuf message NodeInfoResponse
|
|
1664
|
+
*/
|
|
1665
|
+
const NodeInfoResponse = new NodeInfoResponse$Type();
|
|
1666
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1667
|
+
class PauseNeighborRequest$Type extends runtime.MessageType {
|
|
1668
|
+
constructor() {
|
|
1669
|
+
super("PauseNeighborRequest", [
|
|
1670
|
+
{ no: 1, name: "messageChainId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
1671
|
+
]);
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
/**
|
|
1675
|
+
* @generated MessageType for protobuf message PauseNeighborRequest
|
|
1676
|
+
*/
|
|
1677
|
+
const PauseNeighborRequest = new PauseNeighborRequest$Type();
|
|
1678
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1679
|
+
class ResumeNeighborRequest$Type extends runtime.MessageType {
|
|
1680
|
+
constructor() {
|
|
1681
|
+
super("ResumeNeighborRequest", [
|
|
1682
|
+
{ no: 1, name: "messageChainId", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
1683
|
+
{ no: 2, name: "fromTimestamp", kind: "scalar", T: 3 /*ScalarType.INT64*/, L: 2 /*LongType.NUMBER*/ }
|
|
1684
|
+
]);
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
/**
|
|
1688
|
+
* @generated MessageType for protobuf message ResumeNeighborRequest
|
|
1689
|
+
*/
|
|
1690
|
+
const ResumeNeighborRequest = new ResumeNeighborRequest$Type();
|
|
1691
|
+
/**
|
|
1692
|
+
* @generated ServiceType for protobuf service ContentDeliveryRpc
|
|
1693
|
+
*/
|
|
1694
|
+
const ContentDeliveryRpc = new runtimeRpc.ServiceType("ContentDeliveryRpc", [
|
|
1695
|
+
{ name: "sendStreamMessage", options: {}, I: StreamMessage, O: Empty },
|
|
1696
|
+
{ name: "leaveStreamPartNotice", options: {}, I: LeaveStreamPartNotice, O: Empty }
|
|
1697
|
+
]);
|
|
1698
|
+
/**
|
|
1699
|
+
* @generated ServiceType for protobuf service ProxyConnectionRpc
|
|
1700
|
+
*/
|
|
1701
|
+
const ProxyConnectionRpc = new runtimeRpc.ServiceType("ProxyConnectionRpc", [
|
|
1702
|
+
{ name: "requestConnection", options: {}, I: ProxyConnectionRequest, O: ProxyConnectionResponse }
|
|
1703
|
+
]);
|
|
1704
|
+
/**
|
|
1705
|
+
* @generated ServiceType for protobuf service HandshakeRpc
|
|
1706
|
+
*/
|
|
1707
|
+
const HandshakeRpc = new runtimeRpc.ServiceType("HandshakeRpc", [
|
|
1708
|
+
{ name: "handshake", options: {}, I: StreamPartHandshakeRequest, O: StreamPartHandshakeResponse },
|
|
1709
|
+
{ name: "interleaveRequest", options: {}, I: InterleaveRequest, O: InterleaveResponse }
|
|
1710
|
+
]);
|
|
1711
|
+
/**
|
|
1712
|
+
* @generated ServiceType for protobuf service NeighborUpdateRpc
|
|
1713
|
+
*/
|
|
1714
|
+
const NeighborUpdateRpc = new runtimeRpc.ServiceType("NeighborUpdateRpc", [
|
|
1715
|
+
{ name: "neighborUpdate", options: {}, I: NeighborUpdate, O: NeighborUpdate }
|
|
1716
|
+
]);
|
|
1717
|
+
/**
|
|
1718
|
+
* @generated ServiceType for protobuf service TemporaryConnectionRpc
|
|
1719
|
+
*/
|
|
1720
|
+
const TemporaryConnectionRpc = new runtimeRpc.ServiceType("TemporaryConnectionRpc", [
|
|
1721
|
+
{ name: "openConnection", options: {}, I: TemporaryConnectionRequest, O: TemporaryConnectionResponse },
|
|
1722
|
+
{ name: "closeConnection", options: {}, I: CloseTemporaryConnection, O: Empty }
|
|
1723
|
+
]);
|
|
1724
|
+
/**
|
|
1725
|
+
* @generated ServiceType for protobuf service NodeInfoRpc
|
|
1726
|
+
*/
|
|
1727
|
+
const NodeInfoRpc = new runtimeRpc.ServiceType("NodeInfoRpc", [
|
|
1728
|
+
{ name: "getInfo", options: {}, I: NodeInfoRequest, O: NodeInfoResponse }
|
|
1729
|
+
]);
|
|
1730
|
+
/**
|
|
1731
|
+
* @generated ServiceType for protobuf service PlumtreeRpc
|
|
1732
|
+
*/
|
|
1733
|
+
const PlumtreeRpc = new runtimeRpc.ServiceType("PlumtreeRpc", [
|
|
1734
|
+
{ name: "pauseNeighbor", options: {}, I: PauseNeighborRequest, O: Empty },
|
|
1735
|
+
{ name: "resumeNeighbor", options: {}, I: ResumeNeighborRequest, O: Empty },
|
|
1736
|
+
{ name: "sendMetadata", options: {}, I: MessageID, O: Empty }
|
|
1737
|
+
]);
|
|
1738
|
+
|
|
1739
|
+
// @generated by protobuf-ts 2.11.1 with parameter server_generic,generate_dependencies,long_type_number
|
|
1740
|
+
// @generated from protobuf file "packages/trackerless-network/protos/NetworkRpc.proto" (syntax proto3)
|
|
1741
|
+
// tslint:disable
|
|
1742
|
+
/**
|
|
1743
|
+
* @generated from protobuf service ContentDeliveryRpc
|
|
1744
|
+
*/
|
|
1745
|
+
class ContentDeliveryRpcClient {
|
|
1746
|
+
_transport;
|
|
1747
|
+
typeName = ContentDeliveryRpc.typeName;
|
|
1748
|
+
methods = ContentDeliveryRpc.methods;
|
|
1749
|
+
options = ContentDeliveryRpc.options;
|
|
1750
|
+
constructor(_transport) {
|
|
1751
|
+
this._transport = _transport;
|
|
1752
|
+
}
|
|
1753
|
+
/**
|
|
1754
|
+
* @generated from protobuf rpc: sendStreamMessage
|
|
1755
|
+
*/
|
|
1756
|
+
sendStreamMessage(input, options) {
|
|
1757
|
+
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
|
1758
|
+
return runtimeRpc.stackIntercept("unary", this._transport, method, opt, input);
|
|
1759
|
+
}
|
|
1760
|
+
/**
|
|
1761
|
+
* @generated from protobuf rpc: leaveStreamPartNotice
|
|
1762
|
+
*/
|
|
1763
|
+
leaveStreamPartNotice(input, options) {
|
|
1764
|
+
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
|
1765
|
+
return runtimeRpc.stackIntercept("unary", this._transport, method, opt, input);
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
/**
|
|
1769
|
+
* @generated from protobuf service ProxyConnectionRpc
|
|
1770
|
+
*/
|
|
1771
|
+
class ProxyConnectionRpcClient {
|
|
1772
|
+
_transport;
|
|
1773
|
+
typeName = ProxyConnectionRpc.typeName;
|
|
1774
|
+
methods = ProxyConnectionRpc.methods;
|
|
1775
|
+
options = ProxyConnectionRpc.options;
|
|
1776
|
+
constructor(_transport) {
|
|
1777
|
+
this._transport = _transport;
|
|
1778
|
+
}
|
|
1779
|
+
/**
|
|
1780
|
+
* @generated from protobuf rpc: requestConnection
|
|
1781
|
+
*/
|
|
1782
|
+
requestConnection(input, options) {
|
|
1783
|
+
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
|
1784
|
+
return runtimeRpc.stackIntercept("unary", this._transport, method, opt, input);
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
/**
|
|
1788
|
+
* @generated from protobuf service HandshakeRpc
|
|
1789
|
+
*/
|
|
1790
|
+
class HandshakeRpcClient {
|
|
1791
|
+
_transport;
|
|
1792
|
+
typeName = HandshakeRpc.typeName;
|
|
1793
|
+
methods = HandshakeRpc.methods;
|
|
1794
|
+
options = HandshakeRpc.options;
|
|
1795
|
+
constructor(_transport) {
|
|
1796
|
+
this._transport = _transport;
|
|
1797
|
+
}
|
|
1798
|
+
/**
|
|
1799
|
+
* @generated from protobuf rpc: handshake
|
|
1800
|
+
*/
|
|
1801
|
+
handshake(input, options) {
|
|
1802
|
+
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
|
1803
|
+
return runtimeRpc.stackIntercept("unary", this._transport, method, opt, input);
|
|
1804
|
+
}
|
|
1805
|
+
/**
|
|
1806
|
+
* @generated from protobuf rpc: interleaveRequest
|
|
1807
|
+
*/
|
|
1808
|
+
interleaveRequest(input, options) {
|
|
1809
|
+
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
|
1810
|
+
return runtimeRpc.stackIntercept("unary", this._transport, method, opt, input);
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
/**
|
|
1814
|
+
* @generated from protobuf service NeighborUpdateRpc
|
|
1815
|
+
*/
|
|
1816
|
+
class NeighborUpdateRpcClient {
|
|
1817
|
+
_transport;
|
|
1818
|
+
typeName = NeighborUpdateRpc.typeName;
|
|
1819
|
+
methods = NeighborUpdateRpc.methods;
|
|
1820
|
+
options = NeighborUpdateRpc.options;
|
|
1821
|
+
constructor(_transport) {
|
|
1822
|
+
this._transport = _transport;
|
|
1823
|
+
}
|
|
1824
|
+
/**
|
|
1825
|
+
* @generated from protobuf rpc: neighborUpdate
|
|
1826
|
+
*/
|
|
1827
|
+
neighborUpdate(input, options) {
|
|
1828
|
+
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
|
1829
|
+
return runtimeRpc.stackIntercept("unary", this._transport, method, opt, input);
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
/**
|
|
1833
|
+
* @generated from protobuf service TemporaryConnectionRpc
|
|
1834
|
+
*/
|
|
1835
|
+
class TemporaryConnectionRpcClient {
|
|
1836
|
+
_transport;
|
|
1837
|
+
typeName = TemporaryConnectionRpc.typeName;
|
|
1838
|
+
methods = TemporaryConnectionRpc.methods;
|
|
1839
|
+
options = TemporaryConnectionRpc.options;
|
|
1840
|
+
constructor(_transport) {
|
|
1841
|
+
this._transport = _transport;
|
|
1842
|
+
}
|
|
1843
|
+
/**
|
|
1844
|
+
* @generated from protobuf rpc: openConnection
|
|
1845
|
+
*/
|
|
1846
|
+
openConnection(input, options) {
|
|
1847
|
+
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
|
1848
|
+
return runtimeRpc.stackIntercept("unary", this._transport, method, opt, input);
|
|
1849
|
+
}
|
|
1850
|
+
/**
|
|
1851
|
+
* @generated from protobuf rpc: closeConnection
|
|
1852
|
+
*/
|
|
1853
|
+
closeConnection(input, options) {
|
|
1854
|
+
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
|
1855
|
+
return runtimeRpc.stackIntercept("unary", this._transport, method, opt, input);
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
/**
|
|
1859
|
+
* @generated from protobuf service NodeInfoRpc
|
|
1860
|
+
*/
|
|
1861
|
+
class NodeInfoRpcClient {
|
|
1862
|
+
_transport;
|
|
1863
|
+
typeName = NodeInfoRpc.typeName;
|
|
1864
|
+
methods = NodeInfoRpc.methods;
|
|
1865
|
+
options = NodeInfoRpc.options;
|
|
1866
|
+
constructor(_transport) {
|
|
1867
|
+
this._transport = _transport;
|
|
1868
|
+
}
|
|
1869
|
+
/**
|
|
1870
|
+
* @generated from protobuf rpc: getInfo
|
|
1871
|
+
*/
|
|
1872
|
+
getInfo(input, options) {
|
|
1873
|
+
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
|
1874
|
+
return runtimeRpc.stackIntercept("unary", this._transport, method, opt, input);
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
/**
|
|
1878
|
+
* @generated from protobuf service PlumtreeRpc
|
|
1879
|
+
*/
|
|
1880
|
+
class PlumtreeRpcClient {
|
|
1881
|
+
_transport;
|
|
1882
|
+
typeName = PlumtreeRpc.typeName;
|
|
1883
|
+
methods = PlumtreeRpc.methods;
|
|
1884
|
+
options = PlumtreeRpc.options;
|
|
1885
|
+
constructor(_transport) {
|
|
1886
|
+
this._transport = _transport;
|
|
1887
|
+
}
|
|
1888
|
+
/**
|
|
1889
|
+
* @generated from protobuf rpc: pauseNeighbor
|
|
1890
|
+
*/
|
|
1891
|
+
pauseNeighbor(input, options) {
|
|
1892
|
+
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
|
1893
|
+
return runtimeRpc.stackIntercept("unary", this._transport, method, opt, input);
|
|
1894
|
+
}
|
|
1895
|
+
/**
|
|
1896
|
+
* @generated from protobuf rpc: resumeNeighbor
|
|
1897
|
+
*/
|
|
1898
|
+
resumeNeighbor(input, options) {
|
|
1899
|
+
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
|
1900
|
+
return runtimeRpc.stackIntercept("unary", this._transport, method, opt, input);
|
|
1901
|
+
}
|
|
1902
|
+
/**
|
|
1903
|
+
* @generated from protobuf rpc: sendMetadata
|
|
1904
|
+
*/
|
|
1905
|
+
sendMetadata(input, options) {
|
|
1906
|
+
const method = this.methods[2], opt = this._transport.mergeOptions(options);
|
|
1907
|
+
return runtimeRpc.stackIntercept("unary", this._transport, method, opt, input);
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
const logger$f = new utils.Logger('ContentDeliveryRpcRemote');
|
|
1912
|
+
class ContentDeliveryRpcRemote extends dht.RpcRemote {
|
|
1913
|
+
rtt;
|
|
1914
|
+
async sendStreamMessage(msg, bufferWhileConnecting) {
|
|
1915
|
+
const options = this.formDhtRpcOptions({
|
|
1916
|
+
notification: true,
|
|
1917
|
+
bufferWhileConnecting
|
|
1918
|
+
});
|
|
1919
|
+
this.getClient().sendStreamMessage(msg, options).catch(() => {
|
|
1920
|
+
logger$f.trace('Failed to sendStreamMessage');
|
|
1921
|
+
});
|
|
1922
|
+
}
|
|
1923
|
+
leaveStreamPartNotice(streamPartId, isLocalNodeEntryPoint) {
|
|
1924
|
+
const notification = {
|
|
1925
|
+
streamPartId,
|
|
1926
|
+
isEntryPoint: isLocalNodeEntryPoint
|
|
1927
|
+
};
|
|
1928
|
+
const options = this.formDhtRpcOptions({
|
|
1929
|
+
notification: true
|
|
1930
|
+
});
|
|
1931
|
+
this.getClient().leaveStreamPartNotice(notification, options).catch(() => {
|
|
1932
|
+
logger$f.debug('Failed to send leaveStreamPartNotice');
|
|
1933
|
+
});
|
|
1934
|
+
}
|
|
1935
|
+
setRtt(rtt) {
|
|
1936
|
+
this.rtt = rtt;
|
|
1937
|
+
}
|
|
1938
|
+
getRtt() {
|
|
1939
|
+
return this.rtt;
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
const logger$e = new utils.Logger('HandshakeRpcLocal');
|
|
1944
|
+
class HandshakeRpcLocal {
|
|
1945
|
+
options;
|
|
1946
|
+
constructor(options) {
|
|
1947
|
+
this.options = options;
|
|
1948
|
+
}
|
|
1949
|
+
async handshake(request, context) {
|
|
1950
|
+
return this.handleRequest(request, context);
|
|
1951
|
+
}
|
|
1952
|
+
handleRequest(request, context) {
|
|
1953
|
+
const senderDescriptor = context.incomingSourceDescriptor;
|
|
1954
|
+
const getInterleaveNodeIds = () => (request.interleaveNodeId !== undefined) ? [dht.toDhtAddress(request.interleaveNodeId)] : [];
|
|
1955
|
+
const senderNodeId = dht.toNodeId(senderDescriptor);
|
|
1956
|
+
if (this.options.ongoingInterleaves.has(senderNodeId)) {
|
|
1957
|
+
return this.rejectHandshake(request);
|
|
1958
|
+
}
|
|
1959
|
+
else if (this.options.neighbors.has(senderNodeId)
|
|
1960
|
+
|| this.options.ongoingHandshakes.has(senderNodeId)) {
|
|
1961
|
+
return this.acceptHandshake(request, senderDescriptor);
|
|
1962
|
+
}
|
|
1963
|
+
else if (this.options.neighbors.size() + this.options.ongoingHandshakes.size < this.options.maxNeighborCount) {
|
|
1964
|
+
return this.acceptHandshake(request, senderDescriptor);
|
|
1965
|
+
}
|
|
1966
|
+
else if (this.options.neighbors.size(getInterleaveNodeIds()) - this.options.ongoingInterleaves.size >= 2
|
|
1967
|
+
&& this.options.neighbors.size() <= this.options.maxNeighborCount) {
|
|
1968
|
+
// Do not accept the handshakes requests if the target neighbor count can potentially drop below 2
|
|
1969
|
+
// due to interleaving. This ensures that a stable number of connections is kept during high churn.
|
|
1970
|
+
return this.acceptHandshakeWithInterleaving(request, senderDescriptor);
|
|
1971
|
+
}
|
|
1972
|
+
else {
|
|
1973
|
+
return this.rejectHandshake(request);
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
acceptHandshake(request, requester) {
|
|
1977
|
+
const res = {
|
|
1978
|
+
requestId: request.requestId,
|
|
1979
|
+
accepted: true
|
|
1980
|
+
};
|
|
1981
|
+
this.options.neighbors.add(this.options.createContentDeliveryRpcRemote(requester));
|
|
1982
|
+
return res;
|
|
1983
|
+
}
|
|
1984
|
+
// eslint-disable-next-line class-methods-use-this
|
|
1985
|
+
rejectHandshake(request) {
|
|
1986
|
+
const res = {
|
|
1987
|
+
requestId: request.requestId,
|
|
1988
|
+
accepted: false
|
|
1989
|
+
};
|
|
1990
|
+
return res;
|
|
1991
|
+
}
|
|
1992
|
+
acceptHandshakeWithInterleaving(request, requester) {
|
|
1993
|
+
const exclude = [];
|
|
1994
|
+
request.neighborNodeIds.forEach((id) => exclude.push(dht.toDhtAddress(id)));
|
|
1995
|
+
this.options.ongoingInterleaves.forEach((id) => exclude.push(id));
|
|
1996
|
+
exclude.push(dht.toNodeId(requester));
|
|
1997
|
+
if (request.interleaveNodeId !== undefined) {
|
|
1998
|
+
exclude.push(dht.toDhtAddress(request.interleaveNodeId));
|
|
1999
|
+
}
|
|
2000
|
+
const last = this.options.neighbors.getLast(exclude);
|
|
2001
|
+
const lastPeerDescriptor = last ? last.getPeerDescriptor() : undefined;
|
|
2002
|
+
if (last) {
|
|
2003
|
+
const nodeId = dht.toNodeId(last.getPeerDescriptor());
|
|
2004
|
+
const remote = this.options.createRpcRemote(last.getPeerDescriptor());
|
|
2005
|
+
this.options.ongoingInterleaves.add(nodeId);
|
|
2006
|
+
// Run this with then catch instead of setImmediate to avoid changes in state
|
|
2007
|
+
// eslint-disable-next-line promise/catch-or-return
|
|
2008
|
+
remote.interleaveRequest(requester).then((response) => {
|
|
2009
|
+
// If response is accepted, remove the last node from the target neighbors
|
|
2010
|
+
// and unlock the connection
|
|
2011
|
+
// If response is not accepted, keep the last node as a neighbor
|
|
2012
|
+
if (response.accepted) {
|
|
2013
|
+
this.options.neighbors.remove(dht.toNodeId(lastPeerDescriptor));
|
|
2014
|
+
}
|
|
2015
|
+
}).catch(() => {
|
|
2016
|
+
// no-op: InterleaveRequest cannot reject
|
|
2017
|
+
}).finally(() => {
|
|
2018
|
+
this.options.ongoingInterleaves.delete(nodeId);
|
|
2019
|
+
});
|
|
2020
|
+
}
|
|
2021
|
+
this.options.neighbors.add(this.options.createContentDeliveryRpcRemote(requester));
|
|
2022
|
+
return {
|
|
2023
|
+
requestId: request.requestId,
|
|
2024
|
+
accepted: true,
|
|
2025
|
+
interleaveTargetDescriptor: lastPeerDescriptor
|
|
2026
|
+
};
|
|
2027
|
+
}
|
|
2028
|
+
async interleaveRequest(message, context) {
|
|
2029
|
+
const senderPeerDescriptor = context.incomingSourceDescriptor;
|
|
2030
|
+
const remoteNodeId = dht.toNodeId(senderPeerDescriptor);
|
|
2031
|
+
try {
|
|
2032
|
+
await this.options.handshakeWithInterleaving(message.interleaveTargetDescriptor, remoteNodeId);
|
|
2033
|
+
this.options.neighbors.remove(remoteNodeId);
|
|
2034
|
+
return { accepted: true };
|
|
2035
|
+
}
|
|
2036
|
+
catch (err) {
|
|
2037
|
+
logger$e.debug(`interleaveRequest to ${dht.toNodeId(message.interleaveTargetDescriptor)} failed`, { err });
|
|
2038
|
+
return { accepted: false };
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
const logger$d = new utils.Logger('HandshakeRpcRemote');
|
|
2044
|
+
const INTERLEAVE_REQUEST_TIMEOUT = 10000;
|
|
2045
|
+
class HandshakeRpcRemote extends dht.RpcRemote {
|
|
2046
|
+
async handshake(streamPartId, neighborNodeIds, concurrentHandshakeNodeId, interleaveNodeId) {
|
|
2047
|
+
const request = {
|
|
2048
|
+
streamPartId,
|
|
2049
|
+
requestId: uuid.v4(),
|
|
2050
|
+
neighborNodeIds: neighborNodeIds.map((id) => dht.toDhtAddressRaw(id)),
|
|
2051
|
+
concurrentHandshakeNodeId: (concurrentHandshakeNodeId !== undefined) ? dht.toDhtAddressRaw(concurrentHandshakeNodeId) : undefined,
|
|
2052
|
+
interleaveNodeId: (interleaveNodeId !== undefined) ? dht.toDhtAddressRaw(interleaveNodeId) : undefined
|
|
2053
|
+
};
|
|
2054
|
+
try {
|
|
2055
|
+
const response = await this.getClient().handshake(request, this.formDhtRpcOptions());
|
|
2056
|
+
return {
|
|
2057
|
+
accepted: response.accepted,
|
|
2058
|
+
interleaveTargetDescriptor: response.interleaveTargetDescriptor
|
|
2059
|
+
};
|
|
2060
|
+
}
|
|
2061
|
+
catch (err) {
|
|
2062
|
+
logger$d.debug(`handshake to ${dht.toNodeId(this.getPeerDescriptor())} failed`, { err });
|
|
2063
|
+
return {
|
|
2064
|
+
accepted: false
|
|
2065
|
+
};
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
async interleaveRequest(originatorDescriptor) {
|
|
2069
|
+
const request = {
|
|
2070
|
+
interleaveTargetDescriptor: originatorDescriptor
|
|
2071
|
+
};
|
|
2072
|
+
const options = this.formDhtRpcOptions({
|
|
2073
|
+
connect: false,
|
|
2074
|
+
timeout: INTERLEAVE_REQUEST_TIMEOUT
|
|
2075
|
+
});
|
|
2076
|
+
try {
|
|
2077
|
+
const res = await this.getClient().interleaveRequest(request, options);
|
|
2078
|
+
return {
|
|
2079
|
+
accepted: res.accepted
|
|
2080
|
+
};
|
|
2081
|
+
}
|
|
2082
|
+
catch (err) {
|
|
2083
|
+
logger$d.debug(`interleaveRequest to ${dht.toNodeId(this.getPeerDescriptor())} failed`, { err });
|
|
2084
|
+
return {
|
|
2085
|
+
accepted: false
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
const logger$c = new utils.Logger('Handshaker');
|
|
2092
|
+
const PARALLEL_HANDSHAKE_COUNT = 2;
|
|
2093
|
+
class Handshaker {
|
|
2094
|
+
options;
|
|
2095
|
+
rpcLocal;
|
|
2096
|
+
constructor(options) {
|
|
2097
|
+
this.options = options;
|
|
2098
|
+
this.rpcLocal = new HandshakeRpcLocal({
|
|
2099
|
+
streamPartId: this.options.streamPartId,
|
|
2100
|
+
neighbors: this.options.neighbors,
|
|
2101
|
+
ongoingHandshakes: this.options.ongoingHandshakes,
|
|
2102
|
+
ongoingInterleaves: new Set(),
|
|
2103
|
+
maxNeighborCount: this.options.maxNeighborCount,
|
|
2104
|
+
handshakeWithInterleaving: (target, remoteNodeId) => this.handshakeWithInterleaving(target, remoteNodeId),
|
|
2105
|
+
createRpcRemote: (target) => this.createRpcRemote(target),
|
|
2106
|
+
createContentDeliveryRpcRemote: (target) => this.createContentDeliveryRpcRemote(target)
|
|
2107
|
+
});
|
|
2108
|
+
this.options.rpcCommunicator.registerRpcMethod(InterleaveRequest, InterleaveResponse, 'interleaveRequest', (req, context) => this.rpcLocal.interleaveRequest(req, context), { timeout: INTERLEAVE_REQUEST_TIMEOUT });
|
|
2109
|
+
this.options.rpcCommunicator.registerRpcMethod(StreamPartHandshakeRequest, StreamPartHandshakeResponse, 'handshake', (req, context) => this.rpcLocal.handshake(req, context));
|
|
2110
|
+
}
|
|
2111
|
+
async attemptHandshakesOnContacts(excludedIds) {
|
|
2112
|
+
// TODO use options option or named constant? or why the value 2?
|
|
2113
|
+
if (this.options.neighbors.size() + this.options.ongoingHandshakes.size < this.options.maxNeighborCount - 2) {
|
|
2114
|
+
logger$c.trace(`Attempting parallel handshakes with ${PARALLEL_HANDSHAKE_COUNT} targets`);
|
|
2115
|
+
return this.selectParallelTargetsAndHandshake(excludedIds);
|
|
2116
|
+
}
|
|
2117
|
+
else if (this.options.neighbors.size() + this.options.ongoingHandshakes.size < this.options.maxNeighborCount) {
|
|
2118
|
+
logger$c.trace(`Attempting handshake with new target`);
|
|
2119
|
+
return this.selectNewTargetAndHandshake(excludedIds);
|
|
2120
|
+
}
|
|
2121
|
+
return excludedIds;
|
|
2122
|
+
}
|
|
2123
|
+
async selectParallelTargetsAndHandshake(excludedIds) {
|
|
2124
|
+
const exclude = excludedIds.concat(this.options.neighbors.getIds());
|
|
2125
|
+
const targets = this.selectParallelTargets(exclude);
|
|
2126
|
+
targets.forEach((contact) => this.options.ongoingHandshakes.add(dht.toNodeId(contact.getPeerDescriptor())));
|
|
2127
|
+
return this.doParallelHandshakes(targets, exclude);
|
|
2128
|
+
}
|
|
2129
|
+
selectParallelTargets(excludedIds) {
|
|
2130
|
+
const targets = new Map();
|
|
2131
|
+
const getExcludedIds = () => [...excludedIds, ...Array.from(targets.keys())];
|
|
2132
|
+
// Step 1: If no neighbors, try to find a WebSocket node first
|
|
2133
|
+
if (this.options.neighbors.size() === 0) {
|
|
2134
|
+
const wsNode = this.options.nearbyNodeView.getFirst(getExcludedIds(), true);
|
|
2135
|
+
if (wsNode) {
|
|
2136
|
+
const wsNodeId = dht.toNodeId(wsNode.getPeerDescriptor());
|
|
2137
|
+
targets.set(wsNodeId, wsNode);
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
// Step 2: Add left and right contacts from the ring
|
|
2141
|
+
const left = this.options.leftNodeView.getFirst(getExcludedIds());
|
|
2142
|
+
const right = this.options.rightNodeView.getFirst(getExcludedIds());
|
|
2143
|
+
if (left) {
|
|
2144
|
+
targets.set(dht.toNodeId(left.getPeerDescriptor()), left);
|
|
2145
|
+
}
|
|
2146
|
+
if (right) {
|
|
2147
|
+
targets.set(dht.toNodeId(right.getPeerDescriptor()), right);
|
|
2148
|
+
}
|
|
2149
|
+
// Step 3: Add closest contact based on Kademlia metric if needed
|
|
2150
|
+
if (targets.size < PARALLEL_HANDSHAKE_COUNT) {
|
|
2151
|
+
const closest = this.options.nearbyNodeView.getFirst(getExcludedIds());
|
|
2152
|
+
if (closest) {
|
|
2153
|
+
targets.set(dht.toNodeId(closest.getPeerDescriptor()), closest);
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
// Step 4: Fill remaining slots with random contacts
|
|
2157
|
+
while (targets.size < PARALLEL_HANDSHAKE_COUNT) {
|
|
2158
|
+
const random = this.options.randomNodeView.getRandom(getExcludedIds());
|
|
2159
|
+
if (!random) {
|
|
2160
|
+
break;
|
|
2161
|
+
}
|
|
2162
|
+
targets.set(dht.toNodeId(random.getPeerDescriptor()), random);
|
|
2163
|
+
}
|
|
2164
|
+
return Array.from(targets.values()).map((neighbor) => this.createRpcRemote(neighbor.getPeerDescriptor()));
|
|
2165
|
+
}
|
|
2166
|
+
async doParallelHandshakes(targets, excludedIds) {
|
|
2167
|
+
const results = await Promise.allSettled(Array.from(targets.values()).map(async (target, i) => {
|
|
2168
|
+
const otherNode = i === 0 ? targets[1] : targets[0];
|
|
2169
|
+
// TODO better check (currently this condition is always true)
|
|
2170
|
+
const otherNodeId = otherNode ? dht.toNodeId(otherNode.getPeerDescriptor()) : undefined;
|
|
2171
|
+
return this.handshakeWithTarget(target, otherNodeId);
|
|
2172
|
+
}));
|
|
2173
|
+
results.forEach((res, i) => {
|
|
2174
|
+
if (res.status !== 'fulfilled' || !res.value) {
|
|
2175
|
+
excludedIds.push(dht.toNodeId(targets[i].getPeerDescriptor()));
|
|
2176
|
+
}
|
|
2177
|
+
});
|
|
2178
|
+
return excludedIds;
|
|
2179
|
+
}
|
|
2180
|
+
async selectNewTargetAndHandshake(excludedIds) {
|
|
2181
|
+
const exclude = excludedIds.concat(this.options.neighbors.getIds());
|
|
2182
|
+
const target = this.options.leftNodeView.getFirst(exclude)
|
|
2183
|
+
?? this.options.rightNodeView.getFirst(exclude)
|
|
2184
|
+
?? this.options.nearbyNodeView.getFirst(exclude)
|
|
2185
|
+
?? this.options.randomNodeView.getRandom(exclude);
|
|
2186
|
+
if (target) {
|
|
2187
|
+
const accepted = await this.handshakeWithTarget(this.createRpcRemote(target.getPeerDescriptor()));
|
|
2188
|
+
if (!accepted) {
|
|
2189
|
+
excludedIds.push(dht.toNodeId(target.getPeerDescriptor()));
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
return excludedIds;
|
|
2193
|
+
}
|
|
2194
|
+
async handshakeWithTarget(target, concurrentNodeId) {
|
|
2195
|
+
const targetNodeId = dht.toNodeId(target.getPeerDescriptor());
|
|
2196
|
+
this.options.ongoingHandshakes.add(targetNodeId);
|
|
2197
|
+
const result = await target.handshake(this.options.streamPartId, this.options.neighbors.getIds(), concurrentNodeId);
|
|
2198
|
+
if (result.accepted) {
|
|
2199
|
+
this.options.neighbors.add(this.createContentDeliveryRpcRemote(target.getPeerDescriptor()));
|
|
2200
|
+
}
|
|
2201
|
+
if (result.interleaveTargetDescriptor) {
|
|
2202
|
+
await this.handshakeWithInterleaving(result.interleaveTargetDescriptor, targetNodeId);
|
|
2203
|
+
}
|
|
2204
|
+
this.options.ongoingHandshakes.delete(targetNodeId);
|
|
2205
|
+
return result.accepted;
|
|
2206
|
+
}
|
|
2207
|
+
async handshakeWithInterleaving(target, remoteNodeId) {
|
|
2208
|
+
const remote = this.createRpcRemote(target);
|
|
2209
|
+
const targetNodeId = dht.toNodeId(remote.getPeerDescriptor());
|
|
2210
|
+
this.options.ongoingHandshakes.add(targetNodeId);
|
|
2211
|
+
const result = await remote.handshake(this.options.streamPartId, this.options.neighbors.getIds(), undefined, remoteNodeId);
|
|
2212
|
+
if (result.accepted) {
|
|
2213
|
+
this.options.neighbors.add(this.createContentDeliveryRpcRemote(remote.getPeerDescriptor()));
|
|
2214
|
+
}
|
|
2215
|
+
this.options.ongoingHandshakes.delete(targetNodeId);
|
|
2216
|
+
return result.accepted;
|
|
2217
|
+
}
|
|
2218
|
+
createRpcRemote(targetPeerDescriptor) {
|
|
2219
|
+
return new HandshakeRpcRemote(this.options.localPeerDescriptor, targetPeerDescriptor, this.options.rpcCommunicator, HandshakeRpcClient, this.options.rpcRequestTimeout);
|
|
2220
|
+
}
|
|
2221
|
+
createContentDeliveryRpcRemote(targetPeerDescriptor) {
|
|
2222
|
+
return new ContentDeliveryRpcRemote(this.options.localPeerDescriptor, targetPeerDescriptor, this.options.rpcCommunicator, ContentDeliveryRpcClient, this.options.rpcRequestTimeout);
|
|
2223
|
+
}
|
|
2224
|
+
getOngoingHandshakes() {
|
|
2225
|
+
return this.options.ongoingHandshakes;
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
const INITIAL_WAIT = 100;
|
|
2230
|
+
const INTERVAL = 250;
|
|
2231
|
+
const logger$b = new utils.Logger('NeighborFinder');
|
|
2232
|
+
class NeighborFinder {
|
|
2233
|
+
abortController;
|
|
2234
|
+
options;
|
|
2235
|
+
running = false;
|
|
2236
|
+
constructor(options) {
|
|
2237
|
+
this.options = options;
|
|
2238
|
+
this.abortController = new AbortController();
|
|
2239
|
+
}
|
|
2240
|
+
async findNeighbors(excluded) {
|
|
2241
|
+
if (!this.running) {
|
|
2242
|
+
return;
|
|
2243
|
+
}
|
|
2244
|
+
const newExcludes = await this.options.doFindNeighbors(excluded);
|
|
2245
|
+
const uniqueContactCount = new Set([
|
|
2246
|
+
...this.options.nearbyNodeView.getIds(),
|
|
2247
|
+
...this.options.leftNodeView.getIds(),
|
|
2248
|
+
...this.options.rightNodeView.getIds(),
|
|
2249
|
+
...this.options.randomNodeView.getIds()
|
|
2250
|
+
]).size;
|
|
2251
|
+
if (this.options.neighbors.size() < this.options.minCount && newExcludes.length < uniqueContactCount) {
|
|
2252
|
+
// TODO should we catch possible promise rejection?
|
|
2253
|
+
utils.setAbortableTimeout(() => this.findNeighbors(newExcludes), INTERVAL, this.abortController.signal);
|
|
2254
|
+
}
|
|
2255
|
+
else if (this.options.neighbors.size() === 0 && uniqueContactCount > 0) {
|
|
2256
|
+
logger$b.debug('No neighbors found yet contacts are available, restarting handshaking process');
|
|
2257
|
+
utils.setAbortableTimeout(() => this.findNeighbors([]), INTERVAL, this.abortController.signal);
|
|
2258
|
+
}
|
|
2259
|
+
else {
|
|
2260
|
+
this.running = false;
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
isRunning() {
|
|
2264
|
+
return this.running;
|
|
2265
|
+
}
|
|
2266
|
+
start(excluded = []) {
|
|
2267
|
+
if (this.running) {
|
|
2268
|
+
return;
|
|
2269
|
+
}
|
|
2270
|
+
this.running = true;
|
|
2271
|
+
// TODO should we catch possible promise rejection?
|
|
2272
|
+
utils.setAbortableTimeout(async () => {
|
|
2273
|
+
await Promise.all([
|
|
2274
|
+
this.findNeighbors(excluded),
|
|
2275
|
+
this.findNeighbors(excluded)
|
|
2276
|
+
]);
|
|
2277
|
+
}, INITIAL_WAIT, this.abortController.signal);
|
|
2278
|
+
}
|
|
2279
|
+
stop() {
|
|
2280
|
+
if (!this.running) {
|
|
2281
|
+
return;
|
|
2282
|
+
}
|
|
2283
|
+
this.running = false;
|
|
2284
|
+
this.abortController.abort();
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
class NeighborUpdateRpcLocal {
|
|
2289
|
+
options;
|
|
2290
|
+
constructor(options) {
|
|
2291
|
+
this.options = options;
|
|
2292
|
+
}
|
|
2293
|
+
updateContacts(neighborDescriptors) {
|
|
2294
|
+
const ownNodeId = dht.toNodeId(this.options.localPeerDescriptor);
|
|
2295
|
+
const newPeerDescriptors = neighborDescriptors.filter((peerDescriptor) => {
|
|
2296
|
+
const nodeId = dht.toNodeId(peerDescriptor);
|
|
2297
|
+
return nodeId !== ownNodeId && !this.options.neighbors.getIds().includes(nodeId);
|
|
2298
|
+
});
|
|
2299
|
+
newPeerDescriptors.forEach((peerDescriptor) => this.options.nearbyNodeView.add(new ContentDeliveryRpcRemote(this.options.localPeerDescriptor, peerDescriptor, this.options.rpcCommunicator, ContentDeliveryRpcClient)));
|
|
2300
|
+
}
|
|
2301
|
+
createResponse(removeMe) {
|
|
2302
|
+
return {
|
|
2303
|
+
streamPartId: this.options.streamPartId,
|
|
2304
|
+
neighborDescriptors: this.options.neighbors.getAll().map((neighbor) => neighbor.getPeerDescriptor()),
|
|
2305
|
+
removeMe
|
|
2306
|
+
};
|
|
2307
|
+
}
|
|
2308
|
+
// INeighborUpdateRpc server method
|
|
2309
|
+
async neighborUpdate(message, context) {
|
|
2310
|
+
const senderPeerDescriptor = context.incomingSourceDescriptor;
|
|
2311
|
+
const remoteNodeId = dht.toNodeId(senderPeerDescriptor);
|
|
2312
|
+
this.updateContacts(message.neighborDescriptors);
|
|
2313
|
+
if (!this.options.neighbors.has(remoteNodeId) && !this.options.ongoingHandshakes.has(remoteNodeId)) {
|
|
2314
|
+
return this.createResponse(true);
|
|
2315
|
+
}
|
|
2316
|
+
else {
|
|
2317
|
+
const isOverNeighborCount = this.options.neighbors.size() > this.options.neighborTargetCount
|
|
2318
|
+
// Motivation: We don't know the remote's neighborTargetCount setting here. We only ask to cut connections
|
|
2319
|
+
// if the remote has a "sufficient" number of neighbors, where "sufficient" means our neighborTargetCount
|
|
2320
|
+
// setting.
|
|
2321
|
+
&& message.neighborDescriptors.length > this.options.neighborTargetCount;
|
|
2322
|
+
if (!isOverNeighborCount) {
|
|
2323
|
+
this.options.neighborFinder.start();
|
|
2324
|
+
}
|
|
2325
|
+
else {
|
|
2326
|
+
this.options.neighbors.remove(remoteNodeId);
|
|
2327
|
+
}
|
|
2328
|
+
return this.createResponse(isOverNeighborCount);
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
const logger$a = new utils.Logger('NeighborUpdateRpcRemote');
|
|
2334
|
+
class NeighborUpdateRpcRemote extends dht.RpcRemote {
|
|
2335
|
+
async updateNeighbors(streamPartId, neighbors) {
|
|
2336
|
+
const request = {
|
|
2337
|
+
streamPartId,
|
|
2338
|
+
neighborDescriptors: neighbors,
|
|
2339
|
+
removeMe: false
|
|
2340
|
+
};
|
|
2341
|
+
try {
|
|
2342
|
+
const response = await this.getClient().neighborUpdate(request, this.formDhtRpcOptions());
|
|
2343
|
+
return {
|
|
2344
|
+
peerDescriptors: response.neighborDescriptors,
|
|
2345
|
+
removeMe: response.removeMe
|
|
2346
|
+
};
|
|
2347
|
+
}
|
|
2348
|
+
catch (err) {
|
|
2349
|
+
logger$a.debug(`updateNeighbors to ${dht.toNodeId(this.getPeerDescriptor())} failed`, { err });
|
|
2350
|
+
return {
|
|
2351
|
+
peerDescriptors: [],
|
|
2352
|
+
removeMe: true
|
|
2353
|
+
};
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
const logger$9 = new utils.Logger('NeighborUpdateManager');
|
|
2359
|
+
const DEFAULT_NEIGHBOR_UPDATE_INTERVAL = 10 * 1000;
|
|
2360
|
+
class NeighborUpdateManager {
|
|
2361
|
+
abortController;
|
|
2362
|
+
options;
|
|
2363
|
+
rpcLocal;
|
|
2364
|
+
constructor(options) {
|
|
2365
|
+
this.abortController = new AbortController();
|
|
2366
|
+
this.rpcLocal = new NeighborUpdateRpcLocal(options);
|
|
2367
|
+
this.options = options;
|
|
2368
|
+
this.options.rpcCommunicator.registerRpcMethod(NeighborUpdate, NeighborUpdate, 'neighborUpdate', (req, context) => this.rpcLocal.neighborUpdate(req, context));
|
|
2369
|
+
}
|
|
2370
|
+
async start() {
|
|
2371
|
+
await utils.scheduleAtInterval(() => this.updateNeighborInfo(), this.options.neighborUpdateInterval, false, this.abortController.signal);
|
|
2372
|
+
}
|
|
2373
|
+
stop() {
|
|
2374
|
+
this.abortController.abort();
|
|
2375
|
+
}
|
|
2376
|
+
async updateNeighborInfo() {
|
|
2377
|
+
logger$9.trace(`Updating neighbor info to nodes`);
|
|
2378
|
+
const neighborDescriptors = this.options.neighbors.getAll().map((neighbor) => neighbor.getPeerDescriptor());
|
|
2379
|
+
const startTime = Date.now();
|
|
2380
|
+
await Promise.allSettled(this.options.neighbors.getAll().map(async (neighbor) => {
|
|
2381
|
+
const res = await this.createRemote(neighbor.getPeerDescriptor()).updateNeighbors(this.options.streamPartId, neighborDescriptors);
|
|
2382
|
+
const nodeId = dht.toNodeId(neighbor.getPeerDescriptor());
|
|
2383
|
+
this.options.neighbors.get(nodeId).setRtt(Date.now() - startTime);
|
|
2384
|
+
if (res.removeMe) {
|
|
2385
|
+
this.options.neighbors.remove(nodeId);
|
|
2386
|
+
this.options.neighborFinder.start([nodeId]);
|
|
2387
|
+
}
|
|
2388
|
+
}));
|
|
2389
|
+
}
|
|
2390
|
+
createRemote(targetPeerDescriptor) {
|
|
2391
|
+
return new NeighborUpdateRpcRemote(this.options.localPeerDescriptor, targetPeerDescriptor, this.options.rpcCommunicator, NeighborUpdateRpcClient);
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2395
|
+
class ContentDeliveryRpcLocal {
|
|
2396
|
+
options;
|
|
2397
|
+
constructor(options) {
|
|
2398
|
+
this.options = options;
|
|
2399
|
+
}
|
|
2400
|
+
async sendStreamMessage(message, context) {
|
|
2401
|
+
const previousNode = context.incomingSourceDescriptor;
|
|
2402
|
+
const previousNodeId = dht.toNodeId(previousNode);
|
|
2403
|
+
this.options.markForInspection(previousNodeId, message.messageId);
|
|
2404
|
+
if (this.options.plumtreeManager === undefined) {
|
|
2405
|
+
if (this.options.markAndCheckDuplicate(message.messageId, message.previousMessageRef)) {
|
|
2406
|
+
this.options.broadcast(message, previousNodeId);
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
else if (this.options.markAndCheckDuplicate(message.messageId, message.previousMessageRef)) {
|
|
2410
|
+
// Message is not a duplicate, so we can broadcast it over the plumtree
|
|
2411
|
+
this.options.plumtreeManager.broadcast(message, previousNodeId);
|
|
2412
|
+
}
|
|
2413
|
+
else {
|
|
2414
|
+
// Message is a duplicate, so we need to pause the neighbor
|
|
2415
|
+
await this.options.plumtreeManager.pauseNeighbor(previousNode, message.messageId.messageChainId);
|
|
2416
|
+
}
|
|
2417
|
+
return Empty;
|
|
2418
|
+
}
|
|
2419
|
+
async leaveStreamPartNotice(message, context) {
|
|
2420
|
+
if (message.streamPartId === this.options.streamPartId) {
|
|
2421
|
+
const sourcePeerDescriptor = context.incomingSourceDescriptor;
|
|
2422
|
+
const remoteNodeId = dht.toNodeId(sourcePeerDescriptor);
|
|
2423
|
+
this.options.onLeaveNotice(remoteNodeId, message.isEntryPoint);
|
|
2424
|
+
}
|
|
2425
|
+
return Empty;
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2429
|
+
/**
|
|
2430
|
+
* Represent a pair of numbers (a,b). Ordering between two pairs is defined as
|
|
2431
|
+
* follows. First compare first numbers. Compare second numbers if first are
|
|
2432
|
+
* equal.
|
|
2433
|
+
*/
|
|
2434
|
+
class NumberPair {
|
|
2435
|
+
a;
|
|
2436
|
+
b;
|
|
2437
|
+
constructor(a, b) {
|
|
2438
|
+
this.a = a;
|
|
2439
|
+
this.b = b;
|
|
2440
|
+
}
|
|
2441
|
+
greaterThanOrEqual(otherPair) {
|
|
2442
|
+
return this.greaterThan(otherPair) || this.equalTo(otherPair);
|
|
2443
|
+
}
|
|
2444
|
+
greaterThan(otherPair) {
|
|
2445
|
+
return this.compareTo(otherPair) === 1;
|
|
2446
|
+
}
|
|
2447
|
+
equalTo(otherPair) {
|
|
2448
|
+
return this.compareTo(otherPair) === 0;
|
|
2449
|
+
}
|
|
2450
|
+
compareTo(otherPair) {
|
|
2451
|
+
if (this.a > otherPair.a) {
|
|
2452
|
+
return 1;
|
|
2453
|
+
}
|
|
2454
|
+
if (this.a < otherPair.a) {
|
|
2455
|
+
return -1;
|
|
2456
|
+
}
|
|
2457
|
+
if (this.b > otherPair.b) {
|
|
2458
|
+
return 1;
|
|
2459
|
+
}
|
|
2460
|
+
if (this.b < otherPair.b) {
|
|
2461
|
+
return -1;
|
|
2462
|
+
}
|
|
2463
|
+
return 0;
|
|
2464
|
+
}
|
|
2465
|
+
toString() {
|
|
2466
|
+
return `${this.a}|${this.b}`;
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
class InvalidNumberingError extends Error {
|
|
2470
|
+
constructor() {
|
|
2471
|
+
super('pre-condition: previousNumber < number');
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
class GapMisMatchError extends Error {
|
|
2475
|
+
constructor(state, previousNumber, number) {
|
|
2476
|
+
super('pre-condition: gap overlap in given numbers:'
|
|
2477
|
+
+ ` previousNumber=${previousNumber.toString()}, number=${number.toString()}, state=${state}`);
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
/**
|
|
2481
|
+
*
|
|
2482
|
+
* Keeps track of a stream's message numbers and reports already seen numbers
|
|
2483
|
+
* as duplicates.
|
|
2484
|
+
*
|
|
2485
|
+
* Leverages the fact that message are assigned numbers from a strictly
|
|
2486
|
+
* increasing integer sequence for lowered space complexity. For example,
|
|
2487
|
+
* if we know that all messages up to number N have been seen, we can only
|
|
2488
|
+
* store the number N to provide message identity check. This is because
|
|
2489
|
+
* anything less than N can be deemed a duplicate.
|
|
2490
|
+
*
|
|
2491
|
+
* Messages arriving out-of-order makes this a bit harder since gaps form.
|
|
2492
|
+
* Most of the code in this class is built to deal with this complexity.
|
|
2493
|
+
* Basically, we need to keep track of which intervals [N,M] could still
|
|
2494
|
+
* contain unseen messages. We should also remove intervals after we are sure
|
|
2495
|
+
* that they contain no unseen messages.
|
|
2496
|
+
*
|
|
2497
|
+
* In addition to the above, there needs to be a limit to the number of
|
|
2498
|
+
* intervals we store, as it could well be that some messages never
|
|
2499
|
+
* arrive. The strategy is to start removing the lowest numbered
|
|
2500
|
+
* intervals when storage limits are hit.
|
|
2501
|
+
*
|
|
2502
|
+
*/
|
|
2503
|
+
class DuplicateMessageDetector {
|
|
2504
|
+
maxGapCount;
|
|
2505
|
+
gaps;
|
|
2506
|
+
constructor(maxGapCount = 10000) {
|
|
2507
|
+
this.maxGapCount = maxGapCount;
|
|
2508
|
+
this.gaps = []; // ascending order of half-closed intervals (x,y] representing gaps that contain unseen message(s)
|
|
2509
|
+
}
|
|
2510
|
+
/**
|
|
2511
|
+
* returns true if number has not yet been seen (i.e. is not a duplicate)
|
|
2512
|
+
*/
|
|
2513
|
+
markAndCheck(previousNumber, number) {
|
|
2514
|
+
if (previousNumber?.greaterThanOrEqual(number)) {
|
|
2515
|
+
throw new InvalidNumberingError();
|
|
2516
|
+
}
|
|
2517
|
+
if (this.gaps.length === 0) {
|
|
2518
|
+
this.gaps.push([number, new NumberPair(Infinity, Infinity)]);
|
|
2519
|
+
return true;
|
|
2520
|
+
}
|
|
2521
|
+
// Handle special case where previousNumber is not provided. Only
|
|
2522
|
+
// minimal duplicate detection is provided (comparing against latest
|
|
2523
|
+
// known message number).
|
|
2524
|
+
if (previousNumber === null) {
|
|
2525
|
+
if (number.greaterThan(this.gaps[this.gaps.length - 1][0])) {
|
|
2526
|
+
this.gaps[this.gaps.length - 1][0] = number;
|
|
2527
|
+
return true;
|
|
2528
|
+
}
|
|
2529
|
+
return false;
|
|
2530
|
+
}
|
|
2531
|
+
for (let i = this.gaps.length - 1; i >= 0; --i) {
|
|
2532
|
+
const [lowerBound, upperBound] = this.gaps[i]; // invariant: upperBound > lowerBound
|
|
2533
|
+
// implies number > upperBound (would've been handled in previous iteration if gap exists)
|
|
2534
|
+
if (previousNumber.greaterThanOrEqual(upperBound)) {
|
|
2535
|
+
return false;
|
|
2536
|
+
}
|
|
2537
|
+
if (previousNumber.greaterThanOrEqual(lowerBound)) {
|
|
2538
|
+
if (number.greaterThan(upperBound)) {
|
|
2539
|
+
throw new GapMisMatchError(this.toString(), previousNumber, number);
|
|
2540
|
+
}
|
|
2541
|
+
if (previousNumber.equalTo(lowerBound)) {
|
|
2542
|
+
if (number.equalTo(upperBound)) {
|
|
2543
|
+
this.gaps.splice(i, 1);
|
|
2544
|
+
}
|
|
2545
|
+
else {
|
|
2546
|
+
this.gaps[i] = [number, upperBound];
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
else if (number.equalTo(upperBound)) {
|
|
2550
|
+
this.gaps[i] = [lowerBound, previousNumber];
|
|
2551
|
+
}
|
|
2552
|
+
else {
|
|
2553
|
+
this.gaps.splice(i, 1, [lowerBound, previousNumber], [number, upperBound]);
|
|
2554
|
+
}
|
|
2555
|
+
// invariants after:
|
|
2556
|
+
// - gaps are in ascending order
|
|
2557
|
+
// - the intersection between any two gaps is empty
|
|
2558
|
+
// - there are no gaps that define the empty set
|
|
2559
|
+
// - last gap is [n, Infinity]
|
|
2560
|
+
// - anything not covered by a gap is considered seen
|
|
2561
|
+
this.dropLowestGapIfOverMaxGapCount();
|
|
2562
|
+
return true;
|
|
2563
|
+
}
|
|
2564
|
+
if (number.greaterThan(lowerBound)) {
|
|
2565
|
+
throw new GapMisMatchError(this.toString(), previousNumber, number);
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
return false;
|
|
2569
|
+
}
|
|
2570
|
+
dropLowestGapIfOverMaxGapCount() {
|
|
2571
|
+
// invariant: this.gaps.length <= this.maxGapCount + 1
|
|
2572
|
+
if (this.gaps.length > this.maxGapCount) {
|
|
2573
|
+
this.gaps.shift();
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
toString() {
|
|
2577
|
+
return this.gaps.map(([lower, upper]) => `(${lower.toString()}, ${upper.toString()}]`).join(', ');
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
|
|
2581
|
+
const markAndCheckDuplicate = (duplicateDetectors, currentMessage, previousMessageRef) => {
|
|
2582
|
+
const detectorKey = `${utils.toUserId(currentMessage.publisherId)}-${currentMessage.messageChainId}`;
|
|
2583
|
+
const previousNumberPair = previousMessageRef ?
|
|
2584
|
+
new NumberPair(Number(previousMessageRef.timestamp), previousMessageRef.sequenceNumber) : null;
|
|
2585
|
+
const currentNumberPair = new NumberPair(Number(currentMessage.timestamp), currentMessage.sequenceNumber);
|
|
2586
|
+
if (!duplicateDetectors.has(detectorKey)) {
|
|
2587
|
+
duplicateDetectors.set(detectorKey, new DuplicateMessageDetector());
|
|
2588
|
+
}
|
|
2589
|
+
return duplicateDetectors.get(detectorKey).markAndCheck(previousNumberPair, currentNumberPair);
|
|
2590
|
+
};
|
|
2591
|
+
|
|
2592
|
+
const DEFAULT_NODE_VIEW_SIZE = 20;
|
|
2593
|
+
const DEFAULT_NEIGHBOR_TARGET_COUNT = 4;
|
|
2594
|
+
const DEFAULT_ACCEPT_PROXY_CONNECTIONS = false;
|
|
2595
|
+
const logger$8 = new utils.Logger('ContentDeliveryLayerNode');
|
|
2596
|
+
class ContentDeliveryLayerNode extends eventemitter3.EventEmitter {
|
|
2597
|
+
started = false;
|
|
2598
|
+
duplicateDetectors;
|
|
2599
|
+
options;
|
|
2600
|
+
contentDeliveryRpcLocal;
|
|
2601
|
+
abortController = new AbortController();
|
|
2602
|
+
messagesPropagated = 0;
|
|
2603
|
+
constructor(options) {
|
|
2604
|
+
super();
|
|
2605
|
+
this.options = options;
|
|
2606
|
+
this.duplicateDetectors = new Map();
|
|
2607
|
+
this.contentDeliveryRpcLocal = new ContentDeliveryRpcLocal({
|
|
2608
|
+
localPeerDescriptor: this.options.localPeerDescriptor,
|
|
2609
|
+
streamPartId: this.options.streamPartId,
|
|
2610
|
+
rpcCommunicator: this.options.rpcCommunicator,
|
|
2611
|
+
markAndCheckDuplicate: (msg, prev) => markAndCheckDuplicate(this.duplicateDetectors, msg, prev),
|
|
2612
|
+
broadcast: (message, previousNode) => this.broadcast(message, previousNode),
|
|
2613
|
+
onLeaveNotice: (remoteNodeId, sourceIsStreamEntryPoint) => {
|
|
2614
|
+
if (this.abortController.signal.aborted) {
|
|
2615
|
+
return;
|
|
2616
|
+
}
|
|
2617
|
+
const contact = this.options.nearbyNodeView.get(remoteNodeId)
|
|
2618
|
+
?? this.options.randomNodeView.get(remoteNodeId)
|
|
2619
|
+
?? this.options.neighbors.get(remoteNodeId)
|
|
2620
|
+
?? this.options.proxyConnectionRpcLocal?.getConnection(remoteNodeId)?.remote;
|
|
2621
|
+
// TODO: check integrity of notifier?
|
|
2622
|
+
if (contact) {
|
|
2623
|
+
this.options.discoveryLayerNode.removeContact(remoteNodeId);
|
|
2624
|
+
this.options.neighbors.remove(remoteNodeId);
|
|
2625
|
+
this.options.nearbyNodeView.remove(remoteNodeId);
|
|
2626
|
+
this.options.randomNodeView.remove(remoteNodeId);
|
|
2627
|
+
this.options.leftNodeView.remove(remoteNodeId);
|
|
2628
|
+
this.options.rightNodeView.remove(remoteNodeId);
|
|
2629
|
+
this.options.neighborFinder.start([remoteNodeId]);
|
|
2630
|
+
this.options.proxyConnectionRpcLocal?.removeConnection(remoteNodeId);
|
|
2631
|
+
}
|
|
2632
|
+
if (sourceIsStreamEntryPoint) {
|
|
2633
|
+
this.emit('entryPointLeaveDetected');
|
|
2634
|
+
}
|
|
2635
|
+
},
|
|
2636
|
+
markForInspection: (remoteNodeId, messageId) => this.options.inspector.markMessage(remoteNodeId, messageId),
|
|
2637
|
+
plumtreeManager: this.options.plumtreeManager
|
|
2638
|
+
});
|
|
2639
|
+
}
|
|
2640
|
+
async start() {
|
|
2641
|
+
this.started = true;
|
|
2642
|
+
this.registerDefaultServerMethods();
|
|
2643
|
+
utils.addManagedEventListener(this.options.discoveryLayerNode, 'nearbyContactAdded', () => this.onNearbyContactAdded(), this.abortController.signal);
|
|
2644
|
+
utils.addManagedEventListener(this.options.discoveryLayerNode, 'nearbyContactRemoved', () => this.onNearbyContactRemoved(), this.abortController.signal);
|
|
2645
|
+
utils.addManagedEventListener(this.options.discoveryLayerNode, 'randomContactAdded', () => this.onRandomContactAdded(), this.abortController.signal);
|
|
2646
|
+
utils.addManagedEventListener(this.options.discoveryLayerNode, 'randomContactRemoved', () => this.onRandomContactRemoved(), this.abortController.signal);
|
|
2647
|
+
utils.addManagedEventListener(this.options.discoveryLayerNode, 'ringContactAdded', () => this.onRingContactsUpdated(), this.abortController.signal);
|
|
2648
|
+
utils.addManagedEventListener(this.options.discoveryLayerNode, 'ringContactRemoved', () => this.onRingContactsUpdated(), this.abortController.signal);
|
|
2649
|
+
utils.addManagedEventListener(this.options.transport, 'disconnected', (peerDescriptor) => this.onNodeDisconnected(peerDescriptor), this.abortController.signal);
|
|
2650
|
+
utils.addManagedEventListener(this.options.neighbors, 'nodeAdded', (id, remote) => {
|
|
2651
|
+
this.options.propagation.onNeighborJoined(id);
|
|
2652
|
+
this.options.connectionLocker.weakLockConnection(dht.toNodeId(remote.getPeerDescriptor()), this.options.streamPartId);
|
|
2653
|
+
this.emit('neighborConnected', id);
|
|
2654
|
+
}, this.abortController.signal);
|
|
2655
|
+
utils.addManagedEventListener(this.options.neighbors, 'nodeRemoved', (_id, remote) => {
|
|
2656
|
+
this.options.connectionLocker.weakUnlockConnection(dht.toNodeId(remote.getPeerDescriptor()), this.options.streamPartId);
|
|
2657
|
+
}, this.abortController.signal);
|
|
2658
|
+
if (this.options.proxyConnectionRpcLocal !== undefined) {
|
|
2659
|
+
utils.addManagedEventListener(this.options.proxyConnectionRpcLocal, 'newConnection', (id) => this.options.propagation.onNeighborJoined(id), this.abortController.signal);
|
|
2660
|
+
}
|
|
2661
|
+
if (this.options.plumtreeManager) {
|
|
2662
|
+
utils.addManagedEventListener(this.options.plumtreeManager, 'message', (msg) => this.emit('message', msg), this.abortController.signal);
|
|
2663
|
+
}
|
|
2664
|
+
this.options.neighborFinder.start();
|
|
2665
|
+
await this.options.neighborUpdateManager.start();
|
|
2666
|
+
}
|
|
2667
|
+
registerDefaultServerMethods() {
|
|
2668
|
+
this.options.rpcCommunicator.registerRpcNotification(StreamMessage, 'sendStreamMessage', (msg, context) => this.contentDeliveryRpcLocal.sendStreamMessage(msg, context));
|
|
2669
|
+
this.options.rpcCommunicator.registerRpcNotification(LeaveStreamPartNotice, 'leaveStreamPartNotice', (req, context) => this.contentDeliveryRpcLocal.leaveStreamPartNotice(req, context));
|
|
2670
|
+
this.options.rpcCommunicator.registerRpcMethod(TemporaryConnectionRequest, TemporaryConnectionResponse, 'openConnection', (req, context) => this.options.temporaryConnectionRpcLocal.openConnection(req, context));
|
|
2671
|
+
this.options.rpcCommunicator.registerRpcNotification(CloseTemporaryConnection, 'closeConnection', (req, context) => this.options.temporaryConnectionRpcLocal.closeConnection(req, context));
|
|
2672
|
+
}
|
|
2673
|
+
onRingContactsUpdated() {
|
|
2674
|
+
logger$8.trace('onRingContactsUpdated');
|
|
2675
|
+
if (this.isStopped()) {
|
|
2676
|
+
return;
|
|
2677
|
+
}
|
|
2678
|
+
const contacts = this.options.discoveryLayerNode.getRingContacts();
|
|
2679
|
+
this.options.leftNodeView.replaceAll(contacts.left.map((peer) => new ContentDeliveryRpcRemote(this.options.localPeerDescriptor, peer, this.options.rpcCommunicator, ContentDeliveryRpcClient, this.options.rpcRequestTimeout)));
|
|
2680
|
+
this.options.rightNodeView.replaceAll(contacts.right.map((peer) => new ContentDeliveryRpcRemote(this.options.localPeerDescriptor, peer, this.options.rpcCommunicator, ContentDeliveryRpcClient, this.options.rpcRequestTimeout)));
|
|
2681
|
+
}
|
|
2682
|
+
onNearbyContactAdded() {
|
|
2683
|
+
logger$8.trace(`New nearby contact found`);
|
|
2684
|
+
if (this.isStopped()) {
|
|
2685
|
+
return;
|
|
2686
|
+
}
|
|
2687
|
+
const closestContacts = this.options.discoveryLayerNode.getClosestContacts();
|
|
2688
|
+
this.updateNearbyNodeView(closestContacts);
|
|
2689
|
+
if (this.options.neighbors.size() < this.options.neighborTargetCount) {
|
|
2690
|
+
this.options.neighborFinder.start();
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
onNearbyContactRemoved() {
|
|
2694
|
+
logger$8.trace(`Nearby contact removed`);
|
|
2695
|
+
if (this.isStopped()) {
|
|
2696
|
+
return;
|
|
2697
|
+
}
|
|
2698
|
+
const closestContacts = this.options.discoveryLayerNode.getClosestContacts();
|
|
2699
|
+
this.updateNearbyNodeView(closestContacts);
|
|
2700
|
+
}
|
|
2701
|
+
updateNearbyNodeView(nodes) {
|
|
2702
|
+
this.options.nearbyNodeView.replaceAll(Array.from(nodes).map((descriptor) => new ContentDeliveryRpcRemote(this.options.localPeerDescriptor, descriptor, this.options.rpcCommunicator, ContentDeliveryRpcClient, this.options.rpcRequestTimeout)));
|
|
2703
|
+
for (const descriptor of this.options.discoveryLayerNode.getNeighbors()) {
|
|
2704
|
+
if (this.options.nearbyNodeView.size() >= this.options.nodeViewSize) {
|
|
2705
|
+
break;
|
|
2706
|
+
}
|
|
2707
|
+
this.options.nearbyNodeView.add(new ContentDeliveryRpcRemote(this.options.localPeerDescriptor, descriptor, this.options.rpcCommunicator, ContentDeliveryRpcClient, this.options.rpcRequestTimeout));
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
onRandomContactAdded() {
|
|
2711
|
+
if (this.isStopped()) {
|
|
2712
|
+
return;
|
|
2713
|
+
}
|
|
2714
|
+
const randomContacts = this.options.discoveryLayerNode.getRandomContacts(this.options.nodeViewSize);
|
|
2715
|
+
this.options.randomNodeView.replaceAll(randomContacts.map((descriptor) => new ContentDeliveryRpcRemote(this.options.localPeerDescriptor, descriptor, this.options.rpcCommunicator, ContentDeliveryRpcClient, this.options.rpcRequestTimeout)));
|
|
2716
|
+
if (this.options.neighbors.size() < this.options.neighborTargetCount) {
|
|
2717
|
+
this.options.neighborFinder.start();
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
onRandomContactRemoved() {
|
|
2721
|
+
logger$8.trace(`New random contact removed`);
|
|
2722
|
+
if (this.isStopped()) {
|
|
2723
|
+
return;
|
|
2724
|
+
}
|
|
2725
|
+
const randomContacts = this.options.discoveryLayerNode.getRandomContacts(this.options.nodeViewSize);
|
|
2726
|
+
this.options.randomNodeView.replaceAll(randomContacts.map((descriptor) => new ContentDeliveryRpcRemote(this.options.localPeerDescriptor, descriptor, this.options.rpcCommunicator, ContentDeliveryRpcClient, this.options.rpcRequestTimeout)));
|
|
2727
|
+
}
|
|
2728
|
+
onNodeDisconnected(peerDescriptor) {
|
|
2729
|
+
const nodeId = dht.toNodeId(peerDescriptor);
|
|
2730
|
+
if (this.options.neighbors.has(nodeId)) {
|
|
2731
|
+
this.options.neighbors.remove(nodeId);
|
|
2732
|
+
this.options.neighborFinder.start([nodeId]);
|
|
2733
|
+
this.options.temporaryConnectionRpcLocal.removeNode(nodeId);
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
hasProxyConnection(nodeId) {
|
|
2737
|
+
if (this.options.proxyConnectionRpcLocal) {
|
|
2738
|
+
return this.options.proxyConnectionRpcLocal.hasConnection(nodeId);
|
|
2739
|
+
}
|
|
2740
|
+
return false;
|
|
2741
|
+
}
|
|
2742
|
+
stop() {
|
|
2743
|
+
if (!this.started) {
|
|
2744
|
+
return;
|
|
2745
|
+
}
|
|
2746
|
+
this.abortController.abort();
|
|
2747
|
+
this.options.proxyConnectionRpcLocal?.stop();
|
|
2748
|
+
this.options.neighbors.getAll().map((remote) => {
|
|
2749
|
+
remote.leaveStreamPartNotice(this.options.streamPartId, this.options.isLocalNodeEntryPoint());
|
|
2750
|
+
this.options.connectionLocker.weakUnlockConnection(dht.toNodeId(remote.getPeerDescriptor()), this.options.streamPartId);
|
|
2751
|
+
});
|
|
2752
|
+
this.options.rpcCommunicator.destroy();
|
|
2753
|
+
this.removeAllListeners();
|
|
2754
|
+
this.options.plumtreeManager?.stop();
|
|
2755
|
+
this.options.nearbyNodeView.stop();
|
|
2756
|
+
this.options.neighbors.stop();
|
|
2757
|
+
this.options.randomNodeView.stop();
|
|
2758
|
+
this.options.neighborFinder.stop();
|
|
2759
|
+
this.options.neighborUpdateManager.stop();
|
|
2760
|
+
this.options.inspector.stop();
|
|
2761
|
+
}
|
|
2762
|
+
broadcast(msg, previousNode) {
|
|
2763
|
+
if (!previousNode) {
|
|
2764
|
+
markAndCheckDuplicate(this.duplicateDetectors, msg.messageId, msg.previousMessageRef);
|
|
2765
|
+
}
|
|
2766
|
+
this.emit('message', msg);
|
|
2767
|
+
const skipBackPropagation = previousNode !== undefined && !this.options.temporaryConnectionRpcLocal.hasNode(previousNode);
|
|
2768
|
+
this.options.propagation.feedUnseenMessage(msg, this.getPropagationTargets(msg), skipBackPropagation ? previousNode : null);
|
|
2769
|
+
this.messagesPropagated += 1;
|
|
2770
|
+
}
|
|
2771
|
+
inspect(peerDescriptor) {
|
|
2772
|
+
return this.options.inspector.inspect(peerDescriptor);
|
|
2773
|
+
}
|
|
2774
|
+
getPropagationTargets(msg) {
|
|
2775
|
+
let propagationTargets = this.options.neighbors.getIds();
|
|
2776
|
+
if (this.options.proxyConnectionRpcLocal) {
|
|
2777
|
+
propagationTargets = propagationTargets.concat(this.options.proxyConnectionRpcLocal.getPropagationTargets(msg));
|
|
2778
|
+
}
|
|
2779
|
+
propagationTargets = propagationTargets.concat(this.options.temporaryConnectionRpcLocal.getNodes().getIds());
|
|
2780
|
+
return propagationTargets;
|
|
2781
|
+
}
|
|
2782
|
+
getOwnNodeId() {
|
|
2783
|
+
return dht.toNodeId(this.options.localPeerDescriptor);
|
|
2784
|
+
}
|
|
2785
|
+
getOutgoingHandshakeCount() {
|
|
2786
|
+
return this.options.handshaker.getOngoingHandshakes().size;
|
|
2787
|
+
}
|
|
2788
|
+
getNeighbors() {
|
|
2789
|
+
if (!this.started && this.isStopped()) {
|
|
2790
|
+
return [];
|
|
2791
|
+
}
|
|
2792
|
+
return this.options.neighbors.getAll().map((n) => n.getPeerDescriptor());
|
|
2793
|
+
}
|
|
2794
|
+
getInfos() {
|
|
2795
|
+
return this.options.neighbors.getAll().map((n) => {
|
|
2796
|
+
return {
|
|
2797
|
+
peerDescriptor: n.getPeerDescriptor(),
|
|
2798
|
+
rtt: n.getRtt()
|
|
2799
|
+
};
|
|
2800
|
+
});
|
|
2801
|
+
}
|
|
2802
|
+
getNearbyNodeView() {
|
|
2803
|
+
return this.options.nearbyNodeView;
|
|
2804
|
+
}
|
|
2805
|
+
getDiagnosticInfo() {
|
|
2806
|
+
return {
|
|
2807
|
+
neighborCount: this.options.neighbors.size(),
|
|
2808
|
+
nearbyNodeViewCount: this.options.nearbyNodeView.size(),
|
|
2809
|
+
randomNodeViewCount: this.options.randomNodeView.size(),
|
|
2810
|
+
leftNodeViewCount: this.options.leftNodeView.size(),
|
|
2811
|
+
rightNodeViewCount: this.options.rightNodeView.size(),
|
|
2812
|
+
messagesPropagated: this.messagesPropagated
|
|
2813
|
+
};
|
|
2814
|
+
}
|
|
2815
|
+
isStopped() {
|
|
2816
|
+
return this.abortController.signal.aborted;
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
const getValuesOfIncludedKeys = (nodes, exclude, wsOnly = false) => {
|
|
2821
|
+
const values = wsOnly
|
|
2822
|
+
? Array.from(nodes.entries()).filter(([_, node]) => node.getPeerDescriptor().websocket !== undefined)
|
|
2823
|
+
: Array.from(nodes.entries());
|
|
2824
|
+
return values
|
|
2825
|
+
.filter(([id]) => !exclude.includes(id))
|
|
2826
|
+
.map(([_id, node]) => node);
|
|
2827
|
+
};
|
|
2828
|
+
// The items in the list are in the insertion order
|
|
2829
|
+
class NodeList extends eventemitter3.EventEmitter {
|
|
2830
|
+
nodes;
|
|
2831
|
+
limit;
|
|
2832
|
+
ownId;
|
|
2833
|
+
constructor(ownId, limit) {
|
|
2834
|
+
super();
|
|
2835
|
+
this.nodes = new Map();
|
|
2836
|
+
this.limit = limit;
|
|
2837
|
+
this.ownId = ownId;
|
|
2838
|
+
}
|
|
2839
|
+
add(remote) {
|
|
2840
|
+
const nodeId = dht.toNodeId(remote.getPeerDescriptor());
|
|
2841
|
+
if ((this.ownId !== nodeId) && (this.nodes.size < this.limit)) {
|
|
2842
|
+
const isExistingNode = this.nodes.has(nodeId);
|
|
2843
|
+
this.nodes.set(nodeId, remote);
|
|
2844
|
+
if (!isExistingNode) {
|
|
2845
|
+
this.emit('nodeAdded', nodeId, remote);
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
remove(nodeId) {
|
|
2850
|
+
if (this.nodes.has(nodeId)) {
|
|
2851
|
+
const remote = this.nodes.get(nodeId);
|
|
2852
|
+
this.nodes.delete(nodeId);
|
|
2853
|
+
this.emit('nodeRemoved', nodeId, remote);
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
has(nodeId) {
|
|
2857
|
+
return this.nodes.has(nodeId);
|
|
2858
|
+
}
|
|
2859
|
+
// Replace nodes does not emit nodeRemoved events, use with caution
|
|
2860
|
+
replaceAll(neighbors) {
|
|
2861
|
+
this.nodes.clear();
|
|
2862
|
+
const limited = neighbors.splice(0, this.limit);
|
|
2863
|
+
limited.forEach((remote) => {
|
|
2864
|
+
this.add(remote);
|
|
2865
|
+
});
|
|
2866
|
+
}
|
|
2867
|
+
getIds() {
|
|
2868
|
+
return Array.from(this.nodes.keys());
|
|
2869
|
+
}
|
|
2870
|
+
get(id) {
|
|
2871
|
+
return this.nodes.get(id);
|
|
2872
|
+
}
|
|
2873
|
+
size(exclude = []) {
|
|
2874
|
+
return Array.from(this.nodes.keys()).filter((node) => !exclude.includes(node)).length;
|
|
2875
|
+
}
|
|
2876
|
+
getRandom(exclude) {
|
|
2877
|
+
return sample(getValuesOfIncludedKeys(this.nodes, exclude));
|
|
2878
|
+
}
|
|
2879
|
+
getFirst(exclude, wsOnly = false) {
|
|
2880
|
+
const included = getValuesOfIncludedKeys(this.nodes, exclude, wsOnly);
|
|
2881
|
+
return included[0];
|
|
2882
|
+
}
|
|
2883
|
+
getFirstAndLast(exclude) {
|
|
2884
|
+
const included = getValuesOfIncludedKeys(this.nodes, exclude);
|
|
2885
|
+
if (included.length === 0) {
|
|
2886
|
+
return [];
|
|
2887
|
+
}
|
|
2888
|
+
return included.length > 1 ? [this.getFirst(exclude), this.getLast(exclude)] : [this.getFirst(exclude)];
|
|
2889
|
+
}
|
|
2890
|
+
getLast(exclude) {
|
|
2891
|
+
const included = getValuesOfIncludedKeys(this.nodes, exclude);
|
|
2892
|
+
return included[included.length - 1];
|
|
2893
|
+
}
|
|
2894
|
+
getAll() {
|
|
2895
|
+
return Array.from(this.nodes.values());
|
|
2896
|
+
}
|
|
2897
|
+
stop() {
|
|
2898
|
+
this.nodes.forEach((node) => this.remove(dht.toNodeId(node.getPeerDescriptor())));
|
|
2899
|
+
this.removeAllListeners();
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
|
|
2903
|
+
/**
|
|
2904
|
+
* A "Map" implementation with a maximum size and TTL expiration on entries.
|
|
2905
|
+
*
|
|
2906
|
+
* When full, room is made for new entries by dropping existing by FIFO method.
|
|
2907
|
+
*
|
|
2908
|
+
* Entries have a TTL after which they are considered stale. Stale items are
|
|
2909
|
+
* not returned when querying.
|
|
2910
|
+
*
|
|
2911
|
+
*/
|
|
2912
|
+
class FifoMapWithTTL {
|
|
2913
|
+
// class invariant: the keys present in `items` and `dropQueue` are the same set.
|
|
2914
|
+
items = new Map();
|
|
2915
|
+
dropQueue = yallist.Yallist.create(); // queue is used to determine deletion order when full
|
|
2916
|
+
ttlInMs;
|
|
2917
|
+
maxSize;
|
|
2918
|
+
onItemDropped;
|
|
2919
|
+
timeProvider;
|
|
2920
|
+
constructor({ ttlInMs, maxSize, onItemDropped = () => { }, timeProvider = Date.now }) {
|
|
2921
|
+
if (ttlInMs < 0) {
|
|
2922
|
+
throw new Error(`ttlInMs (${ttlInMs}) cannot be < 0`);
|
|
2923
|
+
}
|
|
2924
|
+
if (maxSize < 0) {
|
|
2925
|
+
throw new Error(`maxSize (${maxSize}) cannot be < 0`);
|
|
2926
|
+
}
|
|
2927
|
+
this.ttlInMs = ttlInMs;
|
|
2928
|
+
this.maxSize = maxSize;
|
|
2929
|
+
this.onItemDropped = onItemDropped;
|
|
2930
|
+
this.timeProvider = timeProvider;
|
|
2931
|
+
}
|
|
2932
|
+
set(key, value) {
|
|
2933
|
+
if (this.maxSize === 0) {
|
|
2934
|
+
return;
|
|
2935
|
+
}
|
|
2936
|
+
if (this.items.size > this.maxSize) {
|
|
2937
|
+
throw new Error('assertion error: maximum size exceeded');
|
|
2938
|
+
}
|
|
2939
|
+
// delete an existing entry if exists
|
|
2940
|
+
this.delete(key);
|
|
2941
|
+
// make room for new entry
|
|
2942
|
+
if (this.items.size === this.maxSize) {
|
|
2943
|
+
const keyToDel = this.dropQueue.shift();
|
|
2944
|
+
if (keyToDel === undefined) {
|
|
2945
|
+
throw new Error('assertion error: queue empty but still have items');
|
|
2946
|
+
}
|
|
2947
|
+
this.items.delete(keyToDel);
|
|
2948
|
+
this.onItemDropped(keyToDel);
|
|
2949
|
+
}
|
|
2950
|
+
// add entry
|
|
2951
|
+
const dropQueueNode = new yallist.Node(key);
|
|
2952
|
+
this.dropQueue.pushNode(dropQueueNode);
|
|
2953
|
+
this.items.set(key, {
|
|
2954
|
+
value,
|
|
2955
|
+
dropQueueNode,
|
|
2956
|
+
expiresAt: this.timeProvider() + this.ttlInMs
|
|
2957
|
+
});
|
|
2958
|
+
}
|
|
2959
|
+
delete(key) {
|
|
2960
|
+
const item = this.items.get(key);
|
|
2961
|
+
if (item !== undefined) {
|
|
2962
|
+
this.items.delete(key);
|
|
2963
|
+
this.dropQueue.removeNode(item.dropQueueNode);
|
|
2964
|
+
this.onItemDropped(key);
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
get(key) {
|
|
2968
|
+
const item = this.items.get(key);
|
|
2969
|
+
if (item === undefined) {
|
|
2970
|
+
return undefined;
|
|
2971
|
+
}
|
|
2972
|
+
if (item.expiresAt <= this.timeProvider()) {
|
|
2973
|
+
this.delete(key);
|
|
2974
|
+
return undefined;
|
|
2975
|
+
}
|
|
2976
|
+
return item.value;
|
|
2977
|
+
}
|
|
2978
|
+
values() {
|
|
2979
|
+
const keys = [...this.items.keys()];
|
|
2980
|
+
const values = [];
|
|
2981
|
+
for (const key of keys) {
|
|
2982
|
+
const value = this.get(key);
|
|
2983
|
+
if (value !== undefined) {
|
|
2984
|
+
values.push(value);
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
2987
|
+
return values;
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
|
|
2991
|
+
/**
|
|
2992
|
+
* Keeps track of propagation tasks for the needs of message propagation logic.
|
|
2993
|
+
*
|
|
2994
|
+
* Properties:
|
|
2995
|
+
* - Allows fetching propagation tasks by StreamPartID
|
|
2996
|
+
* - Upper bound on number of tasks stored, replacement policy if FIFO
|
|
2997
|
+
* - Items have a TTL, after which they are considered stale and not returned when querying
|
|
2998
|
+
**/
|
|
2999
|
+
class PropagationTaskStore {
|
|
3000
|
+
tasks;
|
|
3001
|
+
constructor(ttlInMs, maxTasks) {
|
|
3002
|
+
this.tasks = new FifoMapWithTTL({
|
|
3003
|
+
ttlInMs,
|
|
3004
|
+
maxSize: maxTasks
|
|
3005
|
+
});
|
|
3006
|
+
}
|
|
3007
|
+
get() {
|
|
3008
|
+
return this.tasks.values();
|
|
3009
|
+
}
|
|
3010
|
+
add(task) {
|
|
3011
|
+
const messageId = task.message.messageId;
|
|
3012
|
+
this.tasks.set(messageId, task);
|
|
3013
|
+
}
|
|
3014
|
+
delete(messageId) {
|
|
3015
|
+
this.tasks.delete(messageId); // causes `onKeyDropped` to be invoked
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
|
|
3019
|
+
const DEFAULT_PROPAGATION_BUFFER_TTL = 10 * 1000;
|
|
3020
|
+
const DEFAULT_MIN_PROPAGATION_TARGETS = 2;
|
|
3021
|
+
const DEFAULT_MAX_PROPAGATION_BUFFER_SIZE = 150;
|
|
3022
|
+
/**
|
|
3023
|
+
* Message propagation logic of a node. Given a message, this class will actively attempt to propagate it to
|
|
3024
|
+
* `minPropagationTargets` neighbors until success or TTL expiration.
|
|
3025
|
+
*
|
|
3026
|
+
* Setting `minPropagationTargets = 0` effectively disables any propagation reattempts. A message will then
|
|
3027
|
+
* only be propagated exactly once, to neighbors that are present at that moment, in a fire-and-forget manner.
|
|
3028
|
+
*/
|
|
3029
|
+
class Propagation {
|
|
3030
|
+
sendToNeighbor;
|
|
3031
|
+
minPropagationTargets;
|
|
3032
|
+
activeTaskStore;
|
|
3033
|
+
constructor({ sendToNeighbor, minPropagationTargets, maxMessages, ttl }) {
|
|
3034
|
+
this.sendToNeighbor = sendToNeighbor;
|
|
3035
|
+
this.minPropagationTargets = minPropagationTargets;
|
|
3036
|
+
this.activeTaskStore = new PropagationTaskStore(ttl, maxMessages);
|
|
3037
|
+
}
|
|
3038
|
+
/**
|
|
3039
|
+
* Node should invoke this when it learns about a new message
|
|
3040
|
+
*/
|
|
3041
|
+
feedUnseenMessage(message, targets, source) {
|
|
3042
|
+
const task = {
|
|
3043
|
+
message,
|
|
3044
|
+
source,
|
|
3045
|
+
handledNeighbors: new Set()
|
|
3046
|
+
};
|
|
3047
|
+
this.activeTaskStore.add(task);
|
|
3048
|
+
for (const target of targets) {
|
|
3049
|
+
this.sendAndAwaitThenMark(task, target);
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
/**
|
|
3053
|
+
* Node should invoke this when it learns about a new node stream assignment
|
|
3054
|
+
*/
|
|
3055
|
+
onNeighborJoined(neighborId) {
|
|
3056
|
+
const tasks = this.activeTaskStore.get();
|
|
3057
|
+
for (const task of tasks) {
|
|
3058
|
+
this.sendAndAwaitThenMark(task, neighborId);
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
sendAndAwaitThenMark({ message, source, handledNeighbors }, neighborId) {
|
|
3062
|
+
if (!handledNeighbors.has(neighborId) && neighborId !== source) {
|
|
3063
|
+
(async () => {
|
|
3064
|
+
try {
|
|
3065
|
+
await this.sendToNeighbor(neighborId, message);
|
|
3066
|
+
}
|
|
3067
|
+
catch {
|
|
3068
|
+
return;
|
|
3069
|
+
}
|
|
3070
|
+
// Side-note: due to asynchronicity, the task being modified at this point could already be stale and
|
|
3071
|
+
// deleted from `activeTaskStore`. However, as modifying it or re-deleting it is pretty much
|
|
3072
|
+
// inconsequential at this point, leaving the logic as is.
|
|
3073
|
+
handledNeighbors.add(neighborId);
|
|
3074
|
+
if (handledNeighbors.size >= this.minPropagationTargets) {
|
|
3075
|
+
this.activeTaskStore.delete(message.messageId);
|
|
3076
|
+
}
|
|
3077
|
+
})();
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
|
|
3082
|
+
const logger$7 = new utils.Logger('ProxyConnectionRpcLocal');
|
|
3083
|
+
class ProxyConnectionRpcLocal extends eventemitter3.EventEmitter {
|
|
3084
|
+
options;
|
|
3085
|
+
connections = new Map();
|
|
3086
|
+
constructor(options) {
|
|
3087
|
+
super();
|
|
3088
|
+
this.options = options;
|
|
3089
|
+
this.options.rpcCommunicator.registerRpcMethod(ProxyConnectionRequest, ProxyConnectionResponse, 'requestConnection', (msg, context) => this.requestConnection(msg, context));
|
|
3090
|
+
}
|
|
3091
|
+
getConnection(nodeId) {
|
|
3092
|
+
return this.connections.get(nodeId);
|
|
3093
|
+
}
|
|
3094
|
+
hasConnection(nodeId) {
|
|
3095
|
+
return this.connections.has(nodeId);
|
|
3096
|
+
}
|
|
3097
|
+
removeConnection(nodeId) {
|
|
3098
|
+
this.connections.delete(nodeId);
|
|
3099
|
+
}
|
|
3100
|
+
stop() {
|
|
3101
|
+
this.connections.forEach((connection) => connection.remote.leaveStreamPartNotice(this.options.streamPartId, false));
|
|
3102
|
+
this.connections.clear();
|
|
3103
|
+
this.removeAllListeners();
|
|
3104
|
+
}
|
|
3105
|
+
getPropagationTargets(msg) {
|
|
3106
|
+
if (msg.body.oneofKind === 'groupKeyRequest') {
|
|
3107
|
+
try {
|
|
3108
|
+
const recipientId = msg.body.groupKeyRequest.recipientId;
|
|
3109
|
+
return this.getNodeIdsForUserId(utils.toUserId(recipientId));
|
|
3110
|
+
}
|
|
3111
|
+
catch (err) {
|
|
3112
|
+
logger$7.trace(`Could not parse GroupKeyRequest`, { err });
|
|
3113
|
+
return [];
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
else {
|
|
3117
|
+
return this.getSubscribers();
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
getNodeIdsForUserId(userId) {
|
|
3121
|
+
return Array.from(this.connections.keys()).filter((nodeId) => this.connections.get(nodeId).userId === userId);
|
|
3122
|
+
}
|
|
3123
|
+
getSubscribers() {
|
|
3124
|
+
return Array.from(this.connections.keys()).filter((key) => {
|
|
3125
|
+
const direction = this.connections.get(key).direction;
|
|
3126
|
+
return direction === undefined || direction === exports.ProxyDirection.SUBSCRIBE;
|
|
3127
|
+
});
|
|
3128
|
+
}
|
|
3129
|
+
// IProxyConnectionRpc server method
|
|
3130
|
+
async requestConnection(request, context) {
|
|
3131
|
+
const senderPeerDescriptor = context.incomingSourceDescriptor;
|
|
3132
|
+
const remoteNodeId = dht.toNodeId(senderPeerDescriptor);
|
|
3133
|
+
this.connections.set(remoteNodeId, {
|
|
3134
|
+
direction: request.direction,
|
|
3135
|
+
userId: utils.toUserId(request.userId),
|
|
3136
|
+
remote: new ContentDeliveryRpcRemote(this.options.localPeerDescriptor, senderPeerDescriptor, this.options.rpcCommunicator, ContentDeliveryRpcClient)
|
|
3137
|
+
});
|
|
3138
|
+
const response = {
|
|
3139
|
+
accepted: true
|
|
3140
|
+
};
|
|
3141
|
+
logger$7.trace(`Accepted connection request from ${remoteNodeId} to ${this.options.streamPartId}`);
|
|
3142
|
+
this.emit('newConnection', remoteNodeId);
|
|
3143
|
+
return response;
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
const logger$6 = new utils.Logger('TemporaryConnectionRpcRemote');
|
|
3148
|
+
class TemporaryConnectionRpcRemote extends dht.RpcRemote {
|
|
3149
|
+
async openConnection() {
|
|
3150
|
+
try {
|
|
3151
|
+
const response = await this.getClient().openConnection({}, this.formDhtRpcOptions());
|
|
3152
|
+
return response.accepted;
|
|
3153
|
+
}
|
|
3154
|
+
catch (err) {
|
|
3155
|
+
logger$6.debug(`temporaryConnection to ${dht.toNodeId(this.getPeerDescriptor())} failed`, { err });
|
|
3156
|
+
return false;
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
async closeConnection() {
|
|
3160
|
+
try {
|
|
3161
|
+
await this.getClient().closeConnection({}, this.formDhtRpcOptions({
|
|
3162
|
+
connect: false,
|
|
3163
|
+
notification: true
|
|
3164
|
+
}));
|
|
3165
|
+
}
|
|
3166
|
+
catch (err) {
|
|
3167
|
+
logger$6.trace(`closeConnection to ${dht.toNodeId(this.getPeerDescriptor())} failed`, { err });
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
const createMessageKey = (messageId) => {
|
|
3173
|
+
return `${utils.toUserId(messageId.publisherId)}:${messageId.messageChainId}:${messageId.timestamp}:${messageId.sequenceNumber}`;
|
|
3174
|
+
};
|
|
3175
|
+
class InspectSession extends eventemitter3.EventEmitter {
|
|
3176
|
+
// Boolean indicates if the message has been received by the inspected node
|
|
3177
|
+
inspectionMessages = new Map();
|
|
3178
|
+
inspectedNode;
|
|
3179
|
+
constructor(options) {
|
|
3180
|
+
super();
|
|
3181
|
+
this.inspectedNode = options.inspectedNode;
|
|
3182
|
+
}
|
|
3183
|
+
markMessage(remoteNodeId, messageId) {
|
|
3184
|
+
const messageKey = createMessageKey(messageId);
|
|
3185
|
+
if (!this.inspectionMessages.has(messageKey)) {
|
|
3186
|
+
this.inspectionMessages.set(messageKey, remoteNodeId === this.inspectedNode);
|
|
3187
|
+
}
|
|
3188
|
+
else if (this.inspectionMessages.has(messageKey)
|
|
3189
|
+
&& this.inspectionMessages.get(messageKey) === false
|
|
3190
|
+
&& remoteNodeId === this.inspectedNode) {
|
|
3191
|
+
this.emit('done');
|
|
3192
|
+
}
|
|
3193
|
+
else if (this.inspectionMessages.has(messageKey)
|
|
3194
|
+
&& this.inspectionMessages.get(messageKey) === true) {
|
|
3195
|
+
this.emit('done');
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
getInspectedMessageCount() {
|
|
3199
|
+
return this.inspectionMessages.size;
|
|
3200
|
+
}
|
|
3201
|
+
onlyMarkedByInspectedNode() {
|
|
3202
|
+
return Array.from(this.inspectionMessages.values()).every((value) => value === true);
|
|
3203
|
+
}
|
|
3204
|
+
stop() {
|
|
3205
|
+
this.emit('done');
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
|
|
3209
|
+
const logger$5 = new utils.Logger('Inspector');
|
|
3210
|
+
const DEFAULT_TIMEOUT = 60 * 1000;
|
|
3211
|
+
class Inspector {
|
|
3212
|
+
sessions = new Map();
|
|
3213
|
+
streamPartId;
|
|
3214
|
+
localPeerDescriptor;
|
|
3215
|
+
rpcCommunicator;
|
|
3216
|
+
connectionLocker;
|
|
3217
|
+
inspectionTimeout;
|
|
3218
|
+
openInspectConnection;
|
|
3219
|
+
closeInspectConnection;
|
|
3220
|
+
constructor(options) {
|
|
3221
|
+
this.streamPartId = options.streamPartId;
|
|
3222
|
+
this.localPeerDescriptor = options.localPeerDescriptor;
|
|
3223
|
+
this.rpcCommunicator = options.rpcCommunicator;
|
|
3224
|
+
this.connectionLocker = options.connectionLocker;
|
|
3225
|
+
this.inspectionTimeout = options.inspectionTimeout ?? DEFAULT_TIMEOUT;
|
|
3226
|
+
this.openInspectConnection = options.openInspectConnection ?? this.defaultOpenInspectConnection;
|
|
3227
|
+
this.closeInspectConnection = options.closeInspectConnection ?? this.defaultCloseInspectConnection;
|
|
3228
|
+
}
|
|
3229
|
+
async defaultOpenInspectConnection(peerDescriptor, lockId) {
|
|
3230
|
+
const rpcRemote = new TemporaryConnectionRpcRemote(this.localPeerDescriptor, peerDescriptor, this.rpcCommunicator, TemporaryConnectionRpcClient);
|
|
3231
|
+
await rpcRemote.openConnection();
|
|
3232
|
+
this.connectionLocker.weakLockConnection(dht.toNodeId(peerDescriptor), lockId);
|
|
3233
|
+
}
|
|
3234
|
+
async defaultCloseInspectConnection(peerDescriptor, lockId) {
|
|
3235
|
+
const rpcRemote = new TemporaryConnectionRpcRemote(this.localPeerDescriptor, peerDescriptor, this.rpcCommunicator, TemporaryConnectionRpcClient);
|
|
3236
|
+
await rpcRemote.closeConnection();
|
|
3237
|
+
this.connectionLocker.weakUnlockConnection(dht.toNodeId(peerDescriptor), lockId);
|
|
3238
|
+
}
|
|
3239
|
+
async inspect(peerDescriptor) {
|
|
3240
|
+
const nodeId = dht.toNodeId(peerDescriptor);
|
|
3241
|
+
const session = new InspectSession({
|
|
3242
|
+
inspectedNode: nodeId
|
|
3243
|
+
});
|
|
3244
|
+
const lockId = `inspector-${this.streamPartId}`;
|
|
3245
|
+
this.sessions.set(nodeId, session);
|
|
3246
|
+
await this.openInspectConnection(peerDescriptor, lockId);
|
|
3247
|
+
let success = false;
|
|
3248
|
+
try {
|
|
3249
|
+
await utils.waitForEvent(session, 'done', this.inspectionTimeout);
|
|
3250
|
+
success = true;
|
|
3251
|
+
}
|
|
3252
|
+
catch {
|
|
3253
|
+
logger$5.trace('Inspect session timed out, removing');
|
|
3254
|
+
}
|
|
3255
|
+
finally {
|
|
3256
|
+
await this.closeInspectConnection(peerDescriptor, lockId);
|
|
3257
|
+
this.sessions.delete(nodeId);
|
|
3258
|
+
}
|
|
3259
|
+
return success || session.getInspectedMessageCount() < 1 || session.onlyMarkedByInspectedNode();
|
|
3260
|
+
}
|
|
3261
|
+
markMessage(sender, messageId) {
|
|
3262
|
+
this.sessions.forEach((session) => session.markMessage(sender, messageId));
|
|
3263
|
+
}
|
|
3264
|
+
isInspected(nodeId) {
|
|
3265
|
+
return this.sessions.has(nodeId);
|
|
3266
|
+
}
|
|
3267
|
+
stop() {
|
|
3268
|
+
this.sessions.forEach((session) => {
|
|
3269
|
+
session.stop();
|
|
3270
|
+
});
|
|
3271
|
+
this.sessions.clear();
|
|
3272
|
+
}
|
|
3273
|
+
}
|
|
3274
|
+
|
|
3275
|
+
const LOCK_ID_BASE = 'system/content-delivery/temporary-connection/';
|
|
3276
|
+
class TemporaryConnectionRpcLocal {
|
|
3277
|
+
options;
|
|
3278
|
+
temporaryNodes;
|
|
3279
|
+
lockId;
|
|
3280
|
+
constructor(options) {
|
|
3281
|
+
this.options = options;
|
|
3282
|
+
// TODO use options option or named constant?
|
|
3283
|
+
this.temporaryNodes = new NodeList(dht.toNodeId(options.localPeerDescriptor), 10);
|
|
3284
|
+
this.lockId = LOCK_ID_BASE + options.streamPartId;
|
|
3285
|
+
}
|
|
3286
|
+
getNodes() {
|
|
3287
|
+
return this.temporaryNodes;
|
|
3288
|
+
}
|
|
3289
|
+
hasNode(node) {
|
|
3290
|
+
return this.temporaryNodes.has(node);
|
|
3291
|
+
}
|
|
3292
|
+
removeNode(nodeId) {
|
|
3293
|
+
this.temporaryNodes.remove(nodeId);
|
|
3294
|
+
this.options.connectionLocker.weakUnlockConnection(nodeId, this.lockId);
|
|
3295
|
+
}
|
|
3296
|
+
async openConnection(_request, context) {
|
|
3297
|
+
const sender = context.incomingSourceDescriptor;
|
|
3298
|
+
const remote = new ContentDeliveryRpcRemote(this.options.localPeerDescriptor, sender, this.options.rpcCommunicator, ContentDeliveryRpcClient);
|
|
3299
|
+
this.temporaryNodes.add(remote);
|
|
3300
|
+
this.options.connectionLocker.weakLockConnection(dht.toNodeId(sender), this.lockId);
|
|
3301
|
+
return {
|
|
3302
|
+
accepted: true
|
|
3303
|
+
};
|
|
3304
|
+
}
|
|
3305
|
+
async closeConnection(_request, context) {
|
|
3306
|
+
const remoteNodeId = dht.toNodeId(context.incomingSourceDescriptor);
|
|
3307
|
+
this.removeNode(remoteNodeId);
|
|
3308
|
+
return {};
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
|
|
3312
|
+
const formStreamPartContentDeliveryServiceId = (streamPartId) => {
|
|
3313
|
+
// could be "content-delivery" instead of "delivery", but that is a breaking change
|
|
3314
|
+
return `stream-part-delivery-${streamPartId}`;
|
|
3315
|
+
};
|
|
3316
|
+
|
|
3317
|
+
class PlumtreeRpcLocal {
|
|
3318
|
+
neighbors;
|
|
3319
|
+
pausedNodes;
|
|
3320
|
+
onMetadataCb;
|
|
3321
|
+
sendBuffer;
|
|
3322
|
+
constructor(neighbors, pausedNodes, onMetaDataCb, sendBuffer) {
|
|
3323
|
+
this.neighbors = neighbors;
|
|
3324
|
+
this.pausedNodes = pausedNodes;
|
|
3325
|
+
this.onMetadataCb = onMetaDataCb;
|
|
3326
|
+
this.sendBuffer = sendBuffer;
|
|
3327
|
+
}
|
|
3328
|
+
async sendMetadata(message, context) {
|
|
3329
|
+
const previousNode = context.incomingSourceDescriptor;
|
|
3330
|
+
await this.onMetadataCb(message, previousNode);
|
|
3331
|
+
return Empty;
|
|
3332
|
+
}
|
|
3333
|
+
async pauseNeighbor(request, context) {
|
|
3334
|
+
const sender = dht.toNodeId(context.incomingSourceDescriptor);
|
|
3335
|
+
if (this.neighbors.has(sender)) {
|
|
3336
|
+
this.pausedNodes.add(sender, request.messageChainId);
|
|
3337
|
+
}
|
|
3338
|
+
return Empty;
|
|
3339
|
+
}
|
|
3340
|
+
async resumeNeighbor(request, context) {
|
|
3341
|
+
const sender = context.incomingSourceDescriptor;
|
|
3342
|
+
this.pausedNodes.delete(dht.toNodeId(sender), request.messageChainId);
|
|
3343
|
+
await this.sendBuffer(request.fromTimestamp, request.messageChainId, sender);
|
|
3344
|
+
return Empty;
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
class PlumtreeRpcRemote extends dht.RpcRemote {
|
|
3349
|
+
async sendMetadata(msg) {
|
|
3350
|
+
const options = this.formDhtRpcOptions({
|
|
3351
|
+
notification: true
|
|
3352
|
+
});
|
|
3353
|
+
await this.getClient().sendMetadata(msg, options);
|
|
3354
|
+
}
|
|
3355
|
+
async pauseNeighbor(messageChainId) {
|
|
3356
|
+
const options = this.formDhtRpcOptions({
|
|
3357
|
+
notification: true
|
|
3358
|
+
});
|
|
3359
|
+
await this.getClient().pauseNeighbor({ messageChainId }, options);
|
|
3360
|
+
}
|
|
3361
|
+
async resumeNeighbor(fromTimestamp, messageChainId) {
|
|
3362
|
+
const options = this.formDhtRpcOptions({
|
|
3363
|
+
notification: true
|
|
3364
|
+
});
|
|
3365
|
+
await this.getClient().resumeNeighbor({ fromTimestamp, messageChainId }, options);
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
|
|
3369
|
+
class PausedNeighbors {
|
|
3370
|
+
pausedNeighbors;
|
|
3371
|
+
limit;
|
|
3372
|
+
constructor(limit) {
|
|
3373
|
+
this.pausedNeighbors = new Map();
|
|
3374
|
+
this.limit = limit;
|
|
3375
|
+
}
|
|
3376
|
+
add(node, msgChainId) {
|
|
3377
|
+
if (!this.pausedNeighbors.has(msgChainId)) {
|
|
3378
|
+
this.pausedNeighbors.set(msgChainId, new Set());
|
|
3379
|
+
}
|
|
3380
|
+
if (this.pausedNeighbors.get(msgChainId).size >= this.limit) {
|
|
3381
|
+
return;
|
|
3382
|
+
}
|
|
3383
|
+
this.pausedNeighbors.get(msgChainId).add(node);
|
|
3384
|
+
}
|
|
3385
|
+
delete(node, msgChainId) {
|
|
3386
|
+
this.pausedNeighbors.get(msgChainId)?.delete(node);
|
|
3387
|
+
if (this.pausedNeighbors.get(msgChainId)?.size === 0) {
|
|
3388
|
+
this.pausedNeighbors.delete(msgChainId);
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
deleteAll(node) {
|
|
3392
|
+
this.pausedNeighbors.forEach((neighbors, msgChainId) => {
|
|
3393
|
+
neighbors.delete(node);
|
|
3394
|
+
if (neighbors.size === 0) {
|
|
3395
|
+
this.pausedNeighbors.delete(msgChainId);
|
|
3396
|
+
}
|
|
3397
|
+
});
|
|
3398
|
+
}
|
|
3399
|
+
isPaused(node, msgChainId) {
|
|
3400
|
+
if (!this.pausedNeighbors.has(msgChainId)) {
|
|
3401
|
+
return false;
|
|
3402
|
+
}
|
|
3403
|
+
return this.pausedNeighbors.get(msgChainId).has(node);
|
|
3404
|
+
}
|
|
3405
|
+
forEach(fn) {
|
|
3406
|
+
this.pausedNeighbors.forEach((neighbors, msgChainId) => {
|
|
3407
|
+
fn(neighbors, msgChainId);
|
|
3408
|
+
});
|
|
3409
|
+
}
|
|
3410
|
+
size(msgChainId) {
|
|
3411
|
+
return this.pausedNeighbors.get(msgChainId)?.size ?? 0;
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
3414
|
+
|
|
3415
|
+
const MAX_PAUSED_NEIGHBORS_DEFAULT = 3;
|
|
3416
|
+
const logger$4 = new utils.Logger('PlumtreeManager');
|
|
3417
|
+
class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
3418
|
+
neighbors;
|
|
3419
|
+
localPeerDescriptor;
|
|
3420
|
+
// We have paused sending real data to these neighbrs and only send metadata
|
|
3421
|
+
localPausedNeighbors;
|
|
3422
|
+
// We have asked these nodes to pause sending real data to us, used to limit sending of pausing and resuming requests
|
|
3423
|
+
remotePausedNeighbors;
|
|
3424
|
+
rpcLocal;
|
|
3425
|
+
latestMessages = new Map();
|
|
3426
|
+
rpcCommunicator;
|
|
3427
|
+
metadataTimestampsAheadOfRealData = new Map();
|
|
3428
|
+
maxPausedNeighbors;
|
|
3429
|
+
constructor(options) {
|
|
3430
|
+
super();
|
|
3431
|
+
this.neighbors = options.neighbors;
|
|
3432
|
+
this.maxPausedNeighbors = options.maxPausedNeighbors ?? MAX_PAUSED_NEIGHBORS_DEFAULT;
|
|
3433
|
+
this.localPeerDescriptor = options.localPeerDescriptor;
|
|
3434
|
+
this.localPausedNeighbors = new PausedNeighbors(options.maxPausedNeighbors ?? MAX_PAUSED_NEIGHBORS_DEFAULT);
|
|
3435
|
+
this.remotePausedNeighbors = new PausedNeighbors(options.maxPausedNeighbors ?? MAX_PAUSED_NEIGHBORS_DEFAULT);
|
|
3436
|
+
this.rpcLocal = new PlumtreeRpcLocal(this.neighbors, this.localPausedNeighbors, (metadata, previousNode) => this.onMetadata(metadata, previousNode), (fromTimestamp, msgChainId, remotePeerDescriptor) => this.sendBuffer(fromTimestamp, msgChainId, remotePeerDescriptor));
|
|
3437
|
+
this.neighbors.on('nodeRemoved', (nodeId) => this.onNeighborRemoved(nodeId));
|
|
3438
|
+
this.rpcCommunicator = options.rpcCommunicator;
|
|
3439
|
+
this.rpcCommunicator.registerRpcNotification(MessageID, 'sendMetadata', (msg, context) => this.rpcLocal.sendMetadata(msg, context));
|
|
3440
|
+
this.rpcCommunicator.registerRpcNotification(PauseNeighborRequest, 'pauseNeighbor', (msg, context) => this.rpcLocal.pauseNeighbor(msg, context));
|
|
3441
|
+
this.rpcCommunicator.registerRpcNotification(ResumeNeighborRequest, 'resumeNeighbor', (msg, context) => this.rpcLocal.resumeNeighbor(msg, context));
|
|
3442
|
+
}
|
|
3443
|
+
async pauseNeighbor(node, msgChainId) {
|
|
3444
|
+
if (this.neighbors.has(dht.toNodeId(node))
|
|
3445
|
+
&& !this.remotePausedNeighbors.isPaused(dht.toNodeId(node), msgChainId)
|
|
3446
|
+
&& this.remotePausedNeighbors.size(msgChainId) < this.maxPausedNeighbors) {
|
|
3447
|
+
logger$4.debug(`Pausing neighbor ${dht.toNodeId(node)}`);
|
|
3448
|
+
this.remotePausedNeighbors.add(dht.toNodeId(node), msgChainId);
|
|
3449
|
+
const remote = this.createRemote(node);
|
|
3450
|
+
await remote.pauseNeighbor(msgChainId);
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
async resumeNeighbor(node, msgChainId, fromTimestamp) {
|
|
3454
|
+
if (this.remotePausedNeighbors.isPaused(dht.toNodeId(node), msgChainId)) {
|
|
3455
|
+
logger$4.debug(`Resuming neighbor ${dht.toNodeId(node)}`);
|
|
3456
|
+
this.remotePausedNeighbors.delete(dht.toNodeId(node), msgChainId);
|
|
3457
|
+
const remote = this.createRemote(node);
|
|
3458
|
+
await remote.resumeNeighbor(fromTimestamp, msgChainId);
|
|
3459
|
+
}
|
|
3460
|
+
}
|
|
3461
|
+
onNeighborRemoved(nodeId) {
|
|
3462
|
+
this.localPausedNeighbors.deleteAll(nodeId);
|
|
3463
|
+
this.remotePausedNeighbors.deleteAll(nodeId);
|
|
3464
|
+
if (this.neighbors.size() > 0) {
|
|
3465
|
+
this.remotePausedNeighbors.forEach((pausedNeighbors, msgChainId) => {
|
|
3466
|
+
if (pausedNeighbors.size >= this.neighbors.size()) {
|
|
3467
|
+
logger$4.debug('All neighbors are paused, resuming first neighbor');
|
|
3468
|
+
const neighborToResume = this.neighbors.getFirst([]).getPeerDescriptor();
|
|
3469
|
+
setImmediate(() => this.resumeNeighbor(neighborToResume, msgChainId, this.getLatestMessageTimestamp(msgChainId)));
|
|
3470
|
+
}
|
|
3471
|
+
});
|
|
3472
|
+
}
|
|
3473
|
+
}
|
|
3474
|
+
getLatestMessageTimestamp(msgChainId) {
|
|
3475
|
+
if (!this.latestMessages.has(msgChainId) || this.latestMessages.get(msgChainId).length === 0) {
|
|
3476
|
+
return 0;
|
|
3477
|
+
}
|
|
3478
|
+
return this.latestMessages.get(msgChainId)[this.latestMessages.get(msgChainId).length - 1].messageId.timestamp;
|
|
3479
|
+
}
|
|
3480
|
+
async sendBuffer(fromTimestamp, msgChainId, neighbor) {
|
|
3481
|
+
const remote = new ContentDeliveryRpcRemote(this.localPeerDescriptor, neighbor, this.rpcCommunicator, ContentDeliveryRpcClient);
|
|
3482
|
+
const messages = this.latestMessages.get(msgChainId)?.filter((msg) => msg.messageId.timestamp > fromTimestamp) ?? [];
|
|
3483
|
+
await Promise.all(messages.map((msg) => remote.sendStreamMessage(msg)));
|
|
3484
|
+
}
|
|
3485
|
+
async onMetadata(msg, previousNode) {
|
|
3486
|
+
// If we receive newer metadata than messages in the buffer, resume the sending neighbor
|
|
3487
|
+
const latestMessageTimestamp = this.getLatestMessageTimestamp(msg.messageChainId);
|
|
3488
|
+
if (latestMessageTimestamp < msg.timestamp) {
|
|
3489
|
+
if (!this.metadataTimestampsAheadOfRealData.has(msg.messageChainId)) {
|
|
3490
|
+
this.metadataTimestampsAheadOfRealData.set(msg.messageChainId, new Set());
|
|
3491
|
+
}
|
|
3492
|
+
this.metadataTimestampsAheadOfRealData.get(msg.messageChainId).add(msg.timestamp);
|
|
3493
|
+
if (this.metadataTimestampsAheadOfRealData.get(msg.messageChainId).size > 1) {
|
|
3494
|
+
await this.resumeNeighbor(previousNode, msg.messageChainId, this.getLatestMessageTimestamp(msg.messageChainId));
|
|
3495
|
+
this.metadataTimestampsAheadOfRealData.get(msg.messageChainId).forEach((timestamp) => {
|
|
3496
|
+
this.metadataTimestampsAheadOfRealData.get(msg.messageChainId).delete(timestamp);
|
|
3497
|
+
});
|
|
3498
|
+
}
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
createRemote(neighbor) {
|
|
3502
|
+
return new PlumtreeRpcRemote(this.localPeerDescriptor, neighbor, this.rpcCommunicator, PlumtreeRpcClient);
|
|
3503
|
+
}
|
|
3504
|
+
broadcast(msg, previousNode) {
|
|
3505
|
+
const messageChainId = msg.messageId.messageChainId;
|
|
3506
|
+
if (!this.latestMessages.has(messageChainId)) {
|
|
3507
|
+
this.latestMessages.set(messageChainId, []);
|
|
3508
|
+
}
|
|
3509
|
+
if (this.latestMessages.get(messageChainId).length < 20) {
|
|
3510
|
+
this.latestMessages.get(messageChainId).push(msg);
|
|
3511
|
+
}
|
|
3512
|
+
else {
|
|
3513
|
+
this.latestMessages.get(messageChainId).shift();
|
|
3514
|
+
this.latestMessages.get(messageChainId).push(msg);
|
|
3515
|
+
}
|
|
3516
|
+
if (this.metadataTimestampsAheadOfRealData.has(msg.messageId.messageChainId)) {
|
|
3517
|
+
this.metadataTimestampsAheadOfRealData.get(msg.messageId.messageChainId).delete(msg.messageId.timestamp);
|
|
3518
|
+
}
|
|
3519
|
+
this.emit('message', msg);
|
|
3520
|
+
const neighbors = this.neighbors.getAll().filter((neighbor) => dht.toNodeId(neighbor.getPeerDescriptor()) !== previousNode);
|
|
3521
|
+
for (const neighbor of neighbors) {
|
|
3522
|
+
if (this.localPausedNeighbors.isPaused(dht.toNodeId(neighbor.getPeerDescriptor()), msg.messageId.messageChainId)) {
|
|
3523
|
+
const remote = this.createRemote(neighbor.getPeerDescriptor());
|
|
3524
|
+
setImmediate(() => remote.sendMetadata(msg.messageId));
|
|
3525
|
+
}
|
|
3526
|
+
else {
|
|
3527
|
+
setImmediate(() => neighbor.sendStreamMessage(msg));
|
|
3528
|
+
}
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
isNeighborPaused(node, msgChainId) {
|
|
3532
|
+
return this.localPausedNeighbors.isPaused(dht.toNodeId(node), msgChainId)
|
|
3533
|
+
|| this.remotePausedNeighbors.isPaused(dht.toNodeId(node), msgChainId);
|
|
3534
|
+
}
|
|
3535
|
+
stop() {
|
|
3536
|
+
this.neighbors.off('nodeRemoved', this.onNeighborRemoved);
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
|
|
3540
|
+
const createConfigWithDefaults = (options) => {
|
|
3541
|
+
const ownNodeId = dht.toNodeId(options.localPeerDescriptor);
|
|
3542
|
+
const rpcCommunicator = options.rpcCommunicator ?? new dht.ListeningRpcCommunicator(formStreamPartContentDeliveryServiceId(options.streamPartId), options.transport);
|
|
3543
|
+
const neighborTargetCount = options.neighborTargetCount ?? DEFAULT_NEIGHBOR_TARGET_COUNT;
|
|
3544
|
+
const maxContactCount = options.maxContactCount ?? DEFAULT_NODE_VIEW_SIZE;
|
|
3545
|
+
const acceptProxyConnections = options.acceptProxyConnections ?? DEFAULT_ACCEPT_PROXY_CONNECTIONS;
|
|
3546
|
+
const neighborUpdateInterval = options.neighborUpdateInterval ?? DEFAULT_NEIGHBOR_UPDATE_INTERVAL;
|
|
3547
|
+
const minPropagationTargets = options.minPropagationTargets ?? DEFAULT_MIN_PROPAGATION_TARGETS;
|
|
3548
|
+
const maxPropagationBufferSize = options.maxPropagationBufferSize ?? DEFAULT_MAX_PROPAGATION_BUFFER_SIZE;
|
|
3549
|
+
const neighbors = options.neighbors ?? new NodeList(ownNodeId, maxContactCount);
|
|
3550
|
+
const leftNodeView = options.leftNodeView ?? new NodeList(ownNodeId, maxContactCount);
|
|
3551
|
+
const rightNodeView = options.rightNodeView ?? new NodeList(ownNodeId, maxContactCount);
|
|
3552
|
+
const nearbyNodeView = options.nearbyNodeView ?? new NodeList(ownNodeId, maxContactCount);
|
|
3553
|
+
const randomNodeView = options.randomNodeView ?? new NodeList(ownNodeId, maxContactCount);
|
|
3554
|
+
const ongoingHandshakes = new Set();
|
|
3555
|
+
const temporaryConnectionRpcLocal = new TemporaryConnectionRpcLocal({
|
|
3556
|
+
rpcCommunicator,
|
|
3557
|
+
localPeerDescriptor: options.localPeerDescriptor,
|
|
3558
|
+
streamPartId: options.streamPartId,
|
|
3559
|
+
connectionLocker: options.connectionLocker
|
|
3560
|
+
});
|
|
3561
|
+
const proxyConnectionRpcLocal = acceptProxyConnections ? new ProxyConnectionRpcLocal({
|
|
3562
|
+
localPeerDescriptor: options.localPeerDescriptor,
|
|
3563
|
+
streamPartId: options.streamPartId,
|
|
3564
|
+
rpcCommunicator
|
|
3565
|
+
}) : undefined;
|
|
3566
|
+
const plumtreeManager = options.plumtreeOptimization ? new PlumtreeManager({
|
|
3567
|
+
neighbors,
|
|
3568
|
+
localPeerDescriptor: options.localPeerDescriptor,
|
|
3569
|
+
rpcCommunicator,
|
|
3570
|
+
maxPausedNeighbors: options.plumtreeMaxPausedNeighbors
|
|
3571
|
+
}) : undefined;
|
|
3572
|
+
const propagation = options.propagation ?? new Propagation({
|
|
3573
|
+
minPropagationTargets,
|
|
3574
|
+
maxMessages: maxPropagationBufferSize,
|
|
3575
|
+
ttl: DEFAULT_PROPAGATION_BUFFER_TTL,
|
|
3576
|
+
sendToNeighbor: async (neighborId, msg) => {
|
|
3577
|
+
const remote = neighbors.get(neighborId) ?? temporaryConnectionRpcLocal.getNodes().get(neighborId);
|
|
3578
|
+
const proxyConnection = proxyConnectionRpcLocal?.getConnection(neighborId);
|
|
3579
|
+
if (remote) {
|
|
3580
|
+
await remote.sendStreamMessage(msg, options.bufferWhileConnecting);
|
|
3581
|
+
}
|
|
3582
|
+
else if (proxyConnection) {
|
|
3583
|
+
await proxyConnection.remote.sendStreamMessage(msg);
|
|
3584
|
+
}
|
|
3585
|
+
else {
|
|
3586
|
+
throw new Error('Propagation target not found');
|
|
3587
|
+
}
|
|
3588
|
+
}
|
|
3589
|
+
});
|
|
3590
|
+
const handshaker = options.handshaker ?? new Handshaker({
|
|
3591
|
+
localPeerDescriptor: options.localPeerDescriptor,
|
|
3592
|
+
streamPartId: options.streamPartId,
|
|
3593
|
+
rpcCommunicator,
|
|
3594
|
+
neighbors,
|
|
3595
|
+
leftNodeView,
|
|
3596
|
+
rightNodeView,
|
|
3597
|
+
nearbyNodeView,
|
|
3598
|
+
randomNodeView,
|
|
3599
|
+
maxNeighborCount: neighborTargetCount,
|
|
3600
|
+
rpcRequestTimeout: options.rpcRequestTimeout,
|
|
3601
|
+
ongoingHandshakes
|
|
3602
|
+
});
|
|
3603
|
+
const neighborFinder = options.neighborFinder ?? new NeighborFinder({
|
|
3604
|
+
neighbors,
|
|
3605
|
+
leftNodeView,
|
|
3606
|
+
rightNodeView,
|
|
3607
|
+
nearbyNodeView,
|
|
3608
|
+
randomNodeView,
|
|
3609
|
+
doFindNeighbors: (excludedIds) => handshaker.attemptHandshakesOnContacts(excludedIds),
|
|
3610
|
+
minCount: neighborTargetCount
|
|
3611
|
+
});
|
|
3612
|
+
const neighborUpdateManager = options.neighborUpdateManager ?? new NeighborUpdateManager({
|
|
3613
|
+
neighbors,
|
|
3614
|
+
nearbyNodeView,
|
|
3615
|
+
localPeerDescriptor: options.localPeerDescriptor,
|
|
3616
|
+
neighborFinder,
|
|
3617
|
+
streamPartId: options.streamPartId,
|
|
3618
|
+
rpcCommunicator,
|
|
3619
|
+
neighborUpdateInterval,
|
|
3620
|
+
neighborTargetCount,
|
|
3621
|
+
ongoingHandshakes
|
|
3622
|
+
});
|
|
3623
|
+
const inspector = options.inspector ?? new Inspector({
|
|
3624
|
+
localPeerDescriptor: options.localPeerDescriptor,
|
|
3625
|
+
rpcCommunicator,
|
|
3626
|
+
streamPartId: options.streamPartId,
|
|
3627
|
+
connectionLocker: options.connectionLocker
|
|
3628
|
+
});
|
|
3629
|
+
return {
|
|
3630
|
+
...options,
|
|
3631
|
+
neighbors,
|
|
3632
|
+
leftNodeView,
|
|
3633
|
+
rightNodeView,
|
|
3634
|
+
nearbyNodeView,
|
|
3635
|
+
randomNodeView,
|
|
3636
|
+
rpcCommunicator,
|
|
3637
|
+
handshaker,
|
|
3638
|
+
neighborFinder,
|
|
3639
|
+
neighborUpdateManager,
|
|
3640
|
+
propagation,
|
|
3641
|
+
neighborTargetCount,
|
|
3642
|
+
nodeViewSize: maxContactCount,
|
|
3643
|
+
proxyConnectionRpcLocal,
|
|
3644
|
+
inspector,
|
|
3645
|
+
temporaryConnectionRpcLocal,
|
|
3646
|
+
plumtreeManager
|
|
3647
|
+
};
|
|
3648
|
+
};
|
|
3649
|
+
const createContentDeliveryLayerNode = (options) => {
|
|
3650
|
+
return new ContentDeliveryLayerNode(createConfigWithDefaults(options));
|
|
3651
|
+
};
|
|
3652
|
+
|
|
3653
|
+
const logger$3 = new utils.Logger('ProxyConnectionRpcRemote');
|
|
3654
|
+
class ProxyConnectionRpcRemote extends dht.RpcRemote {
|
|
3655
|
+
async requestConnection(userId, direction) {
|
|
3656
|
+
const request = {
|
|
3657
|
+
direction,
|
|
3658
|
+
userId: utils.toUserIdRaw(userId)
|
|
3659
|
+
};
|
|
3660
|
+
const options = this.formDhtRpcOptions({
|
|
3661
|
+
timeout: dht.EXISTING_CONNECTION_TIMEOUT
|
|
3662
|
+
});
|
|
3663
|
+
try {
|
|
3664
|
+
const res = await this.getClient().requestConnection(request, options);
|
|
3665
|
+
return res.accepted;
|
|
3666
|
+
}
|
|
3667
|
+
catch (err) {
|
|
3668
|
+
logger$3.debug(`ProxyConnectionRequest failed with error`, { err });
|
|
3669
|
+
return false;
|
|
3670
|
+
}
|
|
3671
|
+
}
|
|
3672
|
+
}
|
|
3673
|
+
|
|
3674
|
+
// TODO use options option or named constant?
|
|
3675
|
+
const retry = async (task, description, abortSignal, delay = 10000) => {
|
|
3676
|
+
while (true) {
|
|
3677
|
+
try {
|
|
3678
|
+
const result = await task();
|
|
3679
|
+
return result;
|
|
3680
|
+
}
|
|
3681
|
+
catch {
|
|
3682
|
+
logger$2.warn(`Failed ${description} (retrying after delay)`, {
|
|
3683
|
+
delayInMs: delay
|
|
3684
|
+
});
|
|
3685
|
+
}
|
|
3686
|
+
await utils.wait(delay, abortSignal);
|
|
3687
|
+
}
|
|
3688
|
+
};
|
|
3689
|
+
const logger$2 = new utils.Logger('ProxyClient');
|
|
3690
|
+
const SERVICE_ID = 'system/proxy-client';
|
|
3691
|
+
class ProxyClient extends eventemitter3.EventEmitter {
|
|
3692
|
+
rpcCommunicator;
|
|
3693
|
+
contentDeliveryRpcLocal;
|
|
3694
|
+
options;
|
|
3695
|
+
duplicateDetectors = new Map();
|
|
3696
|
+
definition;
|
|
3697
|
+
connections = new Map();
|
|
3698
|
+
propagation;
|
|
3699
|
+
neighbors;
|
|
3700
|
+
abortController;
|
|
3701
|
+
constructor(options) {
|
|
3702
|
+
super();
|
|
3703
|
+
this.options = options;
|
|
3704
|
+
this.rpcCommunicator = new dht.ListeningRpcCommunicator(formStreamPartContentDeliveryServiceId(options.streamPartId), options.transport);
|
|
3705
|
+
// TODO use options option or named constant?
|
|
3706
|
+
this.neighbors = new NodeList(dht.toNodeId(this.options.localPeerDescriptor), 1000);
|
|
3707
|
+
this.contentDeliveryRpcLocal = new ContentDeliveryRpcLocal({
|
|
3708
|
+
localPeerDescriptor: this.options.localPeerDescriptor,
|
|
3709
|
+
streamPartId: this.options.streamPartId,
|
|
3710
|
+
markAndCheckDuplicate: (msg, prev) => markAndCheckDuplicate(this.duplicateDetectors, msg, prev),
|
|
3711
|
+
broadcast: (message, previousNode) => this.broadcast(message, previousNode),
|
|
3712
|
+
onLeaveNotice: (remoteNodeId) => {
|
|
3713
|
+
const contact = this.neighbors.get(remoteNodeId);
|
|
3714
|
+
if (contact) {
|
|
3715
|
+
// TODO should we catch possible promise rejection?
|
|
3716
|
+
setImmediate(() => this.onNodeDisconnected(contact.getPeerDescriptor()));
|
|
3717
|
+
}
|
|
3718
|
+
},
|
|
3719
|
+
rpcCommunicator: this.rpcCommunicator,
|
|
3720
|
+
markForInspection: () => { }
|
|
3721
|
+
});
|
|
3722
|
+
this.propagation = new Propagation({
|
|
3723
|
+
minPropagationTargets: options.minPropagationTargets,
|
|
3724
|
+
maxMessages: options.maxPropagationBufferSize,
|
|
3725
|
+
ttl: options.propagationBufferTtl,
|
|
3726
|
+
sendToNeighbor: async (neighborId, msg) => {
|
|
3727
|
+
const remote = this.neighbors.get(neighborId);
|
|
3728
|
+
if (remote) {
|
|
3729
|
+
await remote.sendStreamMessage(msg);
|
|
3730
|
+
}
|
|
3731
|
+
else {
|
|
3732
|
+
throw new Error('Propagation target not found');
|
|
3733
|
+
}
|
|
3734
|
+
}
|
|
3735
|
+
});
|
|
3736
|
+
this.abortController = new AbortController();
|
|
3737
|
+
}
|
|
3738
|
+
registerDefaultServerMethods() {
|
|
3739
|
+
this.rpcCommunicator.registerRpcNotification(StreamMessage, 'sendStreamMessage', (msg, context) => this.contentDeliveryRpcLocal.sendStreamMessage(msg, context));
|
|
3740
|
+
this.rpcCommunicator.registerRpcNotification(LeaveStreamPartNotice, 'leaveStreamPartNotice', (req, context) => this.contentDeliveryRpcLocal.leaveStreamPartNotice(req, context));
|
|
3741
|
+
}
|
|
3742
|
+
async setProxies(nodes, userId, direction, connectionCount) {
|
|
3743
|
+
logger$2.trace('Setting proxies', { streamPartId: this.options.streamPartId, peerDescriptors: nodes, direction, userId, connectionCount });
|
|
3744
|
+
if (connectionCount !== undefined && connectionCount > nodes.length) {
|
|
3745
|
+
throw new Error('Cannot set connectionCount above the size of the configured array of nodes');
|
|
3746
|
+
}
|
|
3747
|
+
const nodesIds = new Map();
|
|
3748
|
+
nodes.forEach((peerDescriptor) => {
|
|
3749
|
+
nodesIds.set(dht.toNodeId(peerDescriptor), peerDescriptor);
|
|
3750
|
+
});
|
|
3751
|
+
this.definition = {
|
|
3752
|
+
nodes: nodesIds,
|
|
3753
|
+
userId,
|
|
3754
|
+
direction,
|
|
3755
|
+
connectionCount: connectionCount ?? nodes.length
|
|
3756
|
+
};
|
|
3757
|
+
await this.updateConnections();
|
|
3758
|
+
}
|
|
3759
|
+
async updateConnections() {
|
|
3760
|
+
await Promise.all(this.getInvalidConnections().map(async (id) => {
|
|
3761
|
+
await this.closeConnection(id);
|
|
3762
|
+
}));
|
|
3763
|
+
const connectionCountDiff = this.definition.connectionCount - this.connections.size;
|
|
3764
|
+
if (connectionCountDiff > 0) {
|
|
3765
|
+
await this.openRandomConnections(connectionCountDiff);
|
|
3766
|
+
}
|
|
3767
|
+
else if (connectionCountDiff < 0) {
|
|
3768
|
+
await this.closeRandomConnections(-connectionCountDiff);
|
|
3769
|
+
}
|
|
3770
|
+
}
|
|
3771
|
+
getInvalidConnections() {
|
|
3772
|
+
return Array.from(this.connections.keys()).filter((id) => {
|
|
3773
|
+
return !this.definition.nodes.has(id)
|
|
3774
|
+
|| this.definition.direction !== this.connections.get(id).direction;
|
|
3775
|
+
});
|
|
3776
|
+
}
|
|
3777
|
+
async openRandomConnections(connectionCount) {
|
|
3778
|
+
const proxiesToAttempt = sampleSize(Array.from(this.definition.nodes.keys()).filter((id) => !this.connections.has(id)), connectionCount);
|
|
3779
|
+
await Promise.all(proxiesToAttempt.map((id) => this.attemptConnection(id, this.definition.userId, this.definition.direction)));
|
|
3780
|
+
}
|
|
3781
|
+
async attemptConnection(nodeId, userId, direction) {
|
|
3782
|
+
const peerDescriptor = this.definition.nodes.get(nodeId);
|
|
3783
|
+
const rpcRemote = new ProxyConnectionRpcRemote(this.options.localPeerDescriptor, peerDescriptor, this.rpcCommunicator, ProxyConnectionRpcClient);
|
|
3784
|
+
const accepted = await rpcRemote.requestConnection(userId, direction);
|
|
3785
|
+
if (accepted) {
|
|
3786
|
+
this.options.connectionLocker.lockConnection(peerDescriptor, SERVICE_ID);
|
|
3787
|
+
this.connections.set(nodeId, { peerDescriptor, direction });
|
|
3788
|
+
const remote = new ContentDeliveryRpcRemote(this.options.localPeerDescriptor, peerDescriptor, this.rpcCommunicator, ContentDeliveryRpcClient);
|
|
3789
|
+
this.neighbors.add(remote);
|
|
3790
|
+
this.propagation.onNeighborJoined(nodeId);
|
|
3791
|
+
logger$2.info('Open proxy connection', {
|
|
3792
|
+
nodeId,
|
|
3793
|
+
streamPartId: this.options.streamPartId
|
|
3794
|
+
});
|
|
3795
|
+
}
|
|
3796
|
+
else {
|
|
3797
|
+
logger$2.warn('Unable to open proxy connection', {
|
|
3798
|
+
nodeId,
|
|
3799
|
+
streamPartId: this.options.streamPartId
|
|
3800
|
+
});
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
async closeRandomConnections(connectionCount) {
|
|
3804
|
+
const proxiesToDisconnect = sampleSize(Array.from(this.connections.keys()), connectionCount);
|
|
3805
|
+
await Promise.allSettled(proxiesToDisconnect.map((node) => this.closeConnection(node)));
|
|
3806
|
+
}
|
|
3807
|
+
async closeConnection(nodeId) {
|
|
3808
|
+
if (this.connections.has(nodeId)) {
|
|
3809
|
+
logger$2.info('Close proxy connection', {
|
|
3810
|
+
nodeId
|
|
3811
|
+
});
|
|
3812
|
+
const server = this.neighbors.get(nodeId);
|
|
3813
|
+
server?.leaveStreamPartNotice(this.options.streamPartId, false);
|
|
3814
|
+
this.removeConnection(this.connections.get(nodeId).peerDescriptor);
|
|
3815
|
+
}
|
|
3816
|
+
}
|
|
3817
|
+
removeConnection(peerDescriptor) {
|
|
3818
|
+
const nodeId = dht.toNodeId(peerDescriptor);
|
|
3819
|
+
this.connections.delete(nodeId);
|
|
3820
|
+
this.neighbors.remove(nodeId);
|
|
3821
|
+
this.options.connectionLocker.unlockConnection(peerDescriptor, SERVICE_ID);
|
|
3822
|
+
}
|
|
3823
|
+
broadcast(msg, previousNode) {
|
|
3824
|
+
if (!previousNode) {
|
|
3825
|
+
markAndCheckDuplicate(this.duplicateDetectors, msg.messageId, msg.previousMessageRef);
|
|
3826
|
+
}
|
|
3827
|
+
this.emit('message', msg);
|
|
3828
|
+
this.propagation.feedUnseenMessage(msg, this.neighbors.getIds(), previousNode ?? null);
|
|
3829
|
+
}
|
|
3830
|
+
hasConnection(nodeId, direction) {
|
|
3831
|
+
return this.connections.has(nodeId) && this.connections.get(nodeId).direction === direction;
|
|
3832
|
+
}
|
|
3833
|
+
getDirection() {
|
|
3834
|
+
return this.definition.direction;
|
|
3835
|
+
}
|
|
3836
|
+
async onNodeDisconnected(peerDescriptor) {
|
|
3837
|
+
const nodeId = dht.toNodeId(peerDescriptor);
|
|
3838
|
+
if (this.connections.has(nodeId)) {
|
|
3839
|
+
this.options.connectionLocker.unlockConnection(peerDescriptor, SERVICE_ID);
|
|
3840
|
+
this.removeConnection(peerDescriptor);
|
|
3841
|
+
await retry(() => this.updateConnections(), 'updating proxy connections', this.abortController.signal);
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
3844
|
+
async start() {
|
|
3845
|
+
this.registerDefaultServerMethods();
|
|
3846
|
+
utils.addManagedEventListener(this.options.transport, 'disconnected',
|
|
3847
|
+
// TODO should we catch possible promise rejection?
|
|
3848
|
+
(peerDescriptor) => this.onNodeDisconnected(peerDescriptor), this.abortController.signal);
|
|
3849
|
+
}
|
|
3850
|
+
getDiagnosticInfo() {
|
|
3851
|
+
return {
|
|
3852
|
+
neighbors: this.neighbors.getAll().map((neighbor) => neighbor.getPeerDescriptor()),
|
|
3853
|
+
};
|
|
3854
|
+
}
|
|
3855
|
+
stop() {
|
|
3856
|
+
this.neighbors.getAll().forEach((remote) => {
|
|
3857
|
+
this.options.connectionLocker.unlockConnection(remote.getPeerDescriptor(), SERVICE_ID);
|
|
3858
|
+
remote.leaveStreamPartNotice(this.options.streamPartId, false);
|
|
3859
|
+
});
|
|
3860
|
+
this.neighbors.stop();
|
|
3861
|
+
this.rpcCommunicator.destroy();
|
|
3862
|
+
this.connections.clear();
|
|
3863
|
+
this.abortController.abort();
|
|
3864
|
+
}
|
|
3865
|
+
}
|
|
3866
|
+
|
|
3867
|
+
const logger$1 = new utils.Logger('ContentDeliveryManager');
|
|
3868
|
+
const streamPartIdToDataKey = (streamPartId) => {
|
|
3869
|
+
return dht.toDhtAddress(utils.computeSha1(streamPartId));
|
|
3870
|
+
};
|
|
3871
|
+
class ContentDeliveryManager extends eventemitter3.EventEmitter {
|
|
3872
|
+
transport;
|
|
3873
|
+
connectionLocker;
|
|
3874
|
+
controlLayerNode;
|
|
3875
|
+
metricsContext;
|
|
3876
|
+
metrics;
|
|
3877
|
+
options;
|
|
3878
|
+
streamParts;
|
|
3879
|
+
knownStreamPartEntryPoints = new Map();
|
|
3880
|
+
started = false;
|
|
3881
|
+
destroyed = false;
|
|
3882
|
+
constructor(options) {
|
|
3883
|
+
super();
|
|
3884
|
+
this.options = options;
|
|
3885
|
+
this.streamParts = new Map();
|
|
3886
|
+
this.metricsContext = options.metricsContext ?? new utils.MetricsContext();
|
|
3887
|
+
this.metrics = {
|
|
3888
|
+
broadcastMessagesPerSecond: new utils.RateMetric(),
|
|
3889
|
+
broadcastBytesPerSecond: new utils.RateMetric()
|
|
3890
|
+
};
|
|
3891
|
+
this.metricsContext.addMetrics('node', this.metrics);
|
|
3892
|
+
}
|
|
3893
|
+
async start(startedAndJoinedControlLayerNode, transport, connectionLocker) {
|
|
3894
|
+
if (this.started || this.destroyed) {
|
|
3895
|
+
return;
|
|
3896
|
+
}
|
|
3897
|
+
this.started = true;
|
|
3898
|
+
this.controlLayerNode = startedAndJoinedControlLayerNode;
|
|
3899
|
+
this.transport = transport;
|
|
3900
|
+
this.connectionLocker = connectionLocker;
|
|
3901
|
+
}
|
|
3902
|
+
async destroy() {
|
|
3903
|
+
if (!this.started || this.destroyed) {
|
|
3904
|
+
return;
|
|
3905
|
+
}
|
|
3906
|
+
logger$1.trace('Destroying ContentDeliveryManager');
|
|
3907
|
+
this.destroyed = true;
|
|
3908
|
+
await Promise.all(Array.from(this.streamParts.values()).map((streamPart) => streamPart.stop()));
|
|
3909
|
+
this.streamParts.clear();
|
|
3910
|
+
this.removeAllListeners();
|
|
3911
|
+
this.controlLayerNode = undefined;
|
|
3912
|
+
this.transport = undefined;
|
|
3913
|
+
this.connectionLocker = undefined;
|
|
3914
|
+
}
|
|
3915
|
+
broadcast(msg, streamPartDeliveryOptions) {
|
|
3916
|
+
const streamPartId = utils.toStreamPartID(msg.messageId.streamId, msg.messageId.streamPartition);
|
|
3917
|
+
logger$1.debug(`Broadcasting to stream part ${streamPartId}`);
|
|
3918
|
+
this.joinStreamPart(streamPartId, streamPartDeliveryOptions);
|
|
3919
|
+
this.streamParts.get(streamPartId).broadcast(msg);
|
|
3920
|
+
if (msg.body.oneofKind === 'contentMessage') {
|
|
3921
|
+
this.metrics.broadcastMessagesPerSecond.record(1);
|
|
3922
|
+
this.metrics.broadcastBytesPerSecond.record(msg.body.contentMessage.content.length);
|
|
3923
|
+
}
|
|
3924
|
+
}
|
|
3925
|
+
async leaveStreamPart(streamPartId) {
|
|
3926
|
+
const streamPart = this.streamParts.get(streamPartId);
|
|
3927
|
+
if (streamPart) {
|
|
3928
|
+
await streamPart.stop();
|
|
3929
|
+
this.streamParts.delete(streamPartId);
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
joinStreamPart(streamPartId, streamPartDeliveryOptions) {
|
|
3933
|
+
let streamPart = this.streamParts.get(streamPartId);
|
|
3934
|
+
if (streamPart !== undefined) {
|
|
3935
|
+
return;
|
|
3936
|
+
}
|
|
3937
|
+
logger$1.debug(`Join stream part ${streamPartId}`);
|
|
3938
|
+
const discoveryLayerNode = this.createDiscoveryLayerNode(streamPartId, this.knownStreamPartEntryPoints.get(streamPartId) ?? []);
|
|
3939
|
+
const peerDescriptorStoreManager = new PeerDescriptorStoreManager({
|
|
3940
|
+
key: streamPartIdToDataKey(streamPartId),
|
|
3941
|
+
localPeerDescriptor: this.getPeerDescriptor(),
|
|
3942
|
+
fetchDataFromDht: (key) => this.controlLayerNode.fetchDataFromDht(key),
|
|
3943
|
+
storeDataToDht: (key, data) => this.controlLayerNode.storeDataToDht(key, data),
|
|
3944
|
+
deleteDataFromDht: async (key, waitForCompletion) => this.controlLayerNode.deleteDataFromDht(key, waitForCompletion)
|
|
3945
|
+
});
|
|
3946
|
+
const networkSplitAvoidance = new StreamPartNetworkSplitAvoidance({
|
|
3947
|
+
discoveryLayerNode,
|
|
3948
|
+
discoverEntryPoints: async () => peerDescriptorStoreManager.fetchNodes()
|
|
3949
|
+
});
|
|
3950
|
+
const node = this.createContentDeliveryLayerNode(streamPartId, discoveryLayerNode, () => peerDescriptorStoreManager.isLocalNodeStored(), streamPartDeliveryOptions);
|
|
3951
|
+
const streamPartReconnect = new StreamPartReconnect(discoveryLayerNode, peerDescriptorStoreManager);
|
|
3952
|
+
streamPart = {
|
|
3953
|
+
proxied: false,
|
|
3954
|
+
discoveryLayerNode,
|
|
3955
|
+
node,
|
|
3956
|
+
networkSplitAvoidance,
|
|
3957
|
+
broadcast: (msg) => node.broadcast(msg),
|
|
3958
|
+
stop: async () => {
|
|
3959
|
+
streamPartReconnect.destroy();
|
|
3960
|
+
networkSplitAvoidance.destroy();
|
|
3961
|
+
await peerDescriptorStoreManager.destroy();
|
|
3962
|
+
node.stop();
|
|
3963
|
+
await discoveryLayerNode.stop();
|
|
3964
|
+
},
|
|
3965
|
+
getDiagnosticInfo: () => node.getDiagnosticInfo()
|
|
3966
|
+
};
|
|
3967
|
+
this.streamParts.set(streamPartId, streamPart);
|
|
3968
|
+
node.on('message', (message) => {
|
|
3969
|
+
this.emit('newMessage', message);
|
|
3970
|
+
});
|
|
3971
|
+
const handleEntryPointLeave = async () => {
|
|
3972
|
+
if (this.destroyed || peerDescriptorStoreManager.isLocalNodeStored() || this.knownStreamPartEntryPoints.has(streamPartId)) {
|
|
3973
|
+
return;
|
|
3974
|
+
}
|
|
3975
|
+
const entryPoints = await peerDescriptorStoreManager.fetchNodes();
|
|
3976
|
+
if (entryPoints.length < MAX_NODE_COUNT) {
|
|
3977
|
+
await peerDescriptorStoreManager.storeAndKeepLocalNode();
|
|
3978
|
+
}
|
|
3979
|
+
};
|
|
3980
|
+
discoveryLayerNode.on('manualRejoinRequired', async () => {
|
|
3981
|
+
if (!streamPartReconnect.isRunning() && !networkSplitAvoidance.isRunning()) {
|
|
3982
|
+
logger$1.debug('Manual rejoin required for stream part', { streamPartId });
|
|
3983
|
+
await streamPartReconnect.reconnect();
|
|
3984
|
+
}
|
|
3985
|
+
});
|
|
3986
|
+
node.on('entryPointLeaveDetected', () => handleEntryPointLeave());
|
|
3987
|
+
setImmediate(async () => {
|
|
3988
|
+
try {
|
|
3989
|
+
await this.startLayersAndJoinDht(streamPartId, peerDescriptorStoreManager);
|
|
3990
|
+
}
|
|
3991
|
+
catch (err) {
|
|
3992
|
+
logger$1.warn(`Failed to join to stream part ${streamPartId}`, { err });
|
|
3993
|
+
}
|
|
3994
|
+
});
|
|
3995
|
+
}
|
|
3996
|
+
async startLayersAndJoinDht(streamPartId, peerDescriptorStoreManager) {
|
|
3997
|
+
logger$1.debug(`Start layers and join DHT for stream part ${streamPartId}`);
|
|
3998
|
+
const streamPart = this.streamParts.get(streamPartId);
|
|
3999
|
+
if ((streamPart === undefined) || streamPart.proxied) {
|
|
4000
|
+
// leaveStreamPart has been called (or leaveStreamPart called, and then setProxies called)
|
|
4001
|
+
return;
|
|
4002
|
+
}
|
|
4003
|
+
if (this.transport.isPrivateClientMode()) {
|
|
4004
|
+
await this.transport.disablePrivateClientMode();
|
|
4005
|
+
}
|
|
4006
|
+
await streamPart.discoveryLayerNode.start();
|
|
4007
|
+
await streamPart.node.start();
|
|
4008
|
+
const knownEntryPoints = this.knownStreamPartEntryPoints.get(streamPartId);
|
|
4009
|
+
if (knownEntryPoints !== undefined) {
|
|
4010
|
+
await Promise.all([
|
|
4011
|
+
streamPart.discoveryLayerNode.joinDht(knownEntryPoints),
|
|
4012
|
+
streamPart.discoveryLayerNode.joinRing()
|
|
4013
|
+
]);
|
|
4014
|
+
}
|
|
4015
|
+
else {
|
|
4016
|
+
const entryPoints = await peerDescriptorStoreManager.fetchNodes();
|
|
4017
|
+
await Promise.all([
|
|
4018
|
+
streamPart.discoveryLayerNode.joinDht(sampleSize(entryPoints, MIN_NEIGHBOR_COUNT)),
|
|
4019
|
+
streamPart.discoveryLayerNode.joinRing()
|
|
4020
|
+
]);
|
|
4021
|
+
if (entryPoints.length < MAX_NODE_COUNT) {
|
|
4022
|
+
await peerDescriptorStoreManager.storeAndKeepLocalNode();
|
|
4023
|
+
if (streamPart.discoveryLayerNode.getNeighborCount() < MIN_NEIGHBOR_COUNT) {
|
|
4024
|
+
setImmediate(() => streamPart.networkSplitAvoidance.avoidNetworkSplit());
|
|
4025
|
+
}
|
|
4026
|
+
}
|
|
4027
|
+
}
|
|
4028
|
+
}
|
|
4029
|
+
createDiscoveryLayerNode(streamPartId, entryPoints) {
|
|
4030
|
+
return new dht.DhtNode({
|
|
4031
|
+
transport: this.controlLayerNode,
|
|
4032
|
+
connectionsView: this.controlLayerNode.getConnectionsView(),
|
|
4033
|
+
serviceId: 'layer1::' + streamPartId,
|
|
4034
|
+
peerDescriptor: this.controlLayerNode.getLocalPeerDescriptor(),
|
|
4035
|
+
entryPoints,
|
|
4036
|
+
numberOfNodesPerKBucket: 4, // TODO use options option or named constant?
|
|
4037
|
+
rpcRequestTimeout: dht.EXISTING_CONNECTION_TIMEOUT,
|
|
4038
|
+
dhtJoinTimeout: 20000, // TODO use options option or named constant?
|
|
4039
|
+
periodicallyPingNeighbors: true,
|
|
4040
|
+
periodicallyPingRingContacts: true,
|
|
4041
|
+
neighborPingLimit: 16
|
|
4042
|
+
});
|
|
4043
|
+
}
|
|
4044
|
+
createContentDeliveryLayerNode(streamPartId, discoveryLayerNode, isLocalNodeEntryPoint, streamPartDeliveryOptions) {
|
|
4045
|
+
return createContentDeliveryLayerNode({
|
|
4046
|
+
streamPartId,
|
|
4047
|
+
transport: this.transport,
|
|
4048
|
+
discoveryLayerNode,
|
|
4049
|
+
connectionLocker: this.connectionLocker,
|
|
4050
|
+
localPeerDescriptor: this.controlLayerNode.getLocalPeerDescriptor(),
|
|
4051
|
+
minPropagationTargets: this.options.streamPartitionMinPropagationTargets,
|
|
4052
|
+
neighborTargetCount: this.options.streamPartitionNeighborTargetCount,
|
|
4053
|
+
maxPropagationBufferSize: this.options.streamPartitionMaxPropagationBufferSize,
|
|
4054
|
+
acceptProxyConnections: this.options.acceptProxyConnections,
|
|
4055
|
+
rpcRequestTimeout: this.options.rpcRequestTimeout,
|
|
4056
|
+
neighborUpdateInterval: this.options.neighborUpdateInterval,
|
|
4057
|
+
isLocalNodeEntryPoint,
|
|
4058
|
+
bufferWhileConnecting: this.options.bufferWhileConnecting,
|
|
4059
|
+
plumtreeOptimization: streamPartDeliveryOptions?.plumtreeOptimization?.enabled,
|
|
4060
|
+
plumtreeMaxPausedNeighbors: streamPartDeliveryOptions?.plumtreeOptimization?.enabled === true ?
|
|
4061
|
+
streamPartDeliveryOptions?.plumtreeOptimization?.maxPausedNeighbors : undefined
|
|
4062
|
+
});
|
|
4063
|
+
}
|
|
4064
|
+
async setProxies(streamPartId, nodes, userId, direction, connectionCount) {
|
|
4065
|
+
// TODO explicit default value for "acceptProxyConnections" or make it required
|
|
4066
|
+
if (this.options.acceptProxyConnections) {
|
|
4067
|
+
throw new Error('cannot set proxies when acceptProxyConnections=true');
|
|
4068
|
+
}
|
|
4069
|
+
const enable = (nodes.length > 0) && ((connectionCount === undefined) || (connectionCount > 0));
|
|
4070
|
+
if (enable) {
|
|
4071
|
+
let client;
|
|
4072
|
+
const alreadyProxied = this.isProxiedStreamPart(streamPartId);
|
|
4073
|
+
if (alreadyProxied) {
|
|
4074
|
+
client = this.streamParts.get(streamPartId).client;
|
|
4075
|
+
}
|
|
4076
|
+
else {
|
|
4077
|
+
client = this.createProxyClient(streamPartId);
|
|
4078
|
+
this.streamParts.set(streamPartId, {
|
|
4079
|
+
proxied: true,
|
|
4080
|
+
client,
|
|
4081
|
+
broadcast: (msg) => client.broadcast(msg),
|
|
4082
|
+
stop: async () => client.stop(),
|
|
4083
|
+
getDiagnosticInfo: () => client.getDiagnosticInfo()
|
|
4084
|
+
});
|
|
4085
|
+
client.on('message', (message) => {
|
|
4086
|
+
this.emit('newMessage', message);
|
|
4087
|
+
});
|
|
4088
|
+
if (Array.from(this.streamParts.values()).every((streamPart) => streamPart.proxied)) {
|
|
4089
|
+
await this.transport.enablePrivateClientMode();
|
|
4090
|
+
}
|
|
4091
|
+
await client.start();
|
|
4092
|
+
}
|
|
4093
|
+
await client.setProxies(nodes, userId, direction, connectionCount);
|
|
4094
|
+
}
|
|
4095
|
+
else {
|
|
4096
|
+
await this.streamParts.get(streamPartId)?.stop();
|
|
4097
|
+
this.streamParts.delete(streamPartId);
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
4100
|
+
createProxyClient(streamPartId) {
|
|
4101
|
+
return new ProxyClient({
|
|
4102
|
+
transport: this.transport,
|
|
4103
|
+
localPeerDescriptor: this.controlLayerNode.getLocalPeerDescriptor(),
|
|
4104
|
+
streamPartId,
|
|
4105
|
+
connectionLocker: this.connectionLocker,
|
|
4106
|
+
minPropagationTargets: this.options.streamPartitionMinPropagationTargets ?? DEFAULT_MIN_PROPAGATION_TARGETS,
|
|
4107
|
+
maxPropagationBufferSize: this.options.streamPartitionMaxPropagationBufferSize ?? DEFAULT_MAX_PROPAGATION_BUFFER_SIZE,
|
|
4108
|
+
propagationBufferTtl: DEFAULT_PROPAGATION_BUFFER_TTL
|
|
4109
|
+
});
|
|
4110
|
+
}
|
|
4111
|
+
async inspect(peerDescriptor, streamPartId) {
|
|
4112
|
+
const streamPart = this.streamParts.get(streamPartId);
|
|
4113
|
+
if ((streamPart !== undefined) && !streamPart.proxied) {
|
|
4114
|
+
return streamPart.node.inspect(peerDescriptor);
|
|
4115
|
+
}
|
|
4116
|
+
return false;
|
|
4117
|
+
}
|
|
4118
|
+
// TODO inline this method?
|
|
4119
|
+
getNodeInfo() {
|
|
4120
|
+
const streamParts = Array.from(this.streamParts.entries()).filter(([_, node]) => node.proxied === false);
|
|
4121
|
+
return streamParts.map(([streamPartId]) => {
|
|
4122
|
+
const stream = this.streamParts.get(streamPartId);
|
|
4123
|
+
return {
|
|
4124
|
+
id: streamPartId,
|
|
4125
|
+
controlLayerNeighbors: stream.discoveryLayerNode.getNeighbors(),
|
|
4126
|
+
deprecatedContentDeliveryLayerNeighbors: [],
|
|
4127
|
+
contentDeliveryLayerNeighbors: stream.node.getInfos()
|
|
4128
|
+
};
|
|
4129
|
+
});
|
|
4130
|
+
}
|
|
4131
|
+
setStreamPartEntryPoints(streamPartId, entryPoints) {
|
|
4132
|
+
this.knownStreamPartEntryPoints.set(streamPartId, entryPoints);
|
|
4133
|
+
}
|
|
4134
|
+
isProxiedStreamPart(streamPartId, direction) {
|
|
4135
|
+
const streamPart = this.streamParts.get(streamPartId);
|
|
4136
|
+
return (streamPart !== undefined)
|
|
4137
|
+
&& streamPart.proxied
|
|
4138
|
+
&& ((direction === undefined) || (streamPart.client.getDirection() === direction));
|
|
4139
|
+
}
|
|
4140
|
+
getStreamPartDelivery(streamPartId) {
|
|
4141
|
+
return this.streamParts.get(streamPartId);
|
|
4142
|
+
}
|
|
4143
|
+
hasStreamPart(streamPartId) {
|
|
4144
|
+
return this.streamParts.has(streamPartId);
|
|
4145
|
+
}
|
|
4146
|
+
getPeerDescriptor() {
|
|
4147
|
+
return this.controlLayerNode.getLocalPeerDescriptor();
|
|
4148
|
+
}
|
|
4149
|
+
getNodeId() {
|
|
4150
|
+
return dht.toNodeId(this.controlLayerNode.getLocalPeerDescriptor());
|
|
4151
|
+
}
|
|
4152
|
+
getNeighbors(streamPartId) {
|
|
4153
|
+
const streamPart = this.streamParts.get(streamPartId);
|
|
4154
|
+
return streamPart?.proxied === false
|
|
4155
|
+
? streamPart.node.getNeighbors().map((n) => dht.toNodeId(n))
|
|
4156
|
+
: [];
|
|
4157
|
+
}
|
|
4158
|
+
getStreamParts() {
|
|
4159
|
+
return Array.from(this.streamParts.keys()).map((id) => utils.StreamPartIDUtils.parse(id));
|
|
4160
|
+
}
|
|
4161
|
+
getDiagnosticInfo() {
|
|
4162
|
+
return {
|
|
4163
|
+
streamParts: this.getStreamParts().map((id) => {
|
|
4164
|
+
return {
|
|
4165
|
+
id,
|
|
4166
|
+
info: this.getStreamPartDelivery(id).getDiagnosticInfo()
|
|
4167
|
+
};
|
|
4168
|
+
})
|
|
4169
|
+
};
|
|
4170
|
+
}
|
|
4171
|
+
}
|
|
4172
|
+
|
|
4173
|
+
class NodeInfoRpcRemote extends dht.RpcRemote {
|
|
4174
|
+
async getInfo() {
|
|
4175
|
+
return this.getClient().getInfo({}, this.formDhtRpcOptions());
|
|
4176
|
+
}
|
|
4177
|
+
}
|
|
4178
|
+
|
|
4179
|
+
class NodeInfoClient {
|
|
4180
|
+
ownPeerDescriptor;
|
|
4181
|
+
rpcCommunicator;
|
|
4182
|
+
constructor(ownPeerDescriptor, rpcCommunicator) {
|
|
4183
|
+
this.ownPeerDescriptor = ownPeerDescriptor;
|
|
4184
|
+
this.rpcCommunicator = rpcCommunicator;
|
|
4185
|
+
}
|
|
4186
|
+
async getInfo(node) {
|
|
4187
|
+
const remote = new NodeInfoRpcRemote(this.ownPeerDescriptor, node, this.rpcCommunicator, NodeInfoRpcClient);
|
|
4188
|
+
// TODO remove casting when we validate NodeInfoResponse messages and therefore can annotate
|
|
4189
|
+
// each of the field as required in the decorated type
|
|
4190
|
+
return remote.getInfo();
|
|
4191
|
+
}
|
|
4192
|
+
}
|
|
4193
|
+
|
|
4194
|
+
const NODE_INFO_RPC_SERVICE_ID = 'system/node-info-rpc';
|
|
4195
|
+
class NodeInfoRpcLocal {
|
|
4196
|
+
stack;
|
|
4197
|
+
rpcCommunicator;
|
|
4198
|
+
constructor(stack, rpcCommunicator) {
|
|
4199
|
+
this.stack = stack;
|
|
4200
|
+
this.rpcCommunicator = rpcCommunicator;
|
|
4201
|
+
this.registerDefaultServerMethods();
|
|
4202
|
+
}
|
|
4203
|
+
registerDefaultServerMethods() {
|
|
4204
|
+
this.rpcCommunicator.registerRpcMethod(NodeInfoRequest, NodeInfoResponse, 'getInfo', () => this.getInfo());
|
|
4205
|
+
}
|
|
4206
|
+
async getInfo() {
|
|
4207
|
+
return this.stack.createNodeInfo();
|
|
4208
|
+
}
|
|
4209
|
+
}
|
|
4210
|
+
|
|
4211
|
+
const logger = new utils.Logger('NetworkStack');
|
|
4212
|
+
const instances = [];
|
|
4213
|
+
const stopInstances = async () => {
|
|
4214
|
+
// make a clone so that it is ok for each instance.stop() to remove itself from the list (at line 139)
|
|
4215
|
+
// while the map function is iterating the list
|
|
4216
|
+
const clonedInstances = [...instances];
|
|
4217
|
+
await Promise.all(clonedInstances.map((instance) => instance.stop()));
|
|
4218
|
+
};
|
|
4219
|
+
/**
|
|
4220
|
+
* @todo The following cleanup logic is currently handled inside this module for both Node.js and
|
|
4221
|
+
* browser environments. Consider refactoring it into a higher-level integration layer if lifecycle
|
|
4222
|
+
* management is centralized elsewhere.
|
|
4223
|
+
*/
|
|
4224
|
+
if (typeof process === 'object' && typeof process?.on === 'function') {
|
|
4225
|
+
/**
|
|
4226
|
+
* @todo The `exit` event shouldn't use an async handler because the event loop is already
|
|
4227
|
+
* shutting down, so async work won't complete. Calling `process.exit()` inside an `exit`
|
|
4228
|
+
* handler is also redundant and may cause issues. Remove `exit` from `EXIT_EVENTS`
|
|
4229
|
+
* or omit it entirely, since other signal handlers already terminate the process.
|
|
4230
|
+
*/
|
|
4231
|
+
const EXIT_EVENTS = [`exit`, `SIGINT`, `SIGUSR1`, `SIGUSR2`, `uncaughtException`, `unhandledRejection`, `SIGTERM`];
|
|
4232
|
+
EXIT_EVENTS.forEach((event) => {
|
|
4233
|
+
/**
|
|
4234
|
+
* @todo Registering handlers at module load time can cause side effects. Use explicit
|
|
4235
|
+
* or lazy initialization to improve control and testability.
|
|
4236
|
+
*/
|
|
4237
|
+
process.on(event, async (eventArg) => {
|
|
4238
|
+
const isError = (event === 'uncaughtException') || (event === 'unhandledRejection');
|
|
4239
|
+
if (isError) {
|
|
4240
|
+
logger.error(`exit event: ${event}`, eventArg);
|
|
4241
|
+
}
|
|
4242
|
+
/**
|
|
4243
|
+
* @todo Async `stopInstances()` may be interrupted by `process.exit()`. Use
|
|
4244
|
+
* synchronous cleanup or a timeout, and wait for cleanup on graceful signals
|
|
4245
|
+
* but exit quickly on error events.
|
|
4246
|
+
*/
|
|
4247
|
+
await stopInstances();
|
|
4248
|
+
process.exit(isError ? 1 : 0);
|
|
4249
|
+
});
|
|
4250
|
+
});
|
|
4251
|
+
}
|
|
4252
|
+
if (typeof window === 'object') {
|
|
4253
|
+
/**
|
|
4254
|
+
* @todo Registering handlers at module load time can cause side effects. Use explicit
|
|
4255
|
+
* or lazy initialization to improve control and testability.
|
|
4256
|
+
*/
|
|
4257
|
+
window.addEventListener('unload', async () => {
|
|
4258
|
+
await stopInstances();
|
|
4259
|
+
});
|
|
4260
|
+
}
|
|
4261
|
+
class NetworkStack {
|
|
4262
|
+
controlLayerNode;
|
|
4263
|
+
contentDeliveryManager;
|
|
4264
|
+
stopped = false;
|
|
4265
|
+
metricsContext;
|
|
4266
|
+
options;
|
|
4267
|
+
nodeInfoRpcLocal;
|
|
4268
|
+
nodeInfoClient;
|
|
4269
|
+
constructor(options) {
|
|
4270
|
+
this.options = options;
|
|
4271
|
+
this.metricsContext = options.metricsContext ?? new utils.MetricsContext();
|
|
4272
|
+
this.controlLayerNode = new dht.DhtNode({
|
|
4273
|
+
...options.layer0,
|
|
4274
|
+
metricsContext: this.metricsContext,
|
|
4275
|
+
allowIncomingPrivateConnections: options.networkNode?.acceptProxyConnections
|
|
4276
|
+
});
|
|
4277
|
+
this.contentDeliveryManager = new ContentDeliveryManager({
|
|
4278
|
+
...options.networkNode,
|
|
4279
|
+
metricsContext: this.metricsContext
|
|
4280
|
+
});
|
|
4281
|
+
instances.push(this);
|
|
4282
|
+
}
|
|
4283
|
+
async joinStreamPart(streamPartId, neighborRequirement, streamPartDeliveryOptions) {
|
|
4284
|
+
if (this.getContentDeliveryManager().isProxiedStreamPart(streamPartId)) {
|
|
4285
|
+
throw new Error(`Cannot join to ${streamPartId} as proxy connections have been set`);
|
|
4286
|
+
}
|
|
4287
|
+
await this.ensureConnectedToControlLayer();
|
|
4288
|
+
this.getContentDeliveryManager().joinStreamPart(streamPartId, streamPartDeliveryOptions);
|
|
4289
|
+
if (neighborRequirement !== undefined) {
|
|
4290
|
+
await utils.until(() => {
|
|
4291
|
+
return this.getContentDeliveryManager().getNeighbors(streamPartId).length >= neighborRequirement.minCount;
|
|
4292
|
+
}, neighborRequirement.timeout);
|
|
4293
|
+
}
|
|
4294
|
+
}
|
|
4295
|
+
async broadcast(msg, streamPartDeliveryOptions) {
|
|
4296
|
+
const streamPartId = utils.toStreamPartID(msg.messageId.streamId, msg.messageId.streamPartition);
|
|
4297
|
+
if (this.getContentDeliveryManager().isProxiedStreamPart(streamPartId, exports.ProxyDirection.SUBSCRIBE)
|
|
4298
|
+
&& (msg.body.oneofKind === 'contentMessage')) {
|
|
4299
|
+
throw new Error(`Cannot broadcast to ${streamPartId} as proxy subscribe connections have been set`);
|
|
4300
|
+
}
|
|
4301
|
+
// TODO could combine these two calls to isProxiedStreamPart?
|
|
4302
|
+
if (!this.contentDeliveryManager.isProxiedStreamPart(streamPartId)) {
|
|
4303
|
+
await this.ensureConnectedToControlLayer();
|
|
4304
|
+
}
|
|
4305
|
+
this.getContentDeliveryManager().broadcast(msg, streamPartDeliveryOptions);
|
|
4306
|
+
}
|
|
4307
|
+
async start(doJoin = true) {
|
|
4308
|
+
logger.info('Starting a Streamr Network Node');
|
|
4309
|
+
await this.controlLayerNode.start();
|
|
4310
|
+
logger.info(`Node id is ${dht.toNodeId(this.controlLayerNode.getLocalPeerDescriptor())}`);
|
|
4311
|
+
const connectionManager = this.controlLayerNode.getTransport();
|
|
4312
|
+
if ((this.options.layer0?.entryPoints?.some((entryPoint) => dht.areEqualPeerDescriptors(entryPoint, this.controlLayerNode.getLocalPeerDescriptor())))) {
|
|
4313
|
+
await this.controlLayerNode?.joinDht(this.options.layer0.entryPoints);
|
|
4314
|
+
}
|
|
4315
|
+
else if (doJoin) {
|
|
4316
|
+
// in practice there aren't be existing connections and therefore this always connects
|
|
4317
|
+
await this.ensureConnectedToControlLayer();
|
|
4318
|
+
}
|
|
4319
|
+
// TODO: remove undefined checks here. Assume that start is approproately awaited before stop is called.
|
|
4320
|
+
await this.contentDeliveryManager?.start(this.controlLayerNode, connectionManager, connectionManager);
|
|
4321
|
+
if (this.contentDeliveryManager) {
|
|
4322
|
+
const infoRpcCommunicator = new dht.ListeningRpcCommunicator(NODE_INFO_RPC_SERVICE_ID, this.getConnectionManager());
|
|
4323
|
+
this.nodeInfoRpcLocal = new NodeInfoRpcLocal(this, infoRpcCommunicator);
|
|
4324
|
+
this.nodeInfoClient = new NodeInfoClient(this.controlLayerNode.getLocalPeerDescriptor(), infoRpcCommunicator);
|
|
4325
|
+
}
|
|
4326
|
+
}
|
|
4327
|
+
async ensureConnectedToControlLayer() {
|
|
4328
|
+
// TODO we could wrap joinDht with pOnce and call it here (no else-if needed in that case)
|
|
4329
|
+
if (!this.controlLayerNode.hasJoined()) {
|
|
4330
|
+
setImmediate(async () => {
|
|
4331
|
+
if (this.options.layer0?.entryPoints !== undefined) {
|
|
4332
|
+
// TODO should catch possible rejection?
|
|
4333
|
+
// the question mark is there to avoid problems when stop() is called before start()
|
|
4334
|
+
// -> TODO change to exlamation mark if we don't support that (and remove NetworkStackStoppedDuringStart.test)
|
|
4335
|
+
await this.controlLayerNode?.joinDht(this.options.layer0.entryPoints);
|
|
4336
|
+
}
|
|
4337
|
+
});
|
|
4338
|
+
await this.controlLayerNode.waitForNetworkConnectivity();
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
getContentDeliveryManager() {
|
|
4342
|
+
return this.contentDeliveryManager;
|
|
4343
|
+
}
|
|
4344
|
+
getControlLayerNode() {
|
|
4345
|
+
return this.controlLayerNode;
|
|
4346
|
+
}
|
|
4347
|
+
getMetricsContext() {
|
|
4348
|
+
return this.metricsContext;
|
|
4349
|
+
}
|
|
4350
|
+
async fetchNodeInfo(node) {
|
|
4351
|
+
if (!dht.areEqualPeerDescriptors(node, this.getControlLayerNode().getLocalPeerDescriptor())) {
|
|
4352
|
+
return this.nodeInfoClient.getInfo(node);
|
|
4353
|
+
}
|
|
4354
|
+
else {
|
|
4355
|
+
return this.createNodeInfo();
|
|
4356
|
+
}
|
|
4357
|
+
}
|
|
4358
|
+
createNodeInfo() {
|
|
4359
|
+
return {
|
|
4360
|
+
peerDescriptor: this.getControlLayerNode().getLocalPeerDescriptor(),
|
|
4361
|
+
controlLayer: {
|
|
4362
|
+
connections: this.getControlLayerNode().getConnectionsView().getConnections(),
|
|
4363
|
+
neighbors: this.getControlLayerNode().getNeighbors()
|
|
4364
|
+
},
|
|
4365
|
+
streamPartitions: this.getContentDeliveryManager().getNodeInfo(),
|
|
4366
|
+
applicationVersion: version
|
|
4367
|
+
};
|
|
4368
|
+
}
|
|
4369
|
+
getOptions() {
|
|
4370
|
+
return this.options;
|
|
4371
|
+
}
|
|
4372
|
+
getConnectionManager() {
|
|
4373
|
+
return this.controlLayerNode.getTransport();
|
|
4374
|
+
}
|
|
4375
|
+
async stop() {
|
|
4376
|
+
if (!this.stopped) {
|
|
4377
|
+
this.stopped = true;
|
|
4378
|
+
pull(instances, this);
|
|
4379
|
+
await this.contentDeliveryManager.destroy();
|
|
4380
|
+
await this.controlLayerNode.stop();
|
|
4381
|
+
this.contentDeliveryManager = undefined;
|
|
4382
|
+
this.controlLayerNode = undefined;
|
|
4383
|
+
}
|
|
4384
|
+
}
|
|
4385
|
+
}
|
|
4386
|
+
|
|
4387
|
+
const createNetworkNode = (opts) => {
|
|
4388
|
+
return new NetworkNode(new NetworkStack(opts));
|
|
4389
|
+
};
|
|
4390
|
+
/**
|
|
4391
|
+
* Convenience wrapper for building client-facing functionality. Used by client.
|
|
4392
|
+
*/
|
|
4393
|
+
class NetworkNode {
|
|
4394
|
+
stack;
|
|
4395
|
+
stopped = false;
|
|
4396
|
+
externalNetworkRpc;
|
|
4397
|
+
/** @internal */
|
|
4398
|
+
constructor(stack) {
|
|
4399
|
+
this.stack = stack;
|
|
4400
|
+
}
|
|
4401
|
+
async start(doJoin) {
|
|
4402
|
+
await this.stack.start(doJoin);
|
|
4403
|
+
this.externalNetworkRpc = new ExternalNetworkRpc(this.stack.getControlLayerNode().getTransport());
|
|
4404
|
+
}
|
|
4405
|
+
async inspect(node, streamPartId) {
|
|
4406
|
+
return this.stack.getContentDeliveryManager().inspect(node, streamPartId);
|
|
4407
|
+
}
|
|
4408
|
+
async broadcast(msg, streamPartDeliveryOptions) {
|
|
4409
|
+
await this.stack.broadcast(msg, streamPartDeliveryOptions);
|
|
4410
|
+
}
|
|
4411
|
+
async join(streamPartId, neighborRequirement, streamPartDeliveryOptions) {
|
|
4412
|
+
await this.stack.joinStreamPart(streamPartId, neighborRequirement, streamPartDeliveryOptions);
|
|
4413
|
+
}
|
|
4414
|
+
async setProxies(streamPartId, nodes, userId, direction, connectionCount) {
|
|
4415
|
+
await this.stack.getContentDeliveryManager().setProxies(streamPartId, nodes, userId, direction, connectionCount);
|
|
4416
|
+
}
|
|
4417
|
+
isProxiedStreamPart(streamPartId) {
|
|
4418
|
+
return this.stack.getContentDeliveryManager().isProxiedStreamPart(streamPartId);
|
|
4419
|
+
}
|
|
4420
|
+
addMessageListener(listener) {
|
|
4421
|
+
this.stack.getContentDeliveryManager().on('newMessage', listener);
|
|
4422
|
+
}
|
|
4423
|
+
setStreamPartEntryPoints(streamPartId, contactPeerDescriptors) {
|
|
4424
|
+
this.stack.getContentDeliveryManager().setStreamPartEntryPoints(streamPartId, contactPeerDescriptors);
|
|
4425
|
+
}
|
|
4426
|
+
removeMessageListener(listener) {
|
|
4427
|
+
this.stack.getContentDeliveryManager().off('newMessage', listener);
|
|
4428
|
+
}
|
|
4429
|
+
async leave(streamPartId) {
|
|
4430
|
+
if (this.stopped) {
|
|
4431
|
+
return;
|
|
4432
|
+
}
|
|
4433
|
+
await this.stack.getContentDeliveryManager().leaveStreamPart(streamPartId);
|
|
4434
|
+
}
|
|
4435
|
+
getNeighbors(streamPartId) {
|
|
4436
|
+
return this.stack.getContentDeliveryManager().getNeighbors(streamPartId);
|
|
4437
|
+
}
|
|
4438
|
+
hasStreamPart(streamPartId) {
|
|
4439
|
+
return this.stack.getContentDeliveryManager().hasStreamPart(streamPartId);
|
|
4440
|
+
}
|
|
4441
|
+
async stop() {
|
|
4442
|
+
this.stopped = true;
|
|
4443
|
+
this.externalNetworkRpc.destroy();
|
|
4444
|
+
await this.stack.stop();
|
|
4445
|
+
}
|
|
4446
|
+
getPeerDescriptor() {
|
|
4447
|
+
return this.stack.getControlLayerNode().getLocalPeerDescriptor();
|
|
4448
|
+
}
|
|
4449
|
+
getMetricsContext() {
|
|
4450
|
+
return this.stack.getMetricsContext();
|
|
4451
|
+
}
|
|
4452
|
+
getNodeId() {
|
|
4453
|
+
return this.stack.getContentDeliveryManager().getNodeId();
|
|
4454
|
+
}
|
|
4455
|
+
getOptions() {
|
|
4456
|
+
return this.stack.getOptions();
|
|
4457
|
+
}
|
|
4458
|
+
getStreamParts() {
|
|
4459
|
+
return this.stack.getContentDeliveryManager().getStreamParts();
|
|
4460
|
+
}
|
|
4461
|
+
async fetchNodeInfo(node) {
|
|
4462
|
+
return this.stack.fetchNodeInfo(node);
|
|
4463
|
+
}
|
|
4464
|
+
getDiagnosticInfo() {
|
|
4465
|
+
return {
|
|
4466
|
+
controlLayer: this.stack.getControlLayerNode().getDiagnosticInfo(),
|
|
4467
|
+
contentLayer: this.stack.getContentDeliveryManager().getDiagnosticInfo()
|
|
4468
|
+
};
|
|
4469
|
+
}
|
|
4470
|
+
registerExternalNetworkRpcMethod(request, response, name, fn) {
|
|
4471
|
+
this.externalNetworkRpc.registerRpcMethod(request, response, name, fn);
|
|
4472
|
+
}
|
|
4473
|
+
createExternalRpcClient(clientClass) {
|
|
4474
|
+
return this.externalNetworkRpc.createRpcClient(clientClass);
|
|
4475
|
+
}
|
|
4476
|
+
}
|
|
4477
|
+
|
|
4478
|
+
exports.ControlLayerInfo = ControlLayerInfo;
|
|
4479
|
+
exports.EncryptedGroupKey = EncryptedGroupKey;
|
|
4480
|
+
exports.GroupKeyRequest = GroupKeyRequest;
|
|
4481
|
+
exports.GroupKeyResponse = GroupKeyResponse;
|
|
4482
|
+
exports.MessageID = MessageID;
|
|
4483
|
+
exports.MessageRef = MessageRef;
|
|
4484
|
+
exports.NetworkNode = NetworkNode;
|
|
4485
|
+
exports.NetworkStack = NetworkStack;
|
|
4486
|
+
exports.StreamMessage = StreamMessage;
|
|
4487
|
+
exports.createNetworkNode = createNetworkNode;
|
|
4488
|
+
exports.streamPartIdToDataKey = streamPartIdToDataKey;
|
|
4489
|
+
//# sourceMappingURL=exports.cjs.map
|