Add apiService cachedRequest function, apply to outspends requests
This commit is contained in:
		
							parent
							
								
									7142d69dda
								
							
						
					
					
						commit
						3f0c3c1952
					
				| @ -6,7 +6,7 @@ import { Outspend, Transaction, Vin, Vout } from '../../interfaces/electrs.inter | ||||
| import { ElectrsApiService } from '../../services/electrs-api.service'; | ||||
| import { environment } from '../../../environments/environment'; | ||||
| import { AssetsService } from '../../services/assets.service'; | ||||
| import { filter, map, tap, switchMap, shareReplay } from 'rxjs/operators'; | ||||
| import { filter, map, tap, switchMap, shareReplay, catchError } from 'rxjs/operators'; | ||||
| import { BlockExtended } from '../../interfaces/node-api.interface'; | ||||
| import { ApiService } from '../../services/api.service'; | ||||
| import { PriceService } from '../../services/price.service'; | ||||
| @ -53,6 +53,7 @@ export class TransactionsListComponent implements OnInit, OnChanges { | ||||
|     private assetsService: AssetsService, | ||||
|     private ref: ChangeDetectorRef, | ||||
|     private priceService: PriceService, | ||||
|     private cd: ChangeDetectorRef, | ||||
|   ) { } | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
| @ -75,7 +76,7 @@ export class TransactionsListComponent implements OnInit, OnChanges { | ||||
|               for (let i = 0; i < txIds.length; i += 50) { | ||||
|                 batches.push(txIds.slice(i, i + 50)); | ||||
|               } | ||||
|               return forkJoin(batches.map(batch => this.apiService.getOutspendsBatched$(batch))); | ||||
|               return forkJoin(batches.map(batch => { return this.apiService.cachedRequest(this.apiService.getOutspendsBatched$, 5000, batch); })); | ||||
|             } else { | ||||
|               return of([]); | ||||
|             } | ||||
| @ -90,6 +91,7 @@ export class TransactionsListComponent implements OnInit, OnChanges { | ||||
|             outspends.forEach((outspend, i) => { | ||||
|               transactions[i]._outspends = outspend; | ||||
|             }); | ||||
|             this.cd.markForCheck(); | ||||
|           }), | ||||
|         ), | ||||
|       this.stateService.utxoSpent$ | ||||
| @ -108,6 +110,10 @@ export class TransactionsListComponent implements OnInit, OnChanges { | ||||
|           .pipe( | ||||
|             filter(() => this.stateService.env.LIGHTNING), | ||||
|             switchMap((txIds) => this.apiService.getChannelByTxIds$(txIds)), | ||||
|             catchError((error) => { | ||||
|               // handle 404
 | ||||
|               return of([]); | ||||
|             }), | ||||
|             tap((channels) => { | ||||
|               if (!this.transactions) { | ||||
|                 return; | ||||
|  | ||||
| @ -123,7 +123,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { | ||||
|         .pipe( | ||||
|           switchMap((txid) => { | ||||
|             if (!this.cached) { | ||||
|               return this.apiService.getOutspendsBatched$([txid]); | ||||
|               return this.apiService.cachedRequest(this.apiService.getOutspendsBatched$, 5000, [txid]); | ||||
|             } else { | ||||
|               return of(null); | ||||
|             } | ||||
|  | ||||
| @ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; | ||||
| import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http'; | ||||
| import { CpfpInfo, OptimizedMempoolStats, AddressInformation, LiquidPegs, ITranslators, | ||||
|   PoolStat, BlockExtended, TransactionStripped, RewardStats, AuditScore, BlockSizesAndWeights, RbfTree, BlockAudit } from '../interfaces/node-api.interface'; | ||||
| import { Observable, of } from 'rxjs'; | ||||
| import { BehaviorSubject, Observable, catchError, filter, of, shareReplay, take, tap } from 'rxjs'; | ||||
| import { StateService } from './state.service'; | ||||
| import { IBackendInfo, WebsocketResponse } from '../interfaces/websocket.interface'; | ||||
| import { Outspend, Transaction } from '../interfaces/electrs.interface'; | ||||
| @ -20,6 +20,8 @@ export class ApiService { | ||||
|   private apiBaseUrl: string; // base URL is protocol, hostname, and port
 | ||||
|   private apiBasePath: string; // network path is /testnet, etc. or '' for mainnet
 | ||||
| 
 | ||||
|   private requestCache = new Map<string, { subject: BehaviorSubject<any>, expiry: number }>; | ||||
| 
 | ||||
|   constructor( | ||||
|     private httpClient: HttpClient, | ||||
|     private stateService: StateService, | ||||
| @ -44,6 +46,46 @@ export class ApiService { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private generateCacheKey(functionName: string, params: any[]): string { | ||||
|     return functionName + JSON.stringify(params); | ||||
|   } | ||||
| 
 | ||||
|   // delete expired cache entries
 | ||||
|   private cleanExpiredCache(): void { | ||||
|     this.requestCache.forEach((value, key) => { | ||||
|       if (value.expiry < Date.now()) { | ||||
|         this.requestCache.delete(key); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   cachedRequest<T, F extends (...args: any[]) => Observable<T>>( | ||||
|     apiFunction: F, | ||||
|     expireAfter: number, // in ms
 | ||||
|     ...params: Parameters<F> | ||||
|   ): Observable<T> { | ||||
|     this.cleanExpiredCache(); | ||||
| 
 | ||||
|     const cacheKey = this.generateCacheKey(apiFunction.name, params); | ||||
|     if (!this.requestCache.has(cacheKey)) { | ||||
|       const subject = new BehaviorSubject<T | null>(null); | ||||
|       this.requestCache.set(cacheKey, { subject, expiry: Date.now() + expireAfter }); | ||||
| 
 | ||||
|       apiFunction.bind(this)(...params).pipe( | ||||
|         tap(data => { | ||||
|           subject.next(data as T); | ||||
|         }), | ||||
|         catchError((error) => { | ||||
|           subject.error(error); | ||||
|           return of(null); | ||||
|         }), | ||||
|         shareReplay(1), | ||||
|       ).subscribe(); | ||||
|     } | ||||
| 
 | ||||
|     return this.requestCache.get(cacheKey).subject.asObservable().pipe(filter(val => val !== null), take(1)); | ||||
|   } | ||||
| 
 | ||||
|   list2HStatistics$(): Observable<OptimizedMempoolStats[]> { | ||||
|     return this.httpClient.get<OptimizedMempoolStats[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/statistics/2h'); | ||||
|   } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user