xud
Version:
Exchange Union Daemon
222 lines • 11.1 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientStatus = exports.PaymentState = void 0;
const events_1 = require("events");
const utils_1 = require("../utils/utils");
var ClientStatus;
(function (ClientStatus) {
/** The starting status before a client has initialized. */
ClientStatus[ClientStatus["NotInitialized"] = 0] = "NotInitialized";
/** The client has been initialized but has not attempted to connect to the server yet. */
ClientStatus[ClientStatus["Initialized"] = 1] = "Initialized";
/** The client is permanently disabled. */
ClientStatus[ClientStatus["Disabled"] = 2] = "Disabled";
/** The server cannot be reached or is not responding properly. */
ClientStatus[ClientStatus["Disconnected"] = 3] = "Disconnected";
/** The server is reachable and operational. */
ClientStatus[ClientStatus["ConnectionVerified"] = 4] = "ConnectionVerified";
/** The server is reachable but is not ready pending completion of blockchain or network sync. */
ClientStatus[ClientStatus["OutOfSync"] = 5] = "OutOfSync";
/** The server is reachable but needs to be unlocked before it accepts calls. */
ClientStatus[ClientStatus["WaitingUnlock"] = 6] = "WaitingUnlock";
/** The server has been unlocked, but its status has not been verified yet. */
ClientStatus[ClientStatus["Unlocked"] = 7] = "Unlocked";
/** The client could not be initialized due to faulty configuration. */
ClientStatus[ClientStatus["Misconfigured"] = 8] = "Misconfigured";
/** The server is reachable but hold invoices are not supported. */
ClientStatus[ClientStatus["NoHoldInvoiceSupport"] = 9] = "NoHoldInvoiceSupport";
})(ClientStatus || (ClientStatus = {}));
exports.ClientStatus = ClientStatus;
var PaymentState;
(function (PaymentState) {
PaymentState[PaymentState["Succeeded"] = 0] = "Succeeded";
PaymentState[PaymentState["Failed"] = 1] = "Failed";
PaymentState[PaymentState["Pending"] = 2] = "Pending";
})(PaymentState = exports.PaymentState || (exports.PaymentState = {}));
/**
* A base class to represent an external swap client such as lnd or connext.
*/
let SwapClient = /** @class */ (() => {
class SwapClient extends events_1.EventEmitter {
constructor(logger, disable) {
super();
this.logger = logger;
this.disable = disable;
this.status = ClientStatus.NotInitialized;
this.verifyConnectionWithTimeout = () => {
// don't wait longer than the allotted time for the connection to
// be verified to prevent initialization from hanging
return new Promise((resolve, reject) => {
const verifyTimeout = setTimeout(() => {
// we could not verify the connection within the allotted time
this.logger.info(`could not verify connection within initialization time limit of ${SwapClient.INITIALIZATION_TIME_LIMIT}`);
this.setStatus(ClientStatus.Disconnected);
resolve();
}, SwapClient.INITIALIZATION_TIME_LIMIT);
this.verifyConnection().then(() => {
clearTimeout(verifyTimeout);
resolve();
}).catch(reject);
});
};
this.init = () => __awaiter(this, void 0, void 0, function* () {
// up front checks before initializing client
if (this.disable) {
this.setStatus(ClientStatus.Disabled);
return;
}
if (!this.isNotInitialized() && !this.isMisconfigured()) {
// we only initialize from NotInitialized or Misconfigured status
this.logger.warn(`can not init in ${this.status} status`);
return;
}
// client specific initialization
yield this.initSpecific();
// check to make sure that the client wasn't disabled in the initSpecific routine
if (this.isNotInitialized()) {
// final steps to complete initialization
this.setStatus(ClientStatus.Initialized);
this.setTimers();
this.emit('initialized');
yield this.verifyConnectionWithTimeout();
}
});
this.setConnected = (newIdentifier, newUris) => __awaiter(this, void 0, void 0, function* () {
// we wait briefly to update the capacities for this swap client then proceed to set status to connected
yield Promise.race([this.updateCapacity(), utils_1.setTimeoutPromise(SwapClient.CAPACITY_REFRESH_INTERVAL)]);
this.setStatus(ClientStatus.ConnectionVerified);
this.emit('connectionVerified', {
newIdentifier,
newUris,
});
});
this.setStatus = (newStatus) => {
if (this.status === newStatus) {
return;
}
let validStatusTransition;
switch (newStatus) {
case ClientStatus.Disabled:
case ClientStatus.Misconfigured:
case ClientStatus.Initialized:
// these statuses can only be set on a client that has not been initialized
validStatusTransition = this.isNotInitialized();
break;
case ClientStatus.Unlocked:
// this status can only be set on a client that is waiting unlock
validStatusTransition = this.isWaitingUnlock();
break;
case ClientStatus.ConnectionVerified:
case ClientStatus.Disconnected:
case ClientStatus.WaitingUnlock:
case ClientStatus.OutOfSync:
case ClientStatus.NoHoldInvoiceSupport:
// these statuses can only be set on an operational, initialized client
validStatusTransition = this.isOperational();
break;
case ClientStatus.NotInitialized:
// this is the starting status and cannot be reassigned
validStatusTransition = false;
break;
}
if (validStatusTransition) {
this.logger.info(`new status: ${ClientStatus[newStatus]}`);
this.status = newStatus;
}
else {
this.logger.error(`cannot set status to ${ClientStatus[newStatus]} from ${ClientStatus[this.status]}`);
}
};
this.updateCapacityTimerCallback = () => __awaiter(this, void 0, void 0, function* () {
if (this.isConnected()) {
yield this.updateCapacity();
}
});
this.reconnectionTimerCallback = () => __awaiter(this, void 0, void 0, function* () {
if (this.status === ClientStatus.Disconnected
|| this.status === ClientStatus.OutOfSync
|| this.status === ClientStatus.WaitingUnlock
|| this.status === ClientStatus.Unlocked) {
try {
yield this.verifyConnection();
}
catch (err) {
this.logger.debug(`reconnectionTimer errored with ${err}`);
}
}
if (this.reconnectionTimer) {
this.reconnectionTimer.refresh();
}
});
this.setTimers = () => {
if (!this.updateCapacityTimer) {
this.updateCapacityTimer = setInterval(this.updateCapacityTimerCallback, SwapClient.CAPACITY_REFRESH_INTERVAL);
}
if (!this.reconnectionTimer) {
this.reconnectionTimer = setTimeout(this.reconnectionTimerCallback, SwapClient.RECONNECT_INTERVAL);
}
};
}
isConnected() {
return this.status === ClientStatus.ConnectionVerified;
}
isDisabled() {
return this.status === ClientStatus.Disabled;
}
isMisconfigured() {
return this.status === ClientStatus.Misconfigured;
}
/**
* Returns `true` if the client is enabled and configured properly.
*/
isOperational() {
return !this.isDisabled() && !this.isMisconfigured() && !this.isNotInitialized();
}
isDisconnected() {
return this.status === ClientStatus.Disconnected;
}
isWaitingUnlock() {
return this.status === ClientStatus.WaitingUnlock;
}
isNotInitialized() {
return this.status === ClientStatus.NotInitialized;
}
isOutOfSync() {
return this.status === ClientStatus.OutOfSync;
}
hasNoInvoiceSupport() {
return this.status === ClientStatus.NoHoldInvoiceSupport;
}
/** Ends all connections, subscriptions, and timers for for this client. */
close() {
this.disconnect();
if (this.reconnectionTimer) {
clearTimeout(this.reconnectionTimer);
this.reconnectionTimer = undefined;
}
if (this.updateCapacityTimer) {
clearInterval(this.updateCapacityTimer);
this.updateCapacityTimer = undefined;
}
this.removeAllListeners();
}
}
/** Time in milliseconds between attempts to recheck connectivity to the client. */
SwapClient.RECONNECT_INTERVAL = 5000;
/** The maximum amount of time we will wait for the connection to be verified during initialization. */
SwapClient.INITIALIZATION_TIME_LIMIT = 5000;
/** Time in milliseconds between updating the maximum outbound capacity. */
SwapClient.CAPACITY_REFRESH_INTERVAL = 3000;
return SwapClient;
})();
exports.default = SwapClient;
//# sourceMappingURL=SwapClient.js.map