Loading indicator service indicating mempool sync status.
This commit is contained in:
		
							parent
							
								
									f46728080d
								
							
						
					
					
						commit
						632c243b34
					
				
							
								
								
									
										32
									
								
								backend/src/api/loading-indicators.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								backend/src/api/loading-indicators.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
import { ILoadingIndicators } from '../mempool.interfaces';
 | 
			
		||||
 | 
			
		||||
class LoadingIndicators {
 | 
			
		||||
  private loadingIndicators: ILoadingIndicators = {
 | 
			
		||||
    'mempool': 0,
 | 
			
		||||
  };
 | 
			
		||||
  private progressChangedCallback: ((loadingIndicators: ILoadingIndicators) => void) | undefined;
 | 
			
		||||
 | 
			
		||||
  constructor() { }
 | 
			
		||||
 | 
			
		||||
  public setProgressChangedCallback(fn: (loadingIndicators: ILoadingIndicators) => void) {
 | 
			
		||||
    this.progressChangedCallback = fn;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public setProgress(name: string, progressPercent: number) {
 | 
			
		||||
    const newProgress = Math.round(progressPercent);
 | 
			
		||||
    if (newProgress >= 100) {
 | 
			
		||||
      delete this.loadingIndicators[name];
 | 
			
		||||
    } else {
 | 
			
		||||
      this.loadingIndicators[name] = newProgress;
 | 
			
		||||
    }
 | 
			
		||||
    if (this.progressChangedCallback) {
 | 
			
		||||
      this.progressChangedCallback(this.loadingIndicators);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getLoadingIndicators() {
 | 
			
		||||
    return this.loadingIndicators;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default new LoadingIndicators();
 | 
			
		||||
@ -6,6 +6,7 @@ import { Common } from './common';
 | 
			
		||||
import transactionUtils from './transaction-utils';
 | 
			
		||||
import { IBitcoinApi } from './bitcoin/bitcoin-api.interface';
 | 
			
		||||
import bitcoinBaseApi from './bitcoin/bitcoin-base.api';
 | 
			
		||||
import loadingIndicators from './loading-indicators';
 | 
			
		||||
 | 
			
		||||
class Mempool {
 | 
			
		||||
  private inSync: boolean = false;
 | 
			
		||||
@ -90,6 +91,10 @@ class Mempool {
 | 
			
		||||
    const diff = transactions.length - currentMempoolSize;
 | 
			
		||||
    const newTransactions: TransactionExtended[] = [];
 | 
			
		||||
 | 
			
		||||
    if (!this.inSync) {
 | 
			
		||||
      loadingIndicators.setProgress('mempool', Object.keys(this.mempoolCache).length / transactions.length * 100);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (const txid of transactions) {
 | 
			
		||||
      if (!this.mempoolCache[txid]) {
 | 
			
		||||
        const transaction = await transactionUtils.$getTransactionExtended(txid, true);
 | 
			
		||||
@ -162,6 +167,7 @@ class Mempool {
 | 
			
		||||
    if (!this.inSync && transactions.length === Object.keys(newMempool).length) {
 | 
			
		||||
      this.inSync = true;
 | 
			
		||||
      logger.info('The mempool is now in sync!');
 | 
			
		||||
      loadingIndicators.setProgress('mempool', 100);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this.mempoolChangedCallback && (hasChange || deletedTransactions.length)) {
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,13 @@
 | 
			
		||||
import logger from '../logger';
 | 
			
		||||
import * as WebSocket from 'ws';
 | 
			
		||||
import { BlockExtended, TransactionExtended, WebsocketResponse, MempoolBlock, OptimizedStatistic } from '../mempool.interfaces';
 | 
			
		||||
import { BlockExtended, TransactionExtended, WebsocketResponse, MempoolBlock, OptimizedStatistic, ILoadingIndicators } from '../mempool.interfaces';
 | 
			
		||||
import blocks from './blocks';
 | 
			
		||||
import memPool from './mempool';
 | 
			
		||||
import backendInfo from './backend-info';
 | 
			
		||||
import mempoolBlocks from './mempool-blocks';
 | 
			
		||||
import fiatConversion from './fiat-conversion';
 | 
			
		||||
import { Common } from './common';
 | 
			
		||||
import loadingIndicators from './loading-indicators';
 | 
			
		||||
 | 
			
		||||
class WebsocketHandler {
 | 
			
		||||
  private wss: WebSocket.Server | undefined;
 | 
			
		||||
@ -117,6 +118,19 @@ class WebsocketHandler {
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleLoadingChanged(indicators: ILoadingIndicators) {
 | 
			
		||||
    if (!this.wss) {
 | 
			
		||||
      throw new Error('WebSocket.Server is not set');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.wss.clients.forEach((client: WebSocket) => {
 | 
			
		||||
      if (client.readyState !== WebSocket.OPEN) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      client.send(JSON.stringify({ loadingIndicators: indicators }));
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getInitData(_blocks?: BlockExtended[]) {
 | 
			
		||||
    if (!_blocks) {
 | 
			
		||||
      _blocks = blocks.getBlocks().slice(-8);
 | 
			
		||||
@ -131,6 +145,7 @@ class WebsocketHandler {
 | 
			
		||||
      'transactions': memPool.getLatestTransactions(),
 | 
			
		||||
      'git-commit': backendInfo.gitCommitHash,
 | 
			
		||||
      'hostname': backendInfo.hostname,
 | 
			
		||||
      'loadingIndicators': loadingIndicators.getLoadingIndicators(),
 | 
			
		||||
      ...this.extraInitProperties
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@ import bisqMarkets from './api/bisq/markets';
 | 
			
		||||
import donations from './api/donations';
 | 
			
		||||
import logger from './logger';
 | 
			
		||||
import backendInfo from './api/backend-info';
 | 
			
		||||
import loadingIndicators from './api/loading-indicators';
 | 
			
		||||
 | 
			
		||||
class Server {
 | 
			
		||||
  private wss: WebSocket.Server | undefined;
 | 
			
		||||
@ -135,6 +136,7 @@ class Server {
 | 
			
		||||
    blocks.setNewBlockCallback(websocketHandler.handleNewBlock.bind(websocketHandler));
 | 
			
		||||
    memPool.setMempoolChangedCallback(websocketHandler.handleMempoolChange.bind(websocketHandler));
 | 
			
		||||
    donations.setNotfyDonationStatusCallback(websocketHandler.handleNewDonation.bind(websocketHandler));
 | 
			
		||||
    loadingIndicators.setProgressChangedCallback(websocketHandler.handleLoadingChanged.bind(websocketHandler));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setUpHttpApiRoutes() {
 | 
			
		||||
 | 
			
		||||
@ -136,3 +136,4 @@ interface RequiredParams {
 | 
			
		||||
  types: ('@string' | '@number' | '@boolean' | string)[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ILoadingIndicators { [name: string]: number; }
 | 
			
		||||
 | 
			
		||||
@ -179,8 +179,8 @@
 | 
			
		||||
<ng-template #txPerSecond let-mempoolInfoData>
 | 
			
		||||
  <h5 class="card-title" i18n="dashboard.incoming-transactions">Incoming transactions</h5>
 | 
			
		||||
  <ng-template [ngIf]="mempoolInfoData.value" [ngIfElse]="loading">
 | 
			
		||||
    <span *ngIf="mempoolInfoData.value.vBytesPerSecond === 0; else inSync">
 | 
			
		||||
       <span class="badge badge-pill badge-warning" i18n="dashboard.backend-is-synchronizing">Backend is synchronizing</span>
 | 
			
		||||
    <span *ngIf="(mempoolLoadingStatus$ | async) !== 100; else inSync">
 | 
			
		||||
       <span class="badge badge-pill badge-warning"><ng-container i18n="dashboard.backend-is-synchronizing">Backend is synchronizing</ng-container> ({{ mempoolLoadingStatus$ | async }}%)</span>
 | 
			
		||||
    </span>
 | 
			
		||||
    <ng-template #inSync>
 | 
			
		||||
      <div class="progress sub-text" style="max-width: 250px;">
 | 
			
		||||
 | 
			
		||||
@ -50,6 +50,7 @@ export class DashboardComponent implements OnInit {
 | 
			
		||||
  mempoolBlocksData$: Observable<MempoolBlocksData>;
 | 
			
		||||
  mempoolInfoData$: Observable<MempoolInfoData>;
 | 
			
		||||
  difficultyEpoch$: Observable<EpochProgress>;
 | 
			
		||||
  mempoolLoadingStatus$: Observable<number>;
 | 
			
		||||
  vBytesPerSecondLimit = 1667;
 | 
			
		||||
  blocks$: Observable<Block[]>;
 | 
			
		||||
  transactions$: Observable<TransactionStripped[]>;
 | 
			
		||||
@ -77,6 +78,9 @@ export class DashboardComponent implements OnInit {
 | 
			
		||||
    this.websocketService.want(['blocks', 'stats', 'mempool-blocks', 'live-2h-chart']);
 | 
			
		||||
    this.network$ = merge(of(''), this.stateService.networkChanged$);
 | 
			
		||||
    this.collapseLevel = this.storageService.getValue('dashboard-collapsed') || 'one';
 | 
			
		||||
    this.mempoolLoadingStatus$ = this.stateService.loadingIndicators$.pipe(
 | 
			
		||||
      map((indicators) => indicators.mempool !== undefined ? indicators.mempool : 100)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    this.languageForm = this.formBuilder.group({
 | 
			
		||||
      language: ['']
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,4 @@
 | 
			
		||||
import { ILoadingIndicators } from '../services/state.service';
 | 
			
		||||
import { Block, Transaction } from './electrs.interface';
 | 
			
		||||
 | 
			
		||||
export interface WebsocketResponse {
 | 
			
		||||
@ -15,6 +16,7 @@ export interface WebsocketResponse {
 | 
			
		||||
  rbfTransaction?: Transaction;
 | 
			
		||||
  transactions?: TransactionStripped[];
 | 
			
		||||
  donationConfirmed?: boolean;
 | 
			
		||||
  loadingIndicators?: ILoadingIndicators;
 | 
			
		||||
  'track-tx'?: string;
 | 
			
		||||
  'track-address'?: string;
 | 
			
		||||
  'track-asset'?: string;
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,8 @@ interface MarkBlockState {
 | 
			
		||||
  txFeePerVSize?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ILoadingIndicators { [name: string]: number; }
 | 
			
		||||
 | 
			
		||||
export interface Env {
 | 
			
		||||
  TESTNET_ENABLED: boolean;
 | 
			
		||||
  LIQUID_ENABLED: boolean;
 | 
			
		||||
@ -63,6 +65,7 @@ export class StateService {
 | 
			
		||||
  lastDifficultyAdjustment$ = new ReplaySubject<number>(1);
 | 
			
		||||
  gitCommit$ = new ReplaySubject<string>(1);
 | 
			
		||||
  donationConfirmed$ = new Subject();
 | 
			
		||||
  loadingIndicators$ = new ReplaySubject<ILoadingIndicators>(1);
 | 
			
		||||
 | 
			
		||||
  live2Chart$ = new Subject<OptimizedMempoolStats>();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -270,6 +270,10 @@ export class WebsocketService {
 | 
			
		||||
      this.stateService.live2Chart$.next(response['live-2h-chart']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (response.loadingIndicators) {
 | 
			
		||||
      this.stateService.loadingIndicators$.next(response.loadingIndicators);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (response.mempoolInfo) {
 | 
			
		||||
      this.stateService.mempoolInfo$.next(response.mempoolInfo);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user