@electrum-cash/network 3.3.1-development.6372294997 → 4.0.0-development.6392223875
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -38
- package/dist/index.d.ts +10 -272
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +226 -645
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -9
- package/dist/index.cjs +0 -1643
- package/dist/index.cjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {EventEmitter as $4QiMX$EventEmitter} from "events";
|
|
2
2
|
import {Mutex as $4QiMX$Mutex} from "async-mutex";
|
|
3
3
|
import $4QiMX$debug from "debug";
|
|
4
|
-
import {parse as $4QiMX$parse, parseNumberAndBigInt as $4QiMX$parseNumberAndBigInt
|
|
4
|
+
import {parse as $4QiMX$parse, parseNumberAndBigInt as $4QiMX$parseNumberAndBigInt} from "lossless-json";
|
|
5
5
|
import {connect as $4QiMX$connect, TLSSocket as $4QiMX$TLSSocket} from "tls";
|
|
6
6
|
import {isIP as $4QiMX$isIP, connect as $4QiMX$connect1} from "net";
|
|
7
7
|
import {WebSocket as $4QiMX$WebSocket} from "@monsterbitar/isomorphic-ws";
|
|
@@ -14,7 +14,6 @@ function $parcel$export(e, n, v, s) {
|
|
|
14
14
|
// Create the debug logs.
|
|
15
15
|
const $ef5ba40c8abe5a13$var$debug = {
|
|
16
16
|
client: (0, $4QiMX$debug)("electrum-cash:client "),
|
|
17
|
-
cluster: (0, $4QiMX$debug)("electrum-cash:cluster"),
|
|
18
17
|
errors: (0, $4QiMX$debug)("electrum-cash:error "),
|
|
19
18
|
warning: (0, $4QiMX$debug)("electrum-cash:warning"),
|
|
20
19
|
network: (0, $4QiMX$debug)("electrum-cash:network"),
|
|
@@ -22,7 +21,6 @@ const $ef5ba40c8abe5a13$var$debug = {
|
|
|
22
21
|
};
|
|
23
22
|
// Set log colors.
|
|
24
23
|
$ef5ba40c8abe5a13$var$debug.client.color = "2";
|
|
25
|
-
$ef5ba40c8abe5a13$var$debug.cluster.color = "3";
|
|
26
24
|
$ef5ba40c8abe5a13$var$debug.errors.color = "9";
|
|
27
25
|
$ef5ba40c8abe5a13$var$debug.warning.color = "13";
|
|
28
26
|
$ef5ba40c8abe5a13$var$debug.network.color = "4";
|
|
@@ -91,49 +89,6 @@ var $5abc8fb342687c03$exports = {};
|
|
|
91
89
|
|
|
92
90
|
$parcel$export($5abc8fb342687c03$exports, "ElectrumTransport", () => $5abc8fb342687c03$export$d048df559e6d3842);
|
|
93
91
|
$parcel$export($5abc8fb342687c03$exports, "DefaultParameters", () => $5abc8fb342687c03$export$f019be48b3aacb1a);
|
|
94
|
-
var $a58372b18a18806e$exports = {};
|
|
95
|
-
|
|
96
|
-
$parcel$export($a58372b18a18806e$exports, "ClusterOrder", () => $a58372b18a18806e$export$161fe3707f756bf9);
|
|
97
|
-
$parcel$export($a58372b18a18806e$exports, "ClusterDistribution", () => $a58372b18a18806e$export$436a960acc41e848);
|
|
98
|
-
$parcel$export($a58372b18a18806e$exports, "ClusterStatus", () => $a58372b18a18806e$export$c66b56bc0ff967ca);
|
|
99
|
-
$parcel$export($a58372b18a18806e$exports, "ClientState", () => $a58372b18a18806e$export$c4f81c6d30ca200f);
|
|
100
|
-
$parcel$export($a58372b18a18806e$exports, "ConnectionStatus", () => $a58372b18a18806e$export$7516420eb880ab68);
|
|
101
|
-
// Disable indent rule for this file because it is broken (https://github.com/typescript-eslint/typescript-eslint/issues/1824)
|
|
102
|
-
/* eslint-disable @typescript-eslint/indent */ /**
|
|
103
|
-
* Enum that denotes the ordering to use in an ElectrumCluster.
|
|
104
|
-
* @enum {number}
|
|
105
|
-
* @property {0} RANDOM Send requests to randomly selected servers in the cluster.
|
|
106
|
-
* @property {1} PRIORITY Send requests to servers in the cluster in the order they were added.
|
|
107
|
-
*/ var $a58372b18a18806e$export$161fe3707f756bf9;
|
|
108
|
-
(function(ClusterOrder) {
|
|
109
|
-
ClusterOrder[ClusterOrder["RANDOM"] = 0] = "RANDOM";
|
|
110
|
-
ClusterOrder[ClusterOrder["PRIORITY"] = 1] = "PRIORITY";
|
|
111
|
-
})($a58372b18a18806e$export$161fe3707f756bf9 || ($a58372b18a18806e$export$161fe3707f756bf9 = {}));
|
|
112
|
-
var $a58372b18a18806e$export$436a960acc41e848;
|
|
113
|
-
(function(ClusterDistribution) {
|
|
114
|
-
ClusterDistribution[ClusterDistribution["ALL"] = 0] = "ALL";
|
|
115
|
-
})($a58372b18a18806e$export$436a960acc41e848 || ($a58372b18a18806e$export$436a960acc41e848 = {}));
|
|
116
|
-
var $a58372b18a18806e$export$c66b56bc0ff967ca;
|
|
117
|
-
(function(ClusterStatus) {
|
|
118
|
-
ClusterStatus[ClusterStatus["DISABLED"] = 0] = "DISABLED";
|
|
119
|
-
ClusterStatus[ClusterStatus["DEGRADED"] = 1] = "DEGRADED";
|
|
120
|
-
ClusterStatus[ClusterStatus["READY"] = 2] = "READY";
|
|
121
|
-
})($a58372b18a18806e$export$c66b56bc0ff967ca || ($a58372b18a18806e$export$c66b56bc0ff967ca = {}));
|
|
122
|
-
var $a58372b18a18806e$export$c4f81c6d30ca200f;
|
|
123
|
-
(function(ClientState) {
|
|
124
|
-
ClientState[ClientState["UNAVAILABLE"] = 0] = "UNAVAILABLE";
|
|
125
|
-
ClientState[ClientState["AVAILABLE"] = 1] = "AVAILABLE";
|
|
126
|
-
})($a58372b18a18806e$export$c4f81c6d30ca200f || ($a58372b18a18806e$export$c4f81c6d30ca200f = {}));
|
|
127
|
-
var $a58372b18a18806e$export$7516420eb880ab68;
|
|
128
|
-
(function(ConnectionStatus) {
|
|
129
|
-
ConnectionStatus[ConnectionStatus["DISCONNECTED"] = 0] = "DISCONNECTED";
|
|
130
|
-
ConnectionStatus[ConnectionStatus["CONNECTED"] = 1] = "CONNECTED";
|
|
131
|
-
ConnectionStatus[ConnectionStatus["DISCONNECTING"] = 2] = "DISCONNECTING";
|
|
132
|
-
ConnectionStatus[ConnectionStatus["CONNECTING"] = 3] = "CONNECTING";
|
|
133
|
-
ConnectionStatus[ConnectionStatus["RECONNECTING"] = 4] = "RECONNECTING";
|
|
134
|
-
})($a58372b18a18806e$export$7516420eb880ab68 || ($a58372b18a18806e$export$7516420eb880ab68 = {}));
|
|
135
|
-
|
|
136
|
-
|
|
137
92
|
const $5abc8fb342687c03$export$d048df559e6d3842 = {
|
|
138
93
|
TCP: {
|
|
139
94
|
Port: 50001,
|
|
@@ -164,12 +119,6 @@ const $5abc8fb342687c03$export$f019be48b3aacb1a = {
|
|
|
164
119
|
// Time between ping messages, in milliseconds. Pinging keeps the connection alive.
|
|
165
120
|
// The reason for pinging this frequently is to detect connection problems early.
|
|
166
121
|
PING_INTERVAL: 1000,
|
|
167
|
-
// How many servers are required before we trust information provided.
|
|
168
|
-
CLUSTER_CONFIDENCE: 1,
|
|
169
|
-
// How many servers we send requests to.
|
|
170
|
-
CLUSTER_DISTRIBUTION: (0, $a58372b18a18806e$export$436a960acc41e848).ALL,
|
|
171
|
-
// What order we select servers to send requests to.
|
|
172
|
-
CLUSTER_ORDER: (0, $a58372b18a18806e$export$161fe3707f756bf9).RANDOM,
|
|
173
122
|
// If we use BigInt for numbers in json when parsing and returning json response from the server.
|
|
174
123
|
USE_BIG_INT: false
|
|
175
124
|
};
|
|
@@ -182,16 +131,7 @@ const $5abc8fb342687c03$export$f019be48b3aacb1a = {
|
|
|
182
131
|
|
|
183
132
|
|
|
184
133
|
|
|
185
|
-
|
|
186
|
-
* Isomorphic Socket interface supporting TCP sockets and WebSockets (Node and browser).
|
|
187
|
-
* The interface is a subset of the TLSSocket interface with some slight modifications.
|
|
188
|
-
* It can be expanded when more socket functionality is needed in the rest of the
|
|
189
|
-
* electrum-cash code. Changes from the TLSSocket interface (besides it being a subset):
|
|
190
|
-
* - Event 'close' -> 'disconnect'
|
|
191
|
-
* - New function socket.disconnect()
|
|
192
|
-
*
|
|
193
|
-
* @ignore
|
|
194
|
-
*/ class $ea64e414b68fe23b$var$ElectrumSocket extends (0, $4QiMX$EventEmitter) {
|
|
134
|
+
class $ea64e414b68fe23b$export$22c0ca2c816c3e08 extends (0, $4QiMX$EventEmitter) {
|
|
195
135
|
/**
|
|
196
136
|
* Connect to host:port using the specified transport
|
|
197
137
|
*
|
|
@@ -203,7 +143,7 @@ const $5abc8fb342687c03$export$f019be48b3aacb1a = {
|
|
|
203
143
|
* @throws {Error} if an incorrect transport scheme is specified
|
|
204
144
|
*/ connect(host, port, scheme, timeout) {
|
|
205
145
|
// Check that no existing socket exists before initiating a new connection.
|
|
206
|
-
if (this.tcpSocket
|
|
146
|
+
if (this.tcpSocket) throw new Error("Cannot initiate a new socket connection when an existing connection exists");
|
|
207
147
|
// Set a timer to force disconnect after `timeout` seconds
|
|
208
148
|
this.timers.disconnect = setTimeout(()=>this.disconnectOnTimeout(host, port, timeout), timeout);
|
|
209
149
|
// Remove the timer if a connection is successfully established
|
|
@@ -211,65 +151,182 @@ const $5abc8fb342687c03$export$f019be48b3aacb1a = {
|
|
|
211
151
|
// Define how to refer to the connection scheme in debug output.
|
|
212
152
|
const socketTypes = {
|
|
213
153
|
[(0, $5abc8fb342687c03$export$d048df559e6d3842).TCP.Scheme]: "a TCP Socket",
|
|
214
|
-
[(0, $5abc8fb342687c03$export$d048df559e6d3842).TCP_TLS.Scheme]: "an encrypted TCP socket"
|
|
154
|
+
[(0, $5abc8fb342687c03$export$d048df559e6d3842).TCP_TLS.Scheme]: "an encrypted TCP socket"
|
|
155
|
+
};
|
|
156
|
+
// Log that we are trying to establish a connection.
|
|
157
|
+
(0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).network(`Initiating ${socketTypes[scheme]} connection to '${host}:${port}'.`);
|
|
158
|
+
if (scheme !== (0, $5abc8fb342687c03$export$d048df559e6d3842).TCP.Scheme && scheme !== (0, $5abc8fb342687c03$export$d048df559e6d3842).TCP_TLS.Scheme) // Throw an error if an incorrect transport is specified
|
|
159
|
+
throw new Error("Incorrect transport specified");
|
|
160
|
+
if (scheme === (0, $5abc8fb342687c03$export$d048df559e6d3842).TCP_TLS.Scheme) {
|
|
161
|
+
// Initialize connection options.
|
|
162
|
+
const connectionOptions = {
|
|
163
|
+
rejectUnauthorized: false
|
|
164
|
+
};
|
|
165
|
+
// If the hostname is not an IP address..
|
|
166
|
+
if (!$4QiMX$isIP(host)) // Set the servername option which enables support for SNI.
|
|
167
|
+
// NOTE: SNI enables a server that hosts multiple domains to provide the appropriate TLS certificate.
|
|
168
|
+
connectionOptions.serverName = host;
|
|
169
|
+
// Initialize the socket (allowing self-signed certificates).
|
|
170
|
+
this.tcpSocket = $4QiMX$connect(port, host, connectionOptions);
|
|
171
|
+
// Add a 'secureConnect' listener that checks the authorization status of
|
|
172
|
+
// the socket, and logs a warning when it uses a self signed certificate.
|
|
173
|
+
this.tcpSocket.once("secureConnect", ()=>{
|
|
174
|
+
// Cannot happen, since this event callback *only* exists on TLSSocket
|
|
175
|
+
if (!(this.tcpSocket instanceof $4QiMX$TLSSocket)) return;
|
|
176
|
+
// Force cast authorizationError from Error to string (through unknown)
|
|
177
|
+
// because it is incorrectly typed as an Error
|
|
178
|
+
const authorizationError = this.tcpSocket.authorizationError;
|
|
179
|
+
if (authorizationError === "DEPTH_ZERO_SELF_SIGNED_CERT") (0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).warning(`Connection to ${host}:${port} uses a self-signed certificate`);
|
|
180
|
+
});
|
|
181
|
+
// Trigger successful connection events.
|
|
182
|
+
this.tcpSocket.on("secureConnect", this.onConnect.bind(this, socketTypes[scheme], host, port));
|
|
183
|
+
} else {
|
|
184
|
+
// Initialize the socket.
|
|
185
|
+
this.tcpSocket = $4QiMX$connect1({
|
|
186
|
+
host: host,
|
|
187
|
+
port: port
|
|
188
|
+
});
|
|
189
|
+
// Trigger successful connection events.
|
|
190
|
+
this.tcpSocket.on("connect", this.onConnect.bind(this, socketTypes[scheme], host, port));
|
|
191
|
+
}
|
|
192
|
+
// Configure encoding.
|
|
193
|
+
this.tcpSocket.setEncoding("utf8");
|
|
194
|
+
// Enable persistent connections with an initial delay of 0.
|
|
195
|
+
this.tcpSocket.setKeepAlive(true, 0);
|
|
196
|
+
// Disable buffering of outgoing data.
|
|
197
|
+
this.tcpSocket.setNoDelay(true);
|
|
198
|
+
// Forward the encountered errors.
|
|
199
|
+
this.tcpSocket.on("error", this.eventForwarders.tcpError);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Sets up forwarding of events related to the connection.
|
|
203
|
+
*
|
|
204
|
+
* @param {string} connectionType Name of the connection/transport type, used for logging.
|
|
205
|
+
* @param {string} host Fully qualified domain name or IP address of the host
|
|
206
|
+
* @param {number} port Network port for the host to connect to
|
|
207
|
+
*/ onConnect(connectionType, host, port) {
|
|
208
|
+
// If the onConnect function has already run, do not execute it again.
|
|
209
|
+
if (this.onConnectHasRun) return;
|
|
210
|
+
// Log that the connection has been established.
|
|
211
|
+
(0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).network(`Established ${connectionType} connection with '${host}:${port}'.`);
|
|
212
|
+
// Forward the socket events
|
|
213
|
+
this.tcpSocket.addListener("close", this.eventForwarders.disconnect);
|
|
214
|
+
this.tcpSocket.addListener("data", this.eventForwarders.tcpData);
|
|
215
|
+
// Indicate that the onConnect function has run.
|
|
216
|
+
this.onConnectHasRun = true;
|
|
217
|
+
// Emit the connect event.
|
|
218
|
+
this.emit("connect");
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Clears the disconnect timer if it is still active.
|
|
222
|
+
*/ clearDisconnectTimerOnTimeout() {
|
|
223
|
+
// Clear the retry timer if it is still active.
|
|
224
|
+
if (this.timers.disconnect) clearTimeout(this.timers.disconnect);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Forcibly terminate the connection.
|
|
228
|
+
*
|
|
229
|
+
* @throws {Error} if no connection was found
|
|
230
|
+
*/ disconnect() {
|
|
231
|
+
// Clear the disconnect timer so that the socket does not try to disconnect again later.
|
|
232
|
+
this.clearDisconnectTimerOnTimeout();
|
|
233
|
+
// Remove all event forwarders.
|
|
234
|
+
this.tcpSocket.removeListener("close", this.eventForwarders.disconnect);
|
|
235
|
+
this.tcpSocket.removeListener("data", this.eventForwarders.tcpData);
|
|
236
|
+
this.tcpSocket.removeListener("error", this.eventForwarders.tcpError);
|
|
237
|
+
// Terminate the connection.
|
|
238
|
+
this.tcpSocket.destroy();
|
|
239
|
+
// Remove the stored socket.
|
|
240
|
+
this.tcpSocket = undefined;
|
|
241
|
+
// Indicate that the onConnect function has not run and it has to be run again.
|
|
242
|
+
this.onConnectHasRun = false;
|
|
243
|
+
// Emit a disconnect event
|
|
244
|
+
this.emit("disconnect");
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Write data to the socket
|
|
248
|
+
*
|
|
249
|
+
* @param {Uint8Array | string} data Data to be written to the socket
|
|
250
|
+
* @param {function} callback Callback function to be called when the write has completed
|
|
251
|
+
*
|
|
252
|
+
* @throws {Error} if no connection was found
|
|
253
|
+
* @returns true if the message was fully flushed to the socket, false if part of the message
|
|
254
|
+
* is queued in the user memory
|
|
255
|
+
*/ write(data, callback) {
|
|
256
|
+
// Throw an error if no active connection is found
|
|
257
|
+
if (!this.tcpSocket) throw new Error("Cannot write to socket when there is no active connection");
|
|
258
|
+
// Write data to the TLS Socket and return the status indicating
|
|
259
|
+
// whether the full message was flushed to the socket
|
|
260
|
+
return this.tcpSocket.write(data, callback);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Force a disconnection if no connection is established after `timeout` milliseconds.
|
|
264
|
+
*
|
|
265
|
+
* @param {string} host Host of the connection that timed out
|
|
266
|
+
* @param {number} port Port of the connection that timed out
|
|
267
|
+
* @param {number} timeout Elapsed milliseconds
|
|
268
|
+
*/ disconnectOnTimeout(host, port, timeout) {
|
|
269
|
+
// Remove the connect listener.
|
|
270
|
+
this.removeListener("connect", this.clearDisconnectTimerOnTimeout);
|
|
271
|
+
// Create a new timeout error.
|
|
272
|
+
const timeoutError = {
|
|
273
|
+
code: "ETIMEDOUT",
|
|
274
|
+
message: `Connection to '${host}:${port}' timed out after ${timeout} milliseconds`
|
|
275
|
+
};
|
|
276
|
+
// Emit an error event so that connect is rejected upstream.
|
|
277
|
+
this.emit("error", timeoutError);
|
|
278
|
+
// Forcibly disconnect to clean up the connection on timeout
|
|
279
|
+
this.disconnect();
|
|
280
|
+
}
|
|
281
|
+
constructor(...args){
|
|
282
|
+
super(...args);
|
|
283
|
+
// Declare timers for keep-alive pings and reconnection
|
|
284
|
+
this.timers = {};
|
|
285
|
+
// Initialize boolean that indicates whether the onConnect function has run (initialize to false).
|
|
286
|
+
this.onConnectHasRun = false;
|
|
287
|
+
// Initialize event forwarding functions.
|
|
288
|
+
this.eventForwarders = {
|
|
289
|
+
disconnect: ()=>this.emit("disconnect"),
|
|
290
|
+
tcpData: (data)=>this.emit("data", data),
|
|
291
|
+
tcpError: (err)=>this.emit("error", err)
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
class $ea64e414b68fe23b$export$25b4633f61498e1 extends (0, $4QiMX$EventEmitter) {
|
|
296
|
+
/**
|
|
297
|
+
* Connect to host:port using the specified transport
|
|
298
|
+
*
|
|
299
|
+
* @param {string} host Fully qualified domain name or IP address of the host
|
|
300
|
+
* @param {number} port Network port for the host to connect to
|
|
301
|
+
* @param {TransportScheme} scheme Transport scheme to use
|
|
302
|
+
* @param {number} timeout If no connection is established after `timeout` ms, the connection is terminated
|
|
303
|
+
*
|
|
304
|
+
* @throws {Error} if an incorrect transport scheme is specified
|
|
305
|
+
*/ connect(host, port, scheme, timeout) {
|
|
306
|
+
// Check that no existing socket exists before initiating a new connection.
|
|
307
|
+
if (this.webSocket) throw new Error("Cannot initiate a new socket connection when an existing connection exists");
|
|
308
|
+
// Set a timer to force disconnect after `timeout` seconds
|
|
309
|
+
this.timers.disconnect = setTimeout(()=>this.disconnectOnTimeout(host, port, timeout), timeout);
|
|
310
|
+
// Remove the timer if a connection is successfully established
|
|
311
|
+
this.once("connect", this.clearDisconnectTimerOnTimeout);
|
|
312
|
+
// Define how to refer to the connection scheme in debug output.
|
|
313
|
+
const socketTypes = {
|
|
215
314
|
[(0, $5abc8fb342687c03$export$d048df559e6d3842).WS.Scheme]: "a WebSocket",
|
|
216
315
|
[(0, $5abc8fb342687c03$export$d048df559e6d3842).WSS.Scheme]: "an encrypted WebSocket"
|
|
217
316
|
};
|
|
218
317
|
// Log that we are trying to establish a connection.
|
|
219
318
|
(0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).network(`Initiating ${socketTypes[scheme]} connection to '${host}:${port}'.`);
|
|
220
|
-
if (scheme
|
|
221
|
-
if (scheme === (0, $5abc8fb342687c03$export$d048df559e6d3842).TCP_TLS.Scheme) {
|
|
222
|
-
// Initialize connection options.
|
|
223
|
-
const connectionOptions = {
|
|
224
|
-
rejectUnauthorized: false
|
|
225
|
-
};
|
|
226
|
-
// If the hostname is not an IP address..
|
|
227
|
-
if (!$4QiMX$isIP(host)) // Set the servername option which enables support for SNI.
|
|
228
|
-
// NOTE: SNI enables a server that hosts multiple domains to provide the appropriate TLS certificate.
|
|
229
|
-
connectionOptions.serverName = host;
|
|
230
|
-
// Initialize this.tcpSocket (allowing self-signed certificates).
|
|
231
|
-
this.tcpSocket = $4QiMX$connect(port, host, connectionOptions);
|
|
232
|
-
// Add a 'secureConnect' listener that checks the authorization status of
|
|
233
|
-
// the socket, and logs a warning when it uses a self signed certificate.
|
|
234
|
-
this.tcpSocket.once("secureConnect", ()=>{
|
|
235
|
-
// Cannot happen, since this event callback *only* exists on TLSSocket
|
|
236
|
-
if (!(this.tcpSocket instanceof $4QiMX$TLSSocket)) return;
|
|
237
|
-
// Force cast authorizationError from Error to string (through unknown)
|
|
238
|
-
// because it is incorrectly typed as an Error
|
|
239
|
-
const authorizationError = this.tcpSocket.authorizationError;
|
|
240
|
-
if (authorizationError === "DEPTH_ZERO_SELF_SIGNED_CERT") (0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).warning(`Connection to ${host}:${port} uses a self-signed certificate`);
|
|
241
|
-
});
|
|
242
|
-
// Trigger successful connection events.
|
|
243
|
-
this.tcpSocket.on("secureConnect", this.onConnect.bind(this, socketTypes[scheme], host, port));
|
|
244
|
-
} else {
|
|
245
|
-
// Initialize this.tcpSocket.
|
|
246
|
-
this.tcpSocket = $4QiMX$connect1({
|
|
247
|
-
host: host,
|
|
248
|
-
port: port
|
|
249
|
-
});
|
|
250
|
-
// Trigger successful connection events.
|
|
251
|
-
this.tcpSocket.on("connect", this.onConnect.bind(this, socketTypes[scheme], host, port));
|
|
252
|
-
}
|
|
253
|
-
// Configure encoding.
|
|
254
|
-
this.tcpSocket.setEncoding("utf8");
|
|
255
|
-
// Enable persistent connections with an initial delay of 0.
|
|
256
|
-
this.tcpSocket.setKeepAlive(true, 0);
|
|
257
|
-
// Disable buffering of outgoing data.
|
|
258
|
-
this.tcpSocket.setNoDelay(true);
|
|
259
|
-
// Forward the encountered errors.
|
|
260
|
-
this.tcpSocket.on("error", this.eventForwarders.tcpError);
|
|
261
|
-
} else if (scheme === (0, $5abc8fb342687c03$export$d048df559e6d3842).WS.Scheme || scheme === (0, $5abc8fb342687c03$export$d048df559e6d3842).WSS.Scheme) {
|
|
262
|
-
if (scheme === (0, $5abc8fb342687c03$export$d048df559e6d3842).WSS.Scheme) // Initialize this.webSocket (rejecting self-signed certificates).
|
|
263
|
-
// We reject self-signed certificates to match functionality of browsers.
|
|
264
|
-
this.webSocket = new (0, $4QiMX$WebSocket)(`wss://${host}:${port}`);
|
|
265
|
-
else // Initialize this.webSocket.
|
|
266
|
-
this.webSocket = new (0, $4QiMX$WebSocket)(`ws://${host}:${port}`);
|
|
267
|
-
// Trigger successful connection events.
|
|
268
|
-
this.webSocket.addEventListener("open", this.onConnect.bind(this, socketTypes[scheme], host, port));
|
|
269
|
-
// Forward the encountered errors.
|
|
270
|
-
this.webSocket.addEventListener("error", this.eventForwarders.wsError);
|
|
271
|
-
} else // Throw an error if an incorrect transport is specified
|
|
319
|
+
if (scheme !== (0, $5abc8fb342687c03$export$d048df559e6d3842).WS.Scheme && scheme !== (0, $5abc8fb342687c03$export$d048df559e6d3842).WSS.Scheme) // Throw an error if an incorrect transport is specified
|
|
272
320
|
throw new Error("Incorrect transport specified");
|
|
321
|
+
if (scheme === (0, $5abc8fb342687c03$export$d048df559e6d3842).WSS.Scheme) // Initialize this.webSocket (rejecting self-signed certificates).
|
|
322
|
+
// We reject self-signed certificates to match functionality of browsers.
|
|
323
|
+
this.webSocket = new (0, $4QiMX$WebSocket)(`wss://${host}:${port}`);
|
|
324
|
+
else // Initialize this.webSocket.
|
|
325
|
+
this.webSocket = new (0, $4QiMX$WebSocket)(`ws://${host}:${port}`);
|
|
326
|
+
// Trigger successful connection events.
|
|
327
|
+
this.webSocket.addEventListener("open", this.onConnect.bind(this, socketTypes[scheme], host, port));
|
|
328
|
+
// Forward the encountered errors.
|
|
329
|
+
this.webSocket.addEventListener("error", this.eventForwarders.wsError);
|
|
273
330
|
}
|
|
274
331
|
/**
|
|
275
332
|
* Sets up forwarding of events related to the connection.
|
|
@@ -282,15 +339,9 @@ const $5abc8fb342687c03$export$f019be48b3aacb1a = {
|
|
|
282
339
|
if (this.onConnectHasRun) return;
|
|
283
340
|
// Log that the connection has been established.
|
|
284
341
|
(0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).network(`Established ${connectionType} connection with '${host}:${port}'.`);
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
this.tcpSocket.addListener("data", this.eventForwarders.tcpData);
|
|
289
|
-
} else if (typeof this.webSocket !== "undefined") {
|
|
290
|
-
// Forward the socket events
|
|
291
|
-
this.webSocket.addEventListener("close", this.eventForwarders.disconnect);
|
|
292
|
-
this.webSocket.addEventListener("message", this.eventForwarders.wsData);
|
|
293
|
-
}
|
|
342
|
+
// Forward the socket events
|
|
343
|
+
this.webSocket.addEventListener("close", this.eventForwarders.disconnect);
|
|
344
|
+
this.webSocket.addEventListener("message", this.eventForwarders.wsData);
|
|
294
345
|
// Indicate that the onConnect function has run.
|
|
295
346
|
this.onConnectHasRun = true;
|
|
296
347
|
// Emit the connect event.
|
|
@@ -309,17 +360,7 @@ const $5abc8fb342687c03$export$f019be48b3aacb1a = {
|
|
|
309
360
|
*/ disconnect() {
|
|
310
361
|
// Clear the disconnect timer so that the socket does not try to disconnect again later.
|
|
311
362
|
this.clearDisconnectTimerOnTimeout();
|
|
312
|
-
|
|
313
|
-
if (this.tcpSocket) {
|
|
314
|
-
// Remove all event forwarders.
|
|
315
|
-
this.tcpSocket.removeListener("close", this.eventForwarders.disconnect);
|
|
316
|
-
this.tcpSocket.removeListener("data", this.eventForwarders.tcpData);
|
|
317
|
-
this.tcpSocket.removeListener("error", this.eventForwarders.tcpError);
|
|
318
|
-
// Terminate the connection.
|
|
319
|
-
this.tcpSocket.destroy();
|
|
320
|
-
// Remove the stored socket.
|
|
321
|
-
this.tcpSocket = undefined;
|
|
322
|
-
} else if (this.webSocket) try {
|
|
363
|
+
try {
|
|
323
364
|
// Remove all event forwarders.
|
|
324
365
|
this.webSocket.removeEventListener("close", this.eventForwarders.disconnect);
|
|
325
366
|
this.webSocket.removeEventListener("message", this.eventForwarders.wsData);
|
|
@@ -348,17 +389,12 @@ const $5abc8fb342687c03$export$f019be48b3aacb1a = {
|
|
|
348
389
|
* @returns true if the message was fully flushed to the socket, false if part of the message
|
|
349
390
|
* is queued in the user memory
|
|
350
391
|
*/ write(data, callback) {
|
|
351
|
-
if (this.tcpSocket) // Write data to the TLS Socket and return the status indicating whether the
|
|
352
|
-
// full message was flushed to the socket
|
|
353
|
-
return this.tcpSocket.write(data, callback);
|
|
354
|
-
if (this.webSocket) {
|
|
355
|
-
// Write data to the WebSocket
|
|
356
|
-
this.webSocket.send(data, callback);
|
|
357
|
-
// WebSockets always fit everything in a single request, so we return true
|
|
358
|
-
return true;
|
|
359
|
-
}
|
|
360
392
|
// Throw an error if no active connection is found
|
|
361
|
-
throw new Error("Cannot write to socket when there is no active connection");
|
|
393
|
+
if (!this.webSocket) throw new Error("Cannot write to socket when there is no active connection");
|
|
394
|
+
// Write data to the WebSocket
|
|
395
|
+
this.webSocket.send(data, callback);
|
|
396
|
+
// WebSockets always fit everything in a single request, so we return true
|
|
397
|
+
return true;
|
|
362
398
|
}
|
|
363
399
|
/**
|
|
364
400
|
* Force a disconnection if no connection is established after `timeout` milliseconds.
|
|
@@ -388,17 +424,37 @@ const $5abc8fb342687c03$export$f019be48b3aacb1a = {
|
|
|
388
424
|
// Initialize event forwarding functions.
|
|
389
425
|
this.eventForwarders = {
|
|
390
426
|
disconnect: ()=>this.emit("disconnect"),
|
|
391
|
-
tcpData: (data)=>this.emit("data", data),
|
|
392
427
|
wsData: (event)=>this.emit("data", `${event.data}\n`),
|
|
393
|
-
tcpError: (err)=>this.emit("error", err),
|
|
394
428
|
wsError: (event)=>this.emit("error", event.error)
|
|
395
429
|
};
|
|
396
430
|
}
|
|
397
431
|
}
|
|
398
|
-
var // export the socket.
|
|
399
|
-
$ea64e414b68fe23b$export$2e2bcd8739ae039 = $ea64e414b68fe23b$var$ElectrumSocket;
|
|
400
432
|
|
|
401
433
|
|
|
434
|
+
var $a58372b18a18806e$exports = {};
|
|
435
|
+
|
|
436
|
+
$parcel$export($a58372b18a18806e$exports, "ClientState", () => $a58372b18a18806e$export$c4f81c6d30ca200f);
|
|
437
|
+
$parcel$export($a58372b18a18806e$exports, "ConnectionStatus", () => $a58372b18a18806e$export$7516420eb880ab68);
|
|
438
|
+
// Disable indent rule for this file because it is broken (https://github.com/typescript-eslint/typescript-eslint/issues/1824)
|
|
439
|
+
/* eslint-disable @typescript-eslint/indent */ /**
|
|
440
|
+
* Enum that denotes the availability of an ElectrumClient.
|
|
441
|
+
* @enum {number}
|
|
442
|
+
* @property {0} UNAVAILABLE The client is currently not available.
|
|
443
|
+
* @property {1} AVAILABLE The client is available for use.
|
|
444
|
+
*/ var $a58372b18a18806e$export$c4f81c6d30ca200f;
|
|
445
|
+
(function(ClientState) {
|
|
446
|
+
ClientState[ClientState["UNAVAILABLE"] = 0] = "UNAVAILABLE";
|
|
447
|
+
ClientState[ClientState["AVAILABLE"] = 1] = "AVAILABLE";
|
|
448
|
+
})($a58372b18a18806e$export$c4f81c6d30ca200f || ($a58372b18a18806e$export$c4f81c6d30ca200f = {}));
|
|
449
|
+
var $a58372b18a18806e$export$7516420eb880ab68;
|
|
450
|
+
(function(ConnectionStatus) {
|
|
451
|
+
ConnectionStatus[ConnectionStatus["DISCONNECTED"] = 0] = "DISCONNECTED";
|
|
452
|
+
ConnectionStatus[ConnectionStatus["CONNECTED"] = 1] = "CONNECTED";
|
|
453
|
+
ConnectionStatus[ConnectionStatus["DISCONNECTING"] = 2] = "DISCONNECTING";
|
|
454
|
+
ConnectionStatus[ConnectionStatus["CONNECTING"] = 3] = "CONNECTING";
|
|
455
|
+
ConnectionStatus[ConnectionStatus["RECONNECTING"] = 4] = "RECONNECTING";
|
|
456
|
+
})($a58372b18a18806e$export$7516420eb880ab68 || ($a58372b18a18806e$export$7516420eb880ab68 = {}));
|
|
457
|
+
|
|
402
458
|
|
|
403
459
|
|
|
404
460
|
/**
|
|
@@ -432,15 +488,10 @@ $ea64e414b68fe23b$export$2e2bcd8739ae039 = $ea64e414b68fe23b$var$ElectrumSocket;
|
|
|
432
488
|
this.pingInterval = pingInterval;
|
|
433
489
|
this.reconnectInterval = reconnectInterval;
|
|
434
490
|
this.useBigInt = useBigInt;
|
|
435
|
-
this
|
|
436
|
-
timers = {};
|
|
437
|
-
this
|
|
438
|
-
|
|
439
|
-
verifications = [];
|
|
440
|
-
this.// Initialize the connected flag to false to indicate that there is no connection
|
|
441
|
-
status = (0, $a58372b18a18806e$export$7516420eb880ab68).DISCONNECTED;
|
|
442
|
-
this.// Initialize messageBuffer to an empty string
|
|
443
|
-
messageBuffer = "";
|
|
491
|
+
this.status = (0, $a58372b18a18806e$export$7516420eb880ab68).DISCONNECTED;
|
|
492
|
+
this.timers = {};
|
|
493
|
+
this.verifications = [];
|
|
494
|
+
this.messageBuffer = "";
|
|
444
495
|
// Check if the provided version is a valid version number.
|
|
445
496
|
if (!(0, $c78f59d21170b7a6$export$2e2bcd8739ae039).versionRegexp.test(version)) // Throw an error since the version number was not valid.
|
|
446
497
|
throw new Error(`Provided version string (${version}) is not a valid protocol version number.`);
|
|
@@ -457,8 +508,12 @@ $ea64e414b68fe23b$export$2e2bcd8739ae039 = $ea64e414b68fe23b$var$ElectrumSocket;
|
|
|
457
508
|
/**
|
|
458
509
|
* Create and configures a fresh socket and attaches all relevant listeners.
|
|
459
510
|
*/ createSocket() {
|
|
460
|
-
// Initialize a new
|
|
461
|
-
this.socket = new (0, $ea64e414b68fe23b$export$
|
|
511
|
+
if (this.scheme === (0, $5abc8fb342687c03$export$d048df559e6d3842).TCP.Scheme || this.scheme === (0, $5abc8fb342687c03$export$d048df559e6d3842).TCP_TLS.Scheme) // Initialize a new ElectrumTcpSocket
|
|
512
|
+
this.socket = new (0, $ea64e414b68fe23b$export$22c0ca2c816c3e08)();
|
|
513
|
+
else if (this.scheme === (0, $5abc8fb342687c03$export$d048df559e6d3842).WS.Scheme || this.scheme === (0, $5abc8fb342687c03$export$d048df559e6d3842).WSS.Scheme) // Initialize a new ElectrumWebSocket
|
|
514
|
+
this.socket = new (0, $ea64e414b68fe23b$export$25b4633f61498e1)();
|
|
515
|
+
else // Throw an error if an incorrect transport is specified
|
|
516
|
+
throw new Error(`Provided transport (${this.scheme}) is not a valid ElectrumTransport`);
|
|
462
517
|
// Set up handlers for connection and disconnection.
|
|
463
518
|
this.socket.on("connect", this.onSocketConnect.bind(this));
|
|
464
519
|
this.socket.on("disconnect", this.onSocketDisconnect.bind(this));
|
|
@@ -882,13 +937,18 @@ const $7c0fb93e8eea922a$export$94e3360fcddccc76 = function(message) {
|
|
|
882
937
|
*/ constructor(application, version, host, port = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).PORT, scheme = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).TRANSPORT_SCHEME, timeout = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).TIMEOUT, pingInterval = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).PING_INTERVAL, reconnectInterval = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).RECONNECT, useBigInt = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).USE_BIG_INT){
|
|
883
938
|
// Initialize the event emitter.
|
|
884
939
|
super();
|
|
885
|
-
|
|
940
|
+
this.application = application;
|
|
941
|
+
this.version = version;
|
|
942
|
+
this.host = host;
|
|
943
|
+
this.port = port;
|
|
944
|
+
this.scheme = scheme;
|
|
945
|
+
this.timeout = timeout;
|
|
946
|
+
this.pingInterval = pingInterval;
|
|
947
|
+
this.reconnectInterval = reconnectInterval;
|
|
948
|
+
this.useBigInt = useBigInt;
|
|
886
949
|
this.subscriptionMethods = {};
|
|
887
|
-
// Start counting the request IDs from 0
|
|
888
950
|
this.requestId = 0;
|
|
889
|
-
// Initialize an empty dictionary for keeping track of request resolvers
|
|
890
951
|
this.requestResolvers = {};
|
|
891
|
-
// Mutex lock used to prevent simultaneous connect() and disconnect() calls.
|
|
892
952
|
this.connectionLock = new (0, $4QiMX$Mutex)();
|
|
893
953
|
// Set up a connection to an electrum server.
|
|
894
954
|
this.connection = new (0, $1326c18f93f95fee$export$2e2bcd8739ae039)(application, version, host, port, scheme, timeout, pingInterval, reconnectInterval, useBigInt);
|
|
@@ -1134,484 +1194,5 @@ $620a18299ef8d6fd$export$2e2bcd8739ae039 = $620a18299ef8d6fd$var$ElectrumClient;
|
|
|
1134
1194
|
|
|
1135
1195
|
|
|
1136
1196
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
/**
|
|
1140
|
-
* Triggers when the cluster connects to enough servers to satisfy both the cluster confidence and distribution policies.
|
|
1141
|
-
*
|
|
1142
|
-
* @event ElectrumCluster#ready
|
|
1143
|
-
* @deprecated
|
|
1144
|
-
*/ /**
|
|
1145
|
-
* Triggers when the cluster loses a connection and can no longer satisfy the cluster distribution policy.
|
|
1146
|
-
*
|
|
1147
|
-
* @event ElectrumCluster#degraded
|
|
1148
|
-
* @deprecated
|
|
1149
|
-
*/ /**
|
|
1150
|
-
* Triggers when the cluster loses a connection and can no longer satisfy the cluster confidence policy.
|
|
1151
|
-
*
|
|
1152
|
-
* @event ElectrumCluster#disabled
|
|
1153
|
-
* @deprecated
|
|
1154
|
-
*/ /**
|
|
1155
|
-
* Triggers when the cluster verifies the integrity of remote server sent data that is not a request responses.
|
|
1156
|
-
*
|
|
1157
|
-
* @event ElectrumCluster#notification
|
|
1158
|
-
* @deprecated
|
|
1159
|
-
*/ /**
|
|
1160
|
-
* High-level electrum client that provides transparent load balancing, confidence checking and/or low-latency polling.
|
|
1161
|
-
* @deprecated
|
|
1162
|
-
*/ class $9b2ed2eb52532075$var$ElectrumCluster extends (0, $4QiMX$EventEmitter) {
|
|
1163
|
-
/**
|
|
1164
|
-
* @param {string} application your application name, used to identify to the electrum hosts.
|
|
1165
|
-
* @param {string} version protocol version to use with the hosts.
|
|
1166
|
-
* @param {number} confidence wait for this number of hosts to provide identical results.
|
|
1167
|
-
* @param {number} distribution request information from this number of hosts.
|
|
1168
|
-
* @param {ClusterOrder} order select hosts to communicate with in this order.
|
|
1169
|
-
* @param {number} timeout how long network delays we will wait for before taking action, in milliseconds.
|
|
1170
|
-
* @param {number} pingInterval the time between sending pings to the electrum host, in milliseconds.
|
|
1171
|
-
* @param {number} reconnectInterval the time between reconnection attempts to the electrum host, in milliseconds.
|
|
1172
|
-
* @param {boolean} useBigInt whether to use bigint for numbers in json response.
|
|
1173
|
-
*/ constructor(application, version, confidence = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).CLUSTER_CONFIDENCE, distribution = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).CLUSTER_DISTRIBUTION, order = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).CLUSTER_ORDER, timeout = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).TIMEOUT, pingInterval = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).PING_INTERVAL, reconnectInterval = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).RECONNECT, useBigInt = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).USE_BIG_INT){
|
|
1174
|
-
// Initialize the event emitter.
|
|
1175
|
-
super();
|
|
1176
|
-
this.application = application;
|
|
1177
|
-
this.version = version;
|
|
1178
|
-
this.confidence = confidence;
|
|
1179
|
-
this.distribution = distribution;
|
|
1180
|
-
this.order = order;
|
|
1181
|
-
this.timeout = timeout;
|
|
1182
|
-
this.pingInterval = pingInterval;
|
|
1183
|
-
this.reconnectInterval = reconnectInterval;
|
|
1184
|
-
this.useBigInt = useBigInt;
|
|
1185
|
-
this.// Initialize an empty dictionary of clients in the cluster
|
|
1186
|
-
clients = {};
|
|
1187
|
-
this.// Start at 0 connected clients
|
|
1188
|
-
connections = 0;
|
|
1189
|
-
this.// Set up an empty set of notification data.
|
|
1190
|
-
notifications = {};
|
|
1191
|
-
this.// Start the cluster in DISABLED state
|
|
1192
|
-
status = (0, $a58372b18a18806e$export$c66b56bc0ff967ca).DISABLED;
|
|
1193
|
-
this.// Start counting request IDs at 0
|
|
1194
|
-
requestCounter = 0;
|
|
1195
|
-
this.// Initialize an empty dictionary for keeping track of request resolvers
|
|
1196
|
-
requestPromises = {};
|
|
1197
|
-
this.// Lock to prevent concurrency race conditions when sending requests.
|
|
1198
|
-
requestLock = new (0, $4QiMX$Mutex)();
|
|
1199
|
-
this.// Lock to prevent concurrency race conditions when receiving responses.
|
|
1200
|
-
responseLock = new (0, $4QiMX$Mutex)();
|
|
1201
|
-
// Write a log message.
|
|
1202
|
-
(0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).cluster(`Initialized empty cluster (${confidence} of ${distribution || "ALL"})`);
|
|
1203
|
-
// Print out a warning if we cannot guarantee consensus for subscription notifications.
|
|
1204
|
-
// Case 1: we don't know how many servers will be used, so warning just to be safe
|
|
1205
|
-
// Case 2: we know the number of servers needed to trust a response is less than 50%.
|
|
1206
|
-
if (distribution === (0, $a58372b18a18806e$export$436a960acc41e848).ALL || confidence / distribution <= 0.50) (0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).warning(`Subscriptions might return multiple valid responses when confidence (${confidence}) is less than 51% of distribution.`);
|
|
1207
|
-
}
|
|
1208
|
-
/**
|
|
1209
|
-
* Adds a server to the cluster.
|
|
1210
|
-
* @deprecated
|
|
1211
|
-
*
|
|
1212
|
-
* @param {string} host fully qualified domain name or IP number of the host.
|
|
1213
|
-
* @param {number} port the TCP network port of the host.
|
|
1214
|
-
* @param {TransportScheme} scheme the transport scheme to use for connection
|
|
1215
|
-
* @param {boolean} autoConnect flag indicating whether the server should automatically connect (default true)
|
|
1216
|
-
*
|
|
1217
|
-
* @throws {Error} if the cluster's version is not a valid version string.
|
|
1218
|
-
* @returns a promise that resolves when the connection has been initiated.
|
|
1219
|
-
*/ async addServer(host, port = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).PORT, scheme = (0, $5abc8fb342687c03$export$f019be48b3aacb1a).TRANSPORT_SCHEME, autoConnect = true) {
|
|
1220
|
-
// Set up a new electrum client.
|
|
1221
|
-
const client = new (0, $620a18299ef8d6fd$export$2e2bcd8739ae039)(this.application, this.version, host, port, scheme, this.timeout, this.pingInterval, this.reconnectInterval, this.useBigInt);
|
|
1222
|
-
// Define the client identity to avoid repetition.
|
|
1223
|
-
const clientIdentity = `${host}:${port}`;
|
|
1224
|
-
// Store this client.
|
|
1225
|
-
this.clients[clientIdentity] = {
|
|
1226
|
-
state: (0, $a58372b18a18806e$export$c4f81c6d30ca200f).UNAVAILABLE,
|
|
1227
|
-
connection: client
|
|
1228
|
-
};
|
|
1229
|
-
/**
|
|
1230
|
-
* Define a helper function to evaluate and log cluster status.
|
|
1231
|
-
*
|
|
1232
|
-
* @fires ElectrumCluster#ready
|
|
1233
|
-
* @fires ElectrumCluster#degraded
|
|
1234
|
-
* @fires ElectrumCluster#disabled
|
|
1235
|
-
*/ const updateClusterStatus = ()=>{
|
|
1236
|
-
// Calculate the required distribution, taking into account that distribution to all is represented with 0.
|
|
1237
|
-
const distribution = Math.max(this.confidence, this.distribution);
|
|
1238
|
-
// Check if we have enough connections to saturate distribution.
|
|
1239
|
-
if (this.connections >= distribution) // If the cluster is not currently considered ready..
|
|
1240
|
-
{
|
|
1241
|
-
if (this.status !== (0, $a58372b18a18806e$export$c66b56bc0ff967ca).READY) {
|
|
1242
|
-
// Mark the cluster as ready.
|
|
1243
|
-
this.status = (0, $a58372b18a18806e$export$c66b56bc0ff967ca).READY;
|
|
1244
|
-
// Emit the ready signal to indicate the cluster is running in a ready mode.
|
|
1245
|
-
this.emit("ready");
|
|
1246
|
-
// Write a log message with an update on the current cluster status.
|
|
1247
|
-
(0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).cluster(`Cluster status is ready (currently ${this.connections} of ${distribution} connections available.)`);
|
|
1248
|
-
}
|
|
1249
|
-
} else if (this.connections >= this.confidence) // If the cluster is not currently considered degraded..
|
|
1250
|
-
{
|
|
1251
|
-
if (this.status !== (0, $a58372b18a18806e$export$c66b56bc0ff967ca).DEGRADED) {
|
|
1252
|
-
// Mark the cluster as degraded.
|
|
1253
|
-
this.status = (0, $a58372b18a18806e$export$c66b56bc0ff967ca).DEGRADED;
|
|
1254
|
-
// Emit the degraded signal to indicate the cluster is running in a degraded mode.
|
|
1255
|
-
this.emit("degraded");
|
|
1256
|
-
// Write a log message with an update on the current cluster status.
|
|
1257
|
-
(0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).cluster(`Cluster status is degraded (only ${this.connections} of ${distribution} connections available.)`);
|
|
1258
|
-
}
|
|
1259
|
-
} else if (this.status !== (0, $a58372b18a18806e$export$c66b56bc0ff967ca).DISABLED) {
|
|
1260
|
-
// Mark the cluster as disabled.
|
|
1261
|
-
this.status = (0, $a58372b18a18806e$export$c66b56bc0ff967ca).DISABLED;
|
|
1262
|
-
// Emit the degraded signal to indicate the cluster is disabled.
|
|
1263
|
-
this.emit("disabled");
|
|
1264
|
-
// Write a log message with an update on the current cluster status.
|
|
1265
|
-
(0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).cluster(`Cluster status is disabled (only ${this.connections} of the ${distribution} connections are available.)`);
|
|
1266
|
-
}
|
|
1267
|
-
};
|
|
1268
|
-
// Define a function to run when client has connected.
|
|
1269
|
-
const onConnect = async ()=>{
|
|
1270
|
-
// Wrap in a try-catch so we can ignore errors.
|
|
1271
|
-
try {
|
|
1272
|
-
// Check connection status
|
|
1273
|
-
const connectionStatus = client.connection.status;
|
|
1274
|
-
// If the connection is fine..
|
|
1275
|
-
if (connectionStatus === (0, $a58372b18a18806e$export$7516420eb880ab68).CONNECTED) {
|
|
1276
|
-
// If this was from an unavailable connection..
|
|
1277
|
-
if (this.clients[clientIdentity].state === (0, $a58372b18a18806e$export$c4f81c6d30ca200f).UNAVAILABLE) // Update connection counter.
|
|
1278
|
-
this.connections += 1;
|
|
1279
|
-
// Set client state to available.
|
|
1280
|
-
this.clients[clientIdentity].state = (0, $a58372b18a18806e$export$c4f81c6d30ca200f).AVAILABLE;
|
|
1281
|
-
// update the cluster status.
|
|
1282
|
-
updateClusterStatus();
|
|
1283
|
-
}
|
|
1284
|
-
} catch (error) {
|
|
1285
|
-
// Do nothing.
|
|
1286
|
-
}
|
|
1287
|
-
};
|
|
1288
|
-
// Define a function to run when client disconnects.
|
|
1289
|
-
const onDisconnect = ()=>{
|
|
1290
|
-
// If this was from an established connection..
|
|
1291
|
-
if (this.clients[clientIdentity].state === (0, $a58372b18a18806e$export$c4f81c6d30ca200f).AVAILABLE) // Update connection counter.
|
|
1292
|
-
this.connections -= 1;
|
|
1293
|
-
// Set client state to unavailable.
|
|
1294
|
-
this.clients[clientIdentity].state = (0, $a58372b18a18806e$export$c4f81c6d30ca200f).UNAVAILABLE;
|
|
1295
|
-
// update the cluster status.
|
|
1296
|
-
updateClusterStatus();
|
|
1297
|
-
};
|
|
1298
|
-
// Set up handlers for connection and disconnection.
|
|
1299
|
-
client.connection.on("connect", onConnect.bind(this));
|
|
1300
|
-
client.connection.on("disconnect", onDisconnect.bind(this));
|
|
1301
|
-
// Set up handler for notification events, that includes the identity of this client so it can be tracked.
|
|
1302
|
-
client.on("notification", this.handleSubscriptionNotifications.bind(this, clientIdentity));
|
|
1303
|
-
// Connect if auto-connect is set to true, returning the connection result.
|
|
1304
|
-
if (autoConnect) try {
|
|
1305
|
-
// Set up the connection.
|
|
1306
|
-
await client.connect();
|
|
1307
|
-
} catch (error) {
|
|
1308
|
-
// Log a message why the connection failed and move on.
|
|
1309
|
-
(0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).cluster(`Failed to connect with ${host}: ${error}`);
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
/**
|
|
1313
|
-
* Calls a method on the remote server with the supplied parameters.
|
|
1314
|
-
* @deprecated
|
|
1315
|
-
*
|
|
1316
|
-
* @param {string} method name of the method to call.
|
|
1317
|
-
* @param {...string} parameters one or more parameters for the method.
|
|
1318
|
-
*
|
|
1319
|
-
* @throws {Error} if not enough clients are connected
|
|
1320
|
-
* @throws {Error} if no response is received with sufficient integrity
|
|
1321
|
-
* @returns a promise that resolves with the result of the method.
|
|
1322
|
-
*/ async request(method, ...parameters) {
|
|
1323
|
-
// Check if the cluster is unable to serve requests.
|
|
1324
|
-
if (this.status === (0, $a58372b18a18806e$export$c66b56bc0ff967ca).DISABLED) throw new Error(`Cannot request '${method}' when available clients (${this.connections}) is less than required confidence (${this.confidence}).`);
|
|
1325
|
-
// Lock this request method temporarily.
|
|
1326
|
-
const unlock = await this.requestLock.acquire();
|
|
1327
|
-
// Declare requestId outside of try-catch scope.
|
|
1328
|
-
let requestId = 0;
|
|
1329
|
-
// NOTE: If this async method is called very rapidly, it's theoretically possible that the parts below could interfere.
|
|
1330
|
-
try {
|
|
1331
|
-
// Increase the current request counter.
|
|
1332
|
-
this.requestCounter += 1;
|
|
1333
|
-
// Copy the request counter so we can work with the copy and know it won't change
|
|
1334
|
-
// even if the request counter is raised from concurrent requests.
|
|
1335
|
-
requestId = this.requestCounter;
|
|
1336
|
-
} finally{
|
|
1337
|
-
// Unlock this request method now that the concurrency sensitive condition is completed.
|
|
1338
|
-
unlock();
|
|
1339
|
-
}
|
|
1340
|
-
// Initialize an empty list of request promises.
|
|
1341
|
-
this.requestPromises[requestId] = [];
|
|
1342
|
-
// Extract all available client IDs
|
|
1343
|
-
const availableClientIDs = Object.keys(this.clients).filter((clientID)=>this.clients[clientID].state === (0, $a58372b18a18806e$export$c4f81c6d30ca200f).AVAILABLE);
|
|
1344
|
-
// Initialize a sent counter.
|
|
1345
|
-
let sentCounter = 0;
|
|
1346
|
-
// Determine the number of clients we need to send to, taking ClusterDistribution.ALL (=0) into account.
|
|
1347
|
-
let requiredDistribution = this.distribution || availableClientIDs.length;
|
|
1348
|
-
// If the cluster is in degraded status, we do not have enough available clients to
|
|
1349
|
-
// match distribution, but still enough to reach consensus, so we use the clients we have.
|
|
1350
|
-
if (this.status === (0, $a58372b18a18806e$export$c66b56bc0ff967ca).DEGRADED) requiredDistribution = availableClientIDs.length;
|
|
1351
|
-
// Repeat until we have sent the request to the desired number of clients.
|
|
1352
|
-
while(sentCounter < requiredDistribution){
|
|
1353
|
-
// Pick an array index according to our ordering strategy.
|
|
1354
|
-
let currentIndex = 0;
|
|
1355
|
-
// Use a random array index when cluster order is set to RANDOM
|
|
1356
|
-
if (this.order === (0, $a58372b18a18806e$export$161fe3707f756bf9).RANDOM) currentIndex = Math.floor(Math.random() * availableClientIDs.length);
|
|
1357
|
-
// Move a client identity from the client list to its own variable.
|
|
1358
|
-
const [currentClient] = availableClientIDs.splice(currentIndex, 1);
|
|
1359
|
-
// Send the request to the client and store the request promise.
|
|
1360
|
-
const requestPromise = this.clients[currentClient].connection.request(method, ...parameters);
|
|
1361
|
-
this.requestPromises[requestId].push(requestPromise);
|
|
1362
|
-
// Increase the sent counter.
|
|
1363
|
-
sentCounter += 1;
|
|
1364
|
-
}
|
|
1365
|
-
// Define a function to poll for request responses.
|
|
1366
|
-
const pollResponse = (resolve, reject)=>{
|
|
1367
|
-
// Define a function to resolve request responses based on integrity.
|
|
1368
|
-
const resolveRequest = async ()=>{
|
|
1369
|
-
// Set up an empty set of response data.
|
|
1370
|
-
const responseData = {};
|
|
1371
|
-
// Set up a counter to keep track of how many responses we have checked.
|
|
1372
|
-
let checkedResponses = 0;
|
|
1373
|
-
// For each server we issued a request to..
|
|
1374
|
-
for(const currentPromise in this.requestPromises[requestId]){
|
|
1375
|
-
// Initialize a holder for the response in the required scope to use it.
|
|
1376
|
-
let response;
|
|
1377
|
-
// Race the request promise against a pre-resolved request to determine request status.
|
|
1378
|
-
try {
|
|
1379
|
-
// Arrange an array of the current promise and an empty promise such that..
|
|
1380
|
-
const promises = [
|
|
1381
|
-
this.requestPromises[requestId][currentPromise],
|
|
1382
|
-
Promise.resolve(undefined)
|
|
1383
|
-
];
|
|
1384
|
-
// .. we can get the result of the current promise if it is currently resolved, but don't need to wait for it otherwise.
|
|
1385
|
-
response = await Promise.race(promises);
|
|
1386
|
-
} // Handle case where the request sent resulted in a thrown error / promise rejection, rather then resolving to a response.
|
|
1387
|
-
// Note that in the worst time case, each request can be expected to eventually throw an error on timeout.
|
|
1388
|
-
catch (error) {
|
|
1389
|
-
// Increase the counter for checked responses.
|
|
1390
|
-
checkedResponses += 1;
|
|
1391
|
-
continue;
|
|
1392
|
-
}
|
|
1393
|
-
// If the promise is settled..
|
|
1394
|
-
if (response !== undefined) {
|
|
1395
|
-
// Calculate a unique identifier for this notification data.
|
|
1396
|
-
const responseDataIdentifier = (0, $4QiMX$stringify)(response);
|
|
1397
|
-
// Increase the counter for checked responses.
|
|
1398
|
-
checkedResponses += 1;
|
|
1399
|
-
// Either set the response data counter or increase it.
|
|
1400
|
-
if (responseData[responseDataIdentifier] === undefined) responseData[responseDataIdentifier] = 1;
|
|
1401
|
-
else responseData[responseDataIdentifier] += 1;
|
|
1402
|
-
// Check if this response has enough integrity according to our confidence strategy.
|
|
1403
|
-
if (responseData[responseDataIdentifier] === this.confidence) {
|
|
1404
|
-
// Write log entry.
|
|
1405
|
-
(0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).cluster(`Validated response for '${method}' with sufficient integrity (${this.confidence}).`);
|
|
1406
|
-
// Resolve the request with this response.
|
|
1407
|
-
resolve(response);
|
|
1408
|
-
// Return after resolving since we do not want to continue the execution.
|
|
1409
|
-
return;
|
|
1410
|
-
}
|
|
1411
|
-
}
|
|
1412
|
-
}
|
|
1413
|
-
// If all clients have responded but we failed to reach desired integrity..
|
|
1414
|
-
if (checkedResponses === this.requestPromises[requestId].length) {
|
|
1415
|
-
// Reject this request with an error message.
|
|
1416
|
-
reject(new Error(`Unable to complete request for '${method}', response failed to reach sufficient integrity (${this.confidence}).`));
|
|
1417
|
-
// Return after rejecting since we do not want to continue the execution.
|
|
1418
|
-
return;
|
|
1419
|
-
}
|
|
1420
|
-
// If we are not ready, but have not timed out and should wait more..
|
|
1421
|
-
setTimeout(resolveRequest, 1000);
|
|
1422
|
-
};
|
|
1423
|
-
// Attempt the initial resolution of the request.
|
|
1424
|
-
resolveRequest();
|
|
1425
|
-
};
|
|
1426
|
-
// return some kind of promise that resolves when integrity number of clients results match.
|
|
1427
|
-
return new Promise(pollResponse);
|
|
1428
|
-
}
|
|
1429
|
-
/**
|
|
1430
|
-
* Subscribes to the method at the cluster and attaches the callback function to the event feed.
|
|
1431
|
-
* @deprecated
|
|
1432
|
-
*
|
|
1433
|
-
* @note the response for the subscription request is issued as a notification event.
|
|
1434
|
-
*
|
|
1435
|
-
* @param {string} method one of the subscribable methods the server supports.
|
|
1436
|
-
* @param {...string} parameters one or more parameters for the method.
|
|
1437
|
-
*
|
|
1438
|
-
* @throws {Error} if not enough clients are connected
|
|
1439
|
-
* @throws {Error} if no response is received with sufficient integrity for the initial request
|
|
1440
|
-
*/ async subscribe(method, ...parameters) {
|
|
1441
|
-
// Set up event listener for this subscription.
|
|
1442
|
-
for(const currentClient in this.clients){
|
|
1443
|
-
// Copy the current client for brevity.
|
|
1444
|
-
const client = this.clients[currentClient].connection;
|
|
1445
|
-
try {
|
|
1446
|
-
// Send initial subscription request.
|
|
1447
|
-
// NOTE: This stores and manages the subscription even if the initial request fails.
|
|
1448
|
-
await client.subscribe(method, ...parameters);
|
|
1449
|
-
} catch (error) {
|
|
1450
|
-
// Do nothing, as this is handled on a best-effort basis and
|
|
1451
|
-
// not all servers are expected to be ready at all times.
|
|
1452
|
-
}
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
/**
|
|
1456
|
-
* Unsubscribes to the method at the cluster and removes any callback functions
|
|
1457
|
-
* when there are no more subscriptions for the method.
|
|
1458
|
-
* @deprecated
|
|
1459
|
-
*
|
|
1460
|
-
* @param {string} method one of the subscribable methods the server supports.
|
|
1461
|
-
* @param {...string} parameters one or more parameters for the method.
|
|
1462
|
-
*
|
|
1463
|
-
* @throws {Error} if, for any of the clients, no subscriptions exist for the combination of the provided `method` and `parameters.
|
|
1464
|
-
*/ async unsubscribe(method, ...parameters) {
|
|
1465
|
-
// Initialize an empty list to track subscription requests.
|
|
1466
|
-
const unsubscriptionPromises = [];
|
|
1467
|
-
// For each client..
|
|
1468
|
-
for(const currentClient in this.clients){
|
|
1469
|
-
// Store client in variable for brevity
|
|
1470
|
-
const client = this.clients[currentClient].connection;
|
|
1471
|
-
// unsubscribe this client.
|
|
1472
|
-
unsubscriptionPromises.push(client.unsubscribe(method, ...parameters));
|
|
1473
|
-
}
|
|
1474
|
-
// Wait for all unsubscription promises to resolve.
|
|
1475
|
-
await Promise.all(unsubscriptionPromises);
|
|
1476
|
-
}
|
|
1477
|
-
/**
|
|
1478
|
-
* Define a callback function to validate server notifications and pass them to the subscribe callback.
|
|
1479
|
-
* @deprecated
|
|
1480
|
-
*
|
|
1481
|
-
* @ignore
|
|
1482
|
-
*/ async handleSubscriptionNotifications(clientIdentity, data) {
|
|
1483
|
-
// Lock this response method temporarily.
|
|
1484
|
-
const unlock = await this.responseLock.acquire();
|
|
1485
|
-
try {
|
|
1486
|
-
// Calculate a unique identifier for this notification data.
|
|
1487
|
-
const responseDataIdentifier = (0, $4QiMX$stringify)(data);
|
|
1488
|
-
// Create an empty list of clients who have responded to this notification, if necessary.
|
|
1489
|
-
if (this.notifications[responseDataIdentifier] === undefined) this.notifications[responseDataIdentifier] = new Set();
|
|
1490
|
-
// Ensure this client is on the list of clients that have provided this specific notification.
|
|
1491
|
-
this.notifications[responseDataIdentifier].add(clientIdentity);
|
|
1492
|
-
// Check if this notification has enough integrity according to our confidence strategy.
|
|
1493
|
-
// NOTE: We check against === instead of >== in order to ensure that we only emit each notification once.
|
|
1494
|
-
if (this.notifications[responseDataIdentifier].size === this.confidence) {
|
|
1495
|
-
// Write log entry.
|
|
1496
|
-
(0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).cluster(`Validated notification for '${data.method}' with sufficient integrity (${this.confidence}).`);
|
|
1497
|
-
// Emit an event for the notification data.
|
|
1498
|
-
this.emit("notification", data);
|
|
1499
|
-
// Dismiss the notification data after all nodes are assumed to have sent their notifications.
|
|
1500
|
-
// NOTE: This is a redundant mechanic to ensure that even if some nodes don't provide this notification, we still clear this data.
|
|
1501
|
-
// NOTE: This also introduces a race-condition where if a legit identical notification comes in before/during this timeout, it might get silenced.
|
|
1502
|
-
setTimeout(this.dismissSubscriptionNotification.bind(this, responseDataIdentifier), this.timeout);
|
|
1503
|
-
}
|
|
1504
|
-
// Check if this notification has been fully handled.
|
|
1505
|
-
if (this.notifications[responseDataIdentifier].size === this.distribution) // Dismiss existing response data as we know all related parties have provided their input.
|
|
1506
|
-
this.dismissSubscriptionNotification(responseDataIdentifier);
|
|
1507
|
-
} finally{
|
|
1508
|
-
// Unlock the response method so it can handle the next set of data.
|
|
1509
|
-
unlock();
|
|
1510
|
-
}
|
|
1511
|
-
}
|
|
1512
|
-
/**
|
|
1513
|
-
* Forgets/Removes notification data for a specific notification.
|
|
1514
|
-
*
|
|
1515
|
-
* This is required in order to allow future identical notifications to be properly processed and emitted.
|
|
1516
|
-
* @deprecated
|
|
1517
|
-
*/ async dismissSubscriptionNotification(responseDataIdentifier) {
|
|
1518
|
-
delete this.notifications[responseDataIdentifier];
|
|
1519
|
-
}
|
|
1520
|
-
/**
|
|
1521
|
-
* Provides a method to check or wait for the cluster to become ready.
|
|
1522
|
-
* @deprecated
|
|
1523
|
-
*
|
|
1524
|
-
* @returns a promise that resolves when the required servers are available.
|
|
1525
|
-
*/ async ready() {
|
|
1526
|
-
// Store the current timestamp.
|
|
1527
|
-
const readyTimestamp = Date.now();
|
|
1528
|
-
// Define a function to poll for availability of the cluster.
|
|
1529
|
-
const availabilityPoller = (resolve)=>{
|
|
1530
|
-
// Define a function to check if the cluster is ready to be used.
|
|
1531
|
-
const connectionAvailabilityVerifier = ()=>{
|
|
1532
|
-
// Check if the cluster is active..
|
|
1533
|
-
if (this.status === (0, $a58372b18a18806e$export$c66b56bc0ff967ca).READY) {
|
|
1534
|
-
// Resolve with true to indicate that the cluster is ready to use.
|
|
1535
|
-
resolve(true);
|
|
1536
|
-
// Return after resolving since we do not want to continue the execution.
|
|
1537
|
-
return;
|
|
1538
|
-
}
|
|
1539
|
-
// Calculate how long we have waited, in milliseconds.
|
|
1540
|
-
const timeWaited = Date.now() - readyTimestamp;
|
|
1541
|
-
// Check if we have waited longer than our timeout setting.
|
|
1542
|
-
if (timeWaited > this.timeout) {
|
|
1543
|
-
// Resolve with false to indicate that we did not get ready in time.
|
|
1544
|
-
resolve(false);
|
|
1545
|
-
// Return after resolving since we do not want to continue the execution.
|
|
1546
|
-
return;
|
|
1547
|
-
}
|
|
1548
|
-
// If we are not ready, but have not timed out and should wait more..
|
|
1549
|
-
setTimeout(connectionAvailabilityVerifier, 50);
|
|
1550
|
-
};
|
|
1551
|
-
// Run the initial verification.
|
|
1552
|
-
connectionAvailabilityVerifier();
|
|
1553
|
-
};
|
|
1554
|
-
// Return a promise that resolves when the available clients is sufficient.
|
|
1555
|
-
return new Promise(availabilityPoller);
|
|
1556
|
-
}
|
|
1557
|
-
/**
|
|
1558
|
-
* Connects all servers from the cluster and attaches event listeners and handlers
|
|
1559
|
-
* for all underlying clients and connections.
|
|
1560
|
-
* @deprecated
|
|
1561
|
-
*
|
|
1562
|
-
* @throws {Error} if the cluster's version is not a valid version string.
|
|
1563
|
-
*/ async startup() {
|
|
1564
|
-
// Write a log message.
|
|
1565
|
-
(0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).cluster("Starting up cluster.");
|
|
1566
|
-
// Keep track of all connections
|
|
1567
|
-
const connections = [];
|
|
1568
|
-
// Loop over all clients and reconnect them if they're disconnected
|
|
1569
|
-
for(const clientKey in this.clients){
|
|
1570
|
-
// Retrieve connection information for the client
|
|
1571
|
-
const { host: host, port: port, scheme: scheme } = this.clients[clientKey].connection.connection;
|
|
1572
|
-
// Only connect currently unavailable/disconnected clients
|
|
1573
|
-
if (this.clients[clientKey].state === (0, $a58372b18a18806e$export$c4f81c6d30ca200f).AVAILABLE) // Warn when a server is already connected when calling startup()
|
|
1574
|
-
(0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).warning(`Called startup(), but server ${host}:${port} is already connected`);
|
|
1575
|
-
else // Call the addServer() function with the existing connection data
|
|
1576
|
-
// This effectively reconnects the server and re-instates all event listeners
|
|
1577
|
-
connections.push(this.addServer(host, port, scheme));
|
|
1578
|
-
}
|
|
1579
|
-
// Await all connections
|
|
1580
|
-
return Promise.all(connections);
|
|
1581
|
-
}
|
|
1582
|
-
/**
|
|
1583
|
-
* Disconnects all servers from the cluster. Removes all event listeners and
|
|
1584
|
-
* handlers from all underlying clients and connections. This includes all
|
|
1585
|
-
* active subscriptions, unless retainSubscriptions is set to true.
|
|
1586
|
-
* @deprecated
|
|
1587
|
-
*
|
|
1588
|
-
* @param {boolean} retainSubscriptions retain subscription data so they will be restored on reconnection.
|
|
1589
|
-
*
|
|
1590
|
-
* @returns a list with the disconnection result for every client
|
|
1591
|
-
*/ async shutdown(retainSubscriptions = false) {
|
|
1592
|
-
// Write a log message.
|
|
1593
|
-
(0, $ef5ba40c8abe5a13$export$2e2bcd8739ae039).cluster("Shutting down cluster.");
|
|
1594
|
-
// Set up a list of disconnections to wait for.
|
|
1595
|
-
const disconnections = [];
|
|
1596
|
-
const disconnectResolver = (resolve)=>{
|
|
1597
|
-
// Resolve once the cluster is marked as disabled
|
|
1598
|
-
this.once("disabled", ()=>resolve(Promise.all(disconnections)));
|
|
1599
|
-
// For each client in this cluster..
|
|
1600
|
-
for(const clientIndex in this.clients)// Force disconnection regardless of current status.
|
|
1601
|
-
disconnections.push(this.clients[clientIndex].connection.disconnect(true, retainSubscriptions));
|
|
1602
|
-
};
|
|
1603
|
-
// Return a list of booleans indicating disconnections from all clients
|
|
1604
|
-
return new Promise(disconnectResolver);
|
|
1605
|
-
}
|
|
1606
|
-
}
|
|
1607
|
-
var // Export the cluster.
|
|
1608
|
-
$9b2ed2eb52532075$export$2e2bcd8739ae039 = $9b2ed2eb52532075$var$ElectrumCluster;
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
export {$620a18299ef8d6fd$export$2e2bcd8739ae039 as ElectrumClient, $9b2ed2eb52532075$export$2e2bcd8739ae039 as ElectrumCluster, $a192ea5a4eec42d4$export$e1f38ab2b4ebdde6 as isVersionRejected, $a192ea5a4eec42d4$export$9598f0c76aa41d73 as isVersionNegotiated, $5abc8fb342687c03$export$d048df559e6d3842 as ElectrumTransport, $5abc8fb342687c03$export$f019be48b3aacb1a as DefaultParameters, $a58372b18a18806e$export$161fe3707f756bf9 as ClusterOrder, $a58372b18a18806e$export$436a960acc41e848 as ClusterDistribution, $a58372b18a18806e$export$c66b56bc0ff967ca as ClusterStatus, $a58372b18a18806e$export$c4f81c6d30ca200f as ClientState, $a58372b18a18806e$export$7516420eb880ab68 as ConnectionStatus};
|
|
1197
|
+
export {$620a18299ef8d6fd$export$2e2bcd8739ae039 as ElectrumClient, $a192ea5a4eec42d4$export$e1f38ab2b4ebdde6 as isVersionRejected, $a192ea5a4eec42d4$export$9598f0c76aa41d73 as isVersionNegotiated, $5abc8fb342687c03$export$d048df559e6d3842 as ElectrumTransport, $5abc8fb342687c03$export$f019be48b3aacb1a as DefaultParameters, $a58372b18a18806e$export$c4f81c6d30ca200f as ClientState, $a58372b18a18806e$export$7516420eb880ab68 as ConnectionStatus};
|
|
1617
1198
|
//# sourceMappingURL=index.mjs.map
|