mirror of
https://github.com/mempool/mempool.git
synced 2026-08-13 12:33:11 +02:00
use paginated esplora registry api for liquid assets list
This commit is contained in:
parent
73b64cc5fb
commit
c5b9dc020e
5 changed files with 86 additions and 53 deletions
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<br>
|
||||
|
||||
<ngb-pagination class="pagination-container" [collectionSize]="assets.length" [rotate]="true" [pageSize]="itemsPerPage" [(page)]="page" (pageChange)="pageChange(page)" [maxSize]="paginationMaxSize" [boundaryLinks]="true" [ellipses]="ellipses"></ngb-pagination>
|
||||
<ngb-pagination class="pagination-container" [collectionSize]="totalAssets" [rotate]="true" [pageSize]="itemsPerPage" [(page)]="page" (pageChange)="pageChange(page)" [maxSize]="paginationMaxSize" [boundaryLinks]="true" [ellipses]="ellipses"></ngb-pagination>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
<br>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { AssetsService } from '@app/services/assets.service';
|
||||
import { environment } from '@environments/environment';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { filter, map, switchMap, take } from 'rxjs/operators';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { AssetExtended } from '@interfaces/electrs.interface';
|
||||
import { Observable } from 'rxjs';
|
||||
import { SeoService } from '@app/services/seo.service';
|
||||
import { StateService } from '@app/services/state.service';
|
||||
import { AssetRegistryItem } from '@interfaces/electrs.interface';
|
||||
|
||||
@Component({
|
||||
selector: 'app-assets',
|
||||
|
|
@ -17,16 +15,14 @@ import { StateService } from '@app/services/state.service';
|
|||
standalone: false,
|
||||
})
|
||||
export class AssetsComponent implements OnInit {
|
||||
nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId;
|
||||
paginationMaxSize = window.matchMedia('(max-width: 670px)').matches ? 4 : 6;
|
||||
ellipses = window.matchMedia('(max-width: 670px)').matches ? false : true;
|
||||
|
||||
assets: AssetExtended[];
|
||||
assetsCache: AssetExtended[];
|
||||
searchForm: UntypedFormGroup;
|
||||
assets$: Observable<AssetExtended[]>;
|
||||
assets$: Observable<AssetRegistryItem[]>;
|
||||
|
||||
page = 1;
|
||||
totalAssets = 0;
|
||||
error: any;
|
||||
|
||||
itemsPerPage: number;
|
||||
|
|
@ -38,46 +34,23 @@ export class AssetsComponent implements OnInit {
|
|||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private seoService: SeoService,
|
||||
private stateService: StateService,
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.seoService.setTitle($localize`:@@ee8f8008bae6ce3a49840c4e1d39b4af23d4c263:Assets`);
|
||||
this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10);
|
||||
|
||||
this.assets$ = combineLatest([
|
||||
this.assetsService.getAssetsJson$,
|
||||
this.route.queryParams,
|
||||
])
|
||||
this.assets$ = this.route.queryParams
|
||||
.pipe(
|
||||
take(1),
|
||||
switchMap(([assets, qp]) => {
|
||||
this.assets = assets.array;
|
||||
|
||||
return this.route.queryParams
|
||||
.pipe(
|
||||
filter((queryParams) => {
|
||||
const newPage = parseInt(queryParams.page, 10);
|
||||
if (newPage !== this.page) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
map((queryParams) => {
|
||||
if (queryParams.page) {
|
||||
const newPage = parseInt(queryParams.page, 10);
|
||||
this.page = newPage;
|
||||
} else {
|
||||
this.page = 1;
|
||||
}
|
||||
return '';
|
||||
})
|
||||
);
|
||||
}),
|
||||
map(() => {
|
||||
switchMap((queryParams) => {
|
||||
this.page = queryParams.page ? parseInt(queryParams.page, 10) : 1;
|
||||
const start = (this.page - 1) * this.itemsPerPage;
|
||||
return this.assets.slice(start, this.itemsPerPage + start);
|
||||
})
|
||||
return this.assetsService.getLiquidAssetsPage$(start, this.itemsPerPage);
|
||||
}),
|
||||
map((result) => {
|
||||
this.totalAssets = result.total;
|
||||
return result.assets;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -225,6 +225,14 @@ export interface Entity {
|
|||
domain: string;
|
||||
}
|
||||
|
||||
export interface AssetRegistryItem {
|
||||
asset_id: string;
|
||||
name: string;
|
||||
ticker?: string;
|
||||
domain?: string;
|
||||
entity?: Entity;
|
||||
}
|
||||
|
||||
interface IssuanceTxin {
|
||||
txid: string;
|
||||
vin: number;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
import { Observable, of, throwError } from 'rxjs';
|
||||
import { catchError, map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
import { StateService } from '@app/services/state.service';
|
||||
import { environment } from '@environments/environment';
|
||||
import { Asset, AssetExtended } from '@interfaces/electrs.interface';
|
||||
import { ElectrsApiService } from '@app/services/electrs-api.service';
|
||||
import { Asset, AssetExtended, AssetRegistryItem } from '@interfaces/electrs.interface';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
|
@ -15,19 +16,25 @@ export class AssetsService {
|
|||
getAssetsJson$: Observable<{ array: AssetExtended[]; objects: any}>;
|
||||
getAssetsMinimalJson$: Observable<any>;
|
||||
getWorldMapJson$: Observable<any>;
|
||||
registryAvailable = true;
|
||||
private apiBaseUrl = '';
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private stateService: StateService,
|
||||
private electrsApiService: ElectrsApiService,
|
||||
) {
|
||||
let apiBaseUrl = '';
|
||||
if (!this.stateService.isBrowser) {
|
||||
apiBaseUrl = this.stateService.env.NGINX_PROTOCOL + '://' + this.stateService.env.NGINX_HOSTNAME + ':' + this.stateService.env.NGINX_PORT;
|
||||
this.apiBaseUrl = ''; // use relative URL by default
|
||||
if (!stateService.isBrowser) { // except when inside AU SSR process
|
||||
this.apiBaseUrl = this.stateService.env.NGINX_PROTOCOL + '://' + this.stateService.env.NGINX_HOSTNAME + ':' + this.stateService.env.NGINX_PORT;
|
||||
}
|
||||
this.stateService.networkChanged$.subscribe(() => {
|
||||
this.registryAvailable = true;
|
||||
});
|
||||
|
||||
this.getAssetsJson$ = this.stateService.networkChanged$
|
||||
.pipe(
|
||||
switchMap(() => this.httpClient.get(`${apiBaseUrl}/resources/assets${this.stateService.network === 'liquidtestnet' ? '-testnet' : ''}.json`)),
|
||||
switchMap(() => this.httpClient.get(`${this.apiBaseUrl}/resources/assets${this.stateService.network === 'liquidtestnet' ? '-testnet' : ''}.json`)),
|
||||
map((rawAssets) => {
|
||||
const assets: AssetExtended[] = Object.values(rawAssets);
|
||||
|
||||
|
|
@ -56,7 +63,7 @@ export class AssetsService {
|
|||
);
|
||||
this.getAssetsMinimalJson$ = this.stateService.networkChanged$
|
||||
.pipe(
|
||||
switchMap(() => this.httpClient.get(`${apiBaseUrl}/resources/assets${this.stateService.network === 'liquidtestnet' ? '-testnet' : ''}.minimal.json`)),
|
||||
switchMap(() => this.httpClient.get(`${this.apiBaseUrl}/resources/assets${this.stateService.network === 'liquidtestnet' ? '-testnet' : ''}.minimal.json`)),
|
||||
map((assetsMinimal) => {
|
||||
if (this.stateService.network === 'liquidtestnet') {
|
||||
// Hard coding the Liquid Testnet native asset
|
||||
|
|
@ -67,7 +74,7 @@ export class AssetsService {
|
|||
shareReplay(1),
|
||||
);
|
||||
|
||||
this.getWorldMapJson$ = this.httpClient.get(apiBaseUrl + '/resources/worldmap.json').pipe(shareReplay());
|
||||
this.getWorldMapJson$ = this.httpClient.get(this.apiBaseUrl + '/resources/worldmap.json').pipe(shareReplay());
|
||||
}
|
||||
|
||||
public enrichLiquidAsset$(asset: Asset): Observable<Asset> {
|
||||
|
|
@ -83,4 +90,39 @@ export class AssetsService {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
public getLiquidAssetsPage$(startIndex: number, limit: number): Observable<{ assets: AssetRegistryItem[]; total: number }> {
|
||||
return (this.registryAvailable ? this.electrsApiService.getLiquidAssetsRegistry$(startIndex, limit).pipe(
|
||||
map((response) => {
|
||||
const assets = response.body || [];
|
||||
const total = parseInt(response.headers.get('X-Total-Results') || `${assets.length}`, 10);
|
||||
if (!total && !assets.length) {
|
||||
this.registryAvailable = false;
|
||||
return null;
|
||||
}
|
||||
return { assets, total };
|
||||
}),
|
||||
catchError((error) => {
|
||||
if (![404, 501].includes(error.status)) {
|
||||
return throwError(() => error);
|
||||
}
|
||||
this.registryAvailable = false;
|
||||
return of(null);
|
||||
}),
|
||||
) : of(null)).pipe(
|
||||
switchMap((registryPage) => registryPage ? of(registryPage) : this.getAssetsJson$.pipe(
|
||||
map((assets) => ({
|
||||
assets: assets.array.slice(startIndex, startIndex + limit),
|
||||
total: assets.array.length,
|
||||
})),
|
||||
)),
|
||||
map((page) => ({
|
||||
...page,
|
||||
assets: page.assets.map((asset) => ({
|
||||
...asset,
|
||||
entity: asset.entity || (asset.domain ? { domain: asset.domain } : undefined),
|
||||
})),
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http';
|
||||
import { BehaviorSubject, Observable, catchError, filter, from, of, shareReplay, switchMap, take, tap } from 'rxjs';
|
||||
import { Transaction, Address, Outspend, Recent, Asset, ScriptHash, AddressTxSummary, Utxo } from '@interfaces/electrs.interface';
|
||||
import { Transaction, Address, Outspend, Recent, Asset, ScriptHash, AddressTxSummary, Utxo, AssetRegistryItem } from '@interfaces/electrs.interface';
|
||||
import { StateService } from '@app/services/state.service';
|
||||
import { BlockExtended } from '@interfaces/node-api.interface';
|
||||
import { calcScriptHash$ } from '@app/bitcoin.utils';
|
||||
|
|
@ -228,6 +228,16 @@ export class ElectrsApiService {
|
|||
return this.httpClient.get<Asset>(this.apiBaseUrl + this.apiBasePath + '/api/asset/' + assetId);
|
||||
}
|
||||
|
||||
getLiquidAssetsRegistry$(startIndex: number, limit: number): Observable<HttpResponse<AssetRegistryItem[]>> {
|
||||
const params = new HttpParams()
|
||||
.set('start_index', startIndex)
|
||||
.set('limit', limit)
|
||||
.set('sort_field', 'name')
|
||||
.set('sort_dir', 'asc');
|
||||
|
||||
return this.httpClient.get<AssetRegistryItem[]>(this.apiBaseUrl + this.apiBasePath + '/api/assets/registry', { params, observe: 'response' });
|
||||
}
|
||||
|
||||
getAssetTransactions$(assetId: string): Observable<Transaction[]> {
|
||||
return this.httpClient.get<Transaction[]>(this.apiBaseUrl + this.apiBasePath + '/api/asset/' + assetId + '/txs');
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue