Websocket subscription for fallback server health status
This commit is contained in:
parent
8405e5ff07
commit
f63f1b1773
@ -29,6 +29,7 @@ export interface AbstractBitcoinApi {
|
|||||||
$getOutSpendsByOutpoint(outpoints: { txid: string, vout: number }[]): Promise<IEsploraApi.Outspend[]>;
|
$getOutSpendsByOutpoint(outpoints: { txid: string, vout: number }[]): Promise<IEsploraApi.Outspend[]>;
|
||||||
|
|
||||||
startHealthChecks(): void;
|
startHealthChecks(): void;
|
||||||
|
getHealthStatus(): HealthCheckHost[];
|
||||||
}
|
}
|
||||||
export interface BitcoinRpcCredentials {
|
export interface BitcoinRpcCredentials {
|
||||||
host: string;
|
host: string;
|
||||||
@ -38,3 +39,14 @@ export interface BitcoinRpcCredentials {
|
|||||||
timeout: number;
|
timeout: number;
|
||||||
cookie?: string;
|
cookie?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface HealthCheckHost {
|
||||||
|
host: string;
|
||||||
|
active: boolean;
|
||||||
|
rtt: number;
|
||||||
|
latestHeight: number;
|
||||||
|
socket: boolean;
|
||||||
|
outOfSync: boolean;
|
||||||
|
unreachable: boolean;
|
||||||
|
checked: boolean;
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as bitcoinjs from 'bitcoinjs-lib';
|
import * as bitcoinjs from 'bitcoinjs-lib';
|
||||||
import { AbstractBitcoinApi } from './bitcoin-api-abstract-factory';
|
import { AbstractBitcoinApi, HealthCheckHost } from './bitcoin-api-abstract-factory';
|
||||||
import { IBitcoinApi } from './bitcoin-api.interface';
|
import { IBitcoinApi } from './bitcoin-api.interface';
|
||||||
import { IEsploraApi } from './esplora-api.interface';
|
import { IEsploraApi } from './esplora-api.interface';
|
||||||
import blocks from '../blocks';
|
import blocks from '../blocks';
|
||||||
@ -382,6 +382,10 @@ class BitcoinApi implements AbstractBitcoinApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public startHealthChecks(): void {};
|
public startHealthChecks(): void {};
|
||||||
|
|
||||||
|
public getHealthStatus() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default BitcoinApi;
|
export default BitcoinApi;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
import axios, { AxiosResponse } from 'axios';
|
import axios from 'axios';
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
import { AbstractBitcoinApi } from './bitcoin-api-abstract-factory';
|
import { AbstractBitcoinApi, HealthCheckHost } from './bitcoin-api-abstract-factory';
|
||||||
import { IEsploraApi } from './esplora-api.interface';
|
import { IEsploraApi } from './esplora-api.interface';
|
||||||
import logger from '../../logger';
|
import logger from '../../logger';
|
||||||
import { Common } from '../common';
|
import { Common } from '../common';
|
||||||
@ -157,7 +157,7 @@ class FailoverRouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sort hosts by connection quality, and update default fallback
|
// sort hosts by connection quality, and update default fallback
|
||||||
private sortHosts(): FailoverHost[] {
|
public sortHosts(): FailoverHost[] {
|
||||||
// sort by connection quality
|
// sort by connection quality
|
||||||
return this.hosts.slice().sort((a, b) => {
|
return this.hosts.slice().sort((a, b) => {
|
||||||
if ((a.unreachable || a.outOfSync) === (b.unreachable || b.outOfSync)) {
|
if ((a.unreachable || a.outOfSync) === (b.unreachable || b.outOfSync)) {
|
||||||
@ -342,6 +342,19 @@ class ElectrsApi implements AbstractBitcoinApi {
|
|||||||
public startHealthChecks(): void {
|
public startHealthChecks(): void {
|
||||||
this.failoverRouter.startHealthChecks();
|
this.failoverRouter.startHealthChecks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getHealthStatus(): HealthCheckHost[] {
|
||||||
|
return this.failoverRouter.sortHosts().map(host => ({
|
||||||
|
host: host.host,
|
||||||
|
active: host === this.failoverRouter.activeHost,
|
||||||
|
rtt: host.rtt,
|
||||||
|
latestHeight: host.latestHeight || 0,
|
||||||
|
socket: !!host.socket,
|
||||||
|
outOfSync: !!host.outOfSync,
|
||||||
|
unreachable: !!host.unreachable,
|
||||||
|
checked: !!host.checked,
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ElectrsApi;
|
export default ElectrsApi;
|
||||||
|
@ -26,6 +26,7 @@ import mempool from './mempool';
|
|||||||
import statistics from './statistics/statistics';
|
import statistics from './statistics/statistics';
|
||||||
import accelerationCosts from './acceleration';
|
import accelerationCosts from './acceleration';
|
||||||
import accelerationRepository from '../repositories/AccelerationRepository';
|
import accelerationRepository from '../repositories/AccelerationRepository';
|
||||||
|
import bitcoinApi from './bitcoin/bitcoin-api-factory';
|
||||||
|
|
||||||
interface AddressTransactions {
|
interface AddressTransactions {
|
||||||
mempool: MempoolTransactionExtended[],
|
mempool: MempoolTransactionExtended[],
|
||||||
@ -39,6 +40,7 @@ const wantable = [
|
|||||||
'mempool-blocks',
|
'mempool-blocks',
|
||||||
'live-2h-chart',
|
'live-2h-chart',
|
||||||
'stats',
|
'stats',
|
||||||
|
'tomahawk',
|
||||||
];
|
];
|
||||||
|
|
||||||
class WebsocketHandler {
|
class WebsocketHandler {
|
||||||
@ -123,7 +125,7 @@ class WebsocketHandler {
|
|||||||
for (const sub of wantable) {
|
for (const sub of wantable) {
|
||||||
const key = `want-${sub}`;
|
const key = `want-${sub}`;
|
||||||
const wants = parsedMessage.data.includes(sub);
|
const wants = parsedMessage.data.includes(sub);
|
||||||
if (wants && client['wants'] && !client[key]) {
|
if (wants && !client[key]) {
|
||||||
wantNow[key] = true;
|
wantNow[key] = true;
|
||||||
}
|
}
|
||||||
client[key] = wants;
|
client[key] = wants;
|
||||||
@ -147,6 +149,10 @@ class WebsocketHandler {
|
|||||||
response['da'] = this.socketData['da'];
|
response['da'] = this.socketData['da'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wantNow['want-tomahawk'] && config.MEMPOOL.BACKEND === 'esplora' && config.ESPLORA.FALLBACK?.length) {
|
||||||
|
response['tomahawk'] = JSON.stringify(bitcoinApi.getHealthStatus());
|
||||||
|
}
|
||||||
|
|
||||||
if (parsedMessage && parsedMessage['track-tx']) {
|
if (parsedMessage && parsedMessage['track-tx']) {
|
||||||
if (/^[a-fA-F0-9]{64}$/.test(parsedMessage['track-tx'])) {
|
if (/^[a-fA-F0-9]{64}$/.test(parsedMessage['track-tx'])) {
|
||||||
client['track-tx'] = parsedMessage['track-tx'];
|
client['track-tx'] = parsedMessage['track-tx'];
|
||||||
@ -546,6 +552,10 @@ class WebsocketHandler {
|
|||||||
response['mempool-blocks'] = getCachedResponse('mempool-blocks', mBlocks);
|
response['mempool-blocks'] = getCachedResponse('mempool-blocks', mBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (client['want-tomahawk'] && config.MEMPOOL.BACKEND === 'esplora' && config.ESPLORA.FALLBACK?.length) {
|
||||||
|
response['tomahawk'] = getCachedResponse('tomahawk', bitcoinApi.getHealthStatus());
|
||||||
|
}
|
||||||
|
|
||||||
if (client['track-mempool-tx']) {
|
if (client['track-mempool-tx']) {
|
||||||
const tx = newTransactions.find((t) => t.txid === client['track-mempool-tx']);
|
const tx = newTransactions.find((t) => t.txid === client['track-mempool-tx']);
|
||||||
if (tx) {
|
if (tx) {
|
||||||
@ -909,6 +919,10 @@ class WebsocketHandler {
|
|||||||
response['mempool-blocks'] = getCachedResponse('mempool-blocks', mBlocks);
|
response['mempool-blocks'] = getCachedResponse('mempool-blocks', mBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (client['want-tomahawk'] && config.MEMPOOL.BACKEND === 'esplora' && config.ESPLORA.FALLBACK?.length) {
|
||||||
|
response['tomahawk'] = getCachedResponse('tomahawk', bitcoinApi.getHealthStatus());
|
||||||
|
}
|
||||||
|
|
||||||
if (client['track-tx']) {
|
if (client['track-tx']) {
|
||||||
const trackTxid = client['track-tx'];
|
const trackTxid = client['track-tx'];
|
||||||
if (trackTxid && confirmedTxids[trackTxid]) {
|
if (trackTxid && confirmedTxids[trackTxid]) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user