import { BehaviorSubject , Observable } from 'rxjs' ; import { Injectable } from '@angular/core' ; import { SignalRService } from '@shared/services/signalr-service' ; import { WalletInfo } from '@shared/models/wallet-info' ; import { GeneralInfo , } from '@shared/services/interfaces/api.i' ; import { BlockConnectedSignalREvent , SignalREvents , WalletInfoSignalREvent } from '@shared/services/interfaces/signalr-events.i' ; import { catchError } from 'rxjs/operators' ; import { HttpClient , HttpParams } from '@angular/common/http' ; import { RestApi } from '@shared/services/rest-api' ; import { GlobalService } from '@shared/services/global.service' ; import { ErrorService } from '@shared/services/error-service' ; @ Injectable ( { providedIn : 'root' } ) export class NodeService extends RestApi { private generalInfoSubject : BehaviorSubject < GeneralInfo > = new BehaviorSubject < GeneralInfo > ( { walletName : '' , walletFilePath : '' , network : '' , creationTime : '' , isDecrypted : false , lastBlockSyncedHeight : 0 , chainTip : 0 , isChainSynced : false , connectedNodes : 0 } ) ; private currentWallet : WalletInfo ; constructor ( globalService , http , errorService , signalRService ) { super ( globalService , http , errorService ) ; globalService . currentWallet . subscribe ( wallet => { if ( wallet ) { this . currentWallet = wallet ; this . updateGeneralInfoForCurrentWallet ( ) ; } } ) ; signalRService . registerOnMessageEventHandler < WalletInfoSignalREvent > ( SignalREvents . WalletGeneralInfo , ( message ) => { if ( this . currentWallet && message . walletName === this . currentWallet . walletName ) { this . applyPercentSynced ( message ) ; this . generalInfoSubject . next ( message ) ; } } ) ; signalRService . registerOnMessageEventHandler < BlockConnectedSignalREvent > ( SignalREvents . BlockConnected , ( message ) => { const generalInfo = this . generalInfoSubject . value ; if ( generalInfo . isChainSynced ) { if ( generalInfo . chainTip < message . height ) { this . patchAndUpdateGeneralInfo ( { chainTip : message . height , lastBlockSyncedHeight : message . height } ) ; } } } ) ; } public generalInfo ( ) { return this . generalInfoSubject . asObservable ( ) ; } public addNode ( nodeIP ) { const params = new HttpParams ( ) . set ( 'endpoint' , nodeIP ) . set ( 'command' , 'add' ) ; return this . get ( 'connectionmanager/addnode' , params ) . pipe ( catchError ( err => this . handleHttpError ( err ) ) ) ; } private updateGeneralInfoForCurrentWallet ( ) { if ( this . currentWallet ) { const params = new HttpParams ( ) . set ( 'Name' , this . currentWallet . walletName ) ; this . get < GeneralInfo > ( 'wallet/general-info' , params ) . pipe ( catchError ( err => this . handleHttpError ( err ) ) ) . toPromise ( ) . then ( generalInfo => { this . applyPercentSynced ( generalInfo ) ; this . generalInfoSubject . next ( generalInfo ) ; } ) ; } } private applyPercentSynced ( message ) { let percentSynced = Math . min ( ( message . lastBlockSyncedHeight / message . chainTip ) * 100 , 100 ) ; if ( percentSynced . toFixed ( 0 ) === '100' && message . lastBlockSyncedHeight !== message . chainTip ) { percentSynced = 99 ; } message . percentSynced = percentSynced ; } private patchAndUpdateGeneralInfo ( patch ) { const updatedGeneralInfo = { } as GeneralInfo ; Object . assign ( updatedGeneralInfo , this . generalInfoSubject . value ) ; Object . assign ( updatedGeneralInfo , patch ) ; this . generalInfoSubject . next ( updatedGeneralInfo ) ; } }