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[]>;
 | 
			
		||||
 | 
			
		||||
  startHealthChecks(): void;
 | 
			
		||||
  getHealthStatus(): HealthCheckHost[];
 | 
			
		||||
}
 | 
			
		||||
export interface BitcoinRpcCredentials {
 | 
			
		||||
  host: string;
 | 
			
		||||
@ -38,3 +39,14 @@ export interface BitcoinRpcCredentials {
 | 
			
		||||
  timeout: number;
 | 
			
		||||
  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 { AbstractBitcoinApi } from './bitcoin-api-abstract-factory';
 | 
			
		||||
import { AbstractBitcoinApi, HealthCheckHost } from './bitcoin-api-abstract-factory';
 | 
			
		||||
import { IBitcoinApi } from './bitcoin-api.interface';
 | 
			
		||||
import { IEsploraApi } from './esplora-api.interface';
 | 
			
		||||
import blocks from '../blocks';
 | 
			
		||||
@ -382,6 +382,10 @@ class BitcoinApi implements AbstractBitcoinApi {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public startHealthChecks(): void {};
 | 
			
		||||
 | 
			
		||||
  public getHealthStatus() {
 | 
			
		||||
    return [];
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default BitcoinApi;
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import config from '../../config';
 | 
			
		||||
import axios, { AxiosResponse } from 'axios';
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
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 logger from '../../logger';
 | 
			
		||||
import { Common } from '../common';
 | 
			
		||||
@ -157,7 +157,7 @@ class FailoverRouter {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // sort hosts by connection quality, and update default fallback
 | 
			
		||||
  private sortHosts(): FailoverHost[] {
 | 
			
		||||
  public sortHosts(): FailoverHost[] {
 | 
			
		||||
    // sort by connection quality
 | 
			
		||||
    return this.hosts.slice().sort((a, b) => {
 | 
			
		||||
      if ((a.unreachable || a.outOfSync) === (b.unreachable || b.outOfSync)) {
 | 
			
		||||
@ -342,6 +342,19 @@ class ElectrsApi implements AbstractBitcoinApi {
 | 
			
		||||
  public startHealthChecks(): void {
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,7 @@ import mempool from './mempool';
 | 
			
		||||
import statistics from './statistics/statistics';
 | 
			
		||||
import accelerationCosts from './acceleration';
 | 
			
		||||
import accelerationRepository from '../repositories/AccelerationRepository';
 | 
			
		||||
import bitcoinApi from './bitcoin/bitcoin-api-factory';
 | 
			
		||||
 | 
			
		||||
interface AddressTransactions {
 | 
			
		||||
  mempool: MempoolTransactionExtended[],
 | 
			
		||||
@ -39,6 +40,7 @@ const wantable = [
 | 
			
		||||
  'mempool-blocks',
 | 
			
		||||
  'live-2h-chart',
 | 
			
		||||
  'stats',
 | 
			
		||||
  'tomahawk',
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
class WebsocketHandler {
 | 
			
		||||
@ -123,7 +125,7 @@ class WebsocketHandler {
 | 
			
		||||
            for (const sub of wantable) {
 | 
			
		||||
              const key = `want-${sub}`;
 | 
			
		||||
              const wants = parsedMessage.data.includes(sub);
 | 
			
		||||
              if (wants && client['wants'] && !client[key]) {
 | 
			
		||||
              if (wants && !client[key]) {
 | 
			
		||||
                wantNow[key] = true;
 | 
			
		||||
              }
 | 
			
		||||
              client[key] = wants;
 | 
			
		||||
@ -147,6 +149,10 @@ class WebsocketHandler {
 | 
			
		||||
            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 (/^[a-fA-F0-9]{64}$/.test(parsedMessage['track-tx'])) {
 | 
			
		||||
              client['track-tx'] = parsedMessage['track-tx'];
 | 
			
		||||
@ -546,6 +552,10 @@ class WebsocketHandler {
 | 
			
		||||
        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']) {
 | 
			
		||||
        const tx = newTransactions.find((t) => t.txid === client['track-mempool-tx']);
 | 
			
		||||
        if (tx) {
 | 
			
		||||
@ -909,6 +919,10 @@ class WebsocketHandler {
 | 
			
		||||
        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']) {
 | 
			
		||||
        const trackTxid = client['track-tx'];
 | 
			
		||||
        if (trackTxid && confirmedTxids[trackTxid]) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user