mirror of
https://github.com/mempool/mempool.git
synced 2025-02-24 06:47:52 +01:00
Bisq markets dashboard: Market backend tracking. WIP.
This commit is contained in:
parent
2fca34faaa
commit
d99fd5d59a
17 changed files with 101 additions and 78 deletions
|
@ -96,6 +96,14 @@ class WebsocketHandler {
|
|||
client['track-donation'] = parsedMessage['track-donation'];
|
||||
}
|
||||
|
||||
if (parsedMessage['track-bisq-market']) {
|
||||
if (/^[a-z]{3}_[a-z]{3}$/.test(parsedMessage['track-bisq-market'])) {
|
||||
client['track-bisq-market'] = parsedMessage['track-bisq-market'];
|
||||
} else {
|
||||
client['track-bisq-market'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(response).length) {
|
||||
client.send(JSON.stringify(response));
|
||||
}
|
||||
|
|
|
@ -122,6 +122,7 @@ export interface WebsocketResponse {
|
|||
'track-tx': string;
|
||||
'track-address': string;
|
||||
'watch-mempool': boolean;
|
||||
'track-bisq-market': string;
|
||||
}
|
||||
|
||||
export interface VbytesPerSecond {
|
||||
|
|
|
@ -5,6 +5,7 @@ import { ParamMap, ActivatedRoute } from '@angular/router';
|
|||
import { Subscription, of } from 'rxjs';
|
||||
import { BisqTransaction } from '../bisq.interfaces';
|
||||
import { BisqApiService } from '../bisq-api.service';
|
||||
import { WebsocketService } from 'src/app/services/websocket.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bisq-address',
|
||||
|
@ -22,12 +23,15 @@ export class BisqAddressComponent implements OnInit, OnDestroy {
|
|||
totalSent = 0;
|
||||
|
||||
constructor(
|
||||
private websocketService: WebsocketService,
|
||||
private route: ActivatedRoute,
|
||||
private seoService: SeoService,
|
||||
private bisqApiService: BisqApiService,
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.websocketService.want(['blocks']);
|
||||
|
||||
this.mainSubscription = this.route.paramMap
|
||||
.pipe(
|
||||
switchMap((params: ParamMap) => {
|
||||
|
|
|
@ -8,6 +8,7 @@ import { switchMap, catchError } from 'rxjs/operators';
|
|||
import { SeoService } from 'src/app/services/seo.service';
|
||||
import { ElectrsApiService } from 'src/app/services/electrs-api.service';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { WebsocketService } from 'src/app/services/websocket.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bisq-block',
|
||||
|
@ -23,6 +24,7 @@ export class BisqBlockComponent implements OnInit, OnDestroy {
|
|||
error: HttpErrorResponse | null;
|
||||
|
||||
constructor(
|
||||
private websocketService: WebsocketService,
|
||||
private bisqApiService: BisqApiService,
|
||||
private route: ActivatedRoute,
|
||||
private seoService: SeoService,
|
||||
|
@ -32,6 +34,8 @@ export class BisqBlockComponent implements OnInit, OnDestroy {
|
|||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.websocketService.want(['blocks']);
|
||||
|
||||
this.subscription = this.route.paramMap
|
||||
.pipe(
|
||||
switchMap((params: ParamMap) => {
|
||||
|
|
|
@ -5,6 +5,7 @@ import { Observable } from 'rxjs';
|
|||
import { BisqBlock, BisqOutput, BisqTransaction } from '../bisq.interfaces';
|
||||
import { SeoService } from 'src/app/services/seo.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { WebsocketService } from 'src/app/services/websocket.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bisq-blocks',
|
||||
|
@ -25,6 +26,7 @@ export class BisqBlocksComponent implements OnInit {
|
|||
paginationMaxSize = 10;
|
||||
|
||||
constructor(
|
||||
private websocketService: WebsocketService,
|
||||
private bisqApiService: BisqApiService,
|
||||
private seoService: SeoService,
|
||||
private route: ActivatedRoute,
|
||||
|
@ -32,6 +34,7 @@ export class BisqBlocksComponent implements OnInit {
|
|||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.websocketService.want(['blocks']);
|
||||
this.seoService.setTitle($localize`:@@8a7b4bd44c0ac71b2e72de0398b303257f7d2f54:Blocks`);
|
||||
this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10);
|
||||
this.loadingItems = Array(this.itemsPerPage);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { Observable, combineLatest } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { WebsocketService } from 'src/app/services/websocket.service';
|
||||
import { BisqApiService } from '../bisq-api.service';
|
||||
|
||||
@Component({
|
||||
|
@ -13,10 +14,13 @@ export class BisqDashboardComponent implements OnInit {
|
|||
tickers$: Observable<any>;
|
||||
|
||||
constructor(
|
||||
private websocketService: WebsocketService,
|
||||
private bisqApiService: BisqApiService,
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.websocketService.want(['blocks']);
|
||||
|
||||
this.tickers$ = combineLatest([
|
||||
this.bisqApiService.getMarketsTicker$(),
|
||||
this.bisqApiService.getMarkets$(),
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
<router-outlet></router-outlet>
|
|
@ -1,18 +0,0 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { WebsocketService } from 'src/app/services/websocket.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bisq-explorer',
|
||||
templateUrl: './bisq-explorer.component.html',
|
||||
styleUrls: ['./bisq-explorer.component.scss']
|
||||
})
|
||||
export class BisqExplorerComponent implements OnInit {
|
||||
|
||||
constructor(
|
||||
private websocketService: WebsocketService,
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.websocketService.want(['blocks']);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { combineLatest, merge, Observable, of } from 'rxjs';
|
||||
import { filter, map, mergeAll, switchMap, tap } from 'rxjs/operators';
|
||||
import { WebsocketService } from 'src/app/services/websocket.service';
|
||||
import { BisqApiService } from '../bisq-api.service';
|
||||
|
||||
@Component({
|
||||
|
@ -11,7 +12,7 @@ import { BisqApiService } from '../bisq-api.service';
|
|||
styleUrls: ['./bisq-market.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class BisqMarketComponent implements OnInit {
|
||||
export class BisqMarketComponent implements OnInit, OnDestroy {
|
||||
hlocData$: Observable<any>;
|
||||
currency$: Observable<any>;
|
||||
offers$: Observable<any>;
|
||||
|
@ -19,6 +20,7 @@ export class BisqMarketComponent implements OnInit {
|
|||
defaultInterval = 'half_hour';
|
||||
|
||||
constructor(
|
||||
private websocketService: WebsocketService,
|
||||
private route: ActivatedRoute,
|
||||
private bisqApiService: BisqApiService,
|
||||
private formBuilder: FormBuilder,
|
||||
|
@ -44,6 +46,7 @@ export class BisqMarketComponent implements OnInit {
|
|||
this.offers$ = this.route.paramMap
|
||||
.pipe(
|
||||
map(routeParams => routeParams.get('pair')),
|
||||
tap((marketPair) => this.websocketService.startTrackBisqMarket(marketPair)),
|
||||
switchMap((marketPair) => this.bisqApiService.getMarketOffers$(marketPair)),
|
||||
map((offers) => {
|
||||
return offers[Object.keys(offers)[0]];
|
||||
|
@ -68,4 +71,8 @@ export class BisqMarketComponent implements OnInit {
|
|||
);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.websocketService.stopTrackingBisqMarket();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { BisqApiService } from '../bisq-api.service';
|
|||
import { BisqStats } from '../bisq.interfaces';
|
||||
import { SeoService } from 'src/app/services/seo.service';
|
||||
import { StateService } from 'src/app/services/state.service';
|
||||
import { WebsocketService } from 'src/app/services/websocket.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bisq-stats',
|
||||
|
@ -15,12 +16,15 @@ export class BisqStatsComponent implements OnInit {
|
|||
price: number;
|
||||
|
||||
constructor(
|
||||
private websocketService: WebsocketService,
|
||||
private bisqApiService: BisqApiService,
|
||||
private seoService: SeoService,
|
||||
private stateService: StateService,
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.websocketService.want(['blocks']);
|
||||
|
||||
this.seoService.setTitle($localize`:@@2a30a4cdb123a03facc5ab8c5b3e6d8b8dbbc3d4:BSQ statistics`);
|
||||
this.stateService.bsqPrice$
|
||||
.subscribe((bsqPrice) => {
|
||||
|
|
|
@ -9,6 +9,7 @@ import { BisqApiService } from '../bisq-api.service';
|
|||
import { SeoService } from 'src/app/services/seo.service';
|
||||
import { ElectrsApiService } from 'src/app/services/electrs-api.service';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { WebsocketService } from 'src/app/services/websocket.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bisq-transaction',
|
||||
|
@ -27,6 +28,7 @@ export class BisqTransactionComponent implements OnInit, OnDestroy {
|
|||
subscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private websocketService: WebsocketService,
|
||||
private route: ActivatedRoute,
|
||||
private bisqApiService: BisqApiService,
|
||||
private electrsApiService: ElectrsApiService,
|
||||
|
@ -36,6 +38,8 @@ export class BisqTransactionComponent implements OnInit, OnDestroy {
|
|||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.websocketService.want(['blocks']);
|
||||
|
||||
this.subscription = this.route.paramMap.pipe(
|
||||
switchMap((params: ParamMap) => {
|
||||
this.isLoading = true;
|
||||
|
|
|
@ -8,6 +8,7 @@ import { SeoService } from 'src/app/services/seo.service';
|
|||
import { FormGroup, FormBuilder } from '@angular/forms';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { IMultiSelectOption, IMultiSelectSettings, IMultiSelectTexts } from 'ngx-bootrap-multiselect';
|
||||
import { WebsocketService } from 'src/app/services/websocket.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bisq-transactions',
|
||||
|
@ -65,6 +66,7 @@ export class BisqTransactionsComponent implements OnInit {
|
|||
'PROOF_OF_BURN', 'PROPOSAL', 'REIMBURSEMENT_REQUEST', 'TRANSFER_BSQ', 'UNLOCK', 'VOTE_REVEAL', 'IRREGULAR'];
|
||||
|
||||
constructor(
|
||||
private websocketService: WebsocketService,
|
||||
private bisqApiService: BisqApiService,
|
||||
private seoService: SeoService,
|
||||
private formBuilder: FormBuilder,
|
||||
|
@ -74,6 +76,7 @@ export class BisqTransactionsComponent implements OnInit {
|
|||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.websocketService.want(['blocks']);
|
||||
this.seoService.setTitle($localize`:@@add4cd82e3e38a3110fe67b3c7df56e9602644ee:Transactions`);
|
||||
|
||||
this.radioGroupForm = this.formBuilder.group({
|
||||
|
|
|
@ -17,7 +17,6 @@ import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontaweso
|
|||
import { faLeaf, faQuestion, faExclamationTriangle, faRocket, faRetweet, faFileAlt, faMoneyBill,
|
||||
faEye, faEyeSlash, faLock, faLockOpen, faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
|
||||
import { BisqBlocksComponent } from './bisq-blocks/bisq-blocks.component';
|
||||
import { BisqExplorerComponent } from './bisq-explorer/bisq-explorer.component';
|
||||
import { BisqApiService } from './bisq-api.service';
|
||||
import { BisqAddressComponent } from './bisq-address/bisq-address.component';
|
||||
import { BisqStatsComponent } from './bisq-stats/bisq-stats.component';
|
||||
|
@ -33,7 +32,6 @@ import { BsqAmountComponent } from './bsq-amount/bsq-amount.component';
|
|||
BisqTransactionDetailsComponent,
|
||||
BisqTransfersComponent,
|
||||
BisqBlocksComponent,
|
||||
BisqExplorerComponent,
|
||||
BisqAddressComponent,
|
||||
BisqStatsComponent,
|
||||
BsqAmountComponent,
|
||||
|
|
|
@ -5,7 +5,6 @@ import { BisqTransactionsComponent } from './bisq-transactions/bisq-transactions
|
|||
import { BisqTransactionComponent } from './bisq-transaction/bisq-transaction.component';
|
||||
import { BisqBlockComponent } from './bisq-block/bisq-block.component';
|
||||
import { BisqBlocksComponent } from './bisq-blocks/bisq-blocks.component';
|
||||
import { BisqExplorerComponent } from './bisq-explorer/bisq-explorer.component';
|
||||
import { BisqAddressComponent } from './bisq-address/bisq-address.component';
|
||||
import { BisqStatsComponent } from './bisq-stats/bisq-stats.component';
|
||||
import { ApiDocsComponent } from '../components/api-docs/api-docs.component';
|
||||
|
@ -14,56 +13,50 @@ import { BisqMarketComponent } from './bisq-market/bisq-market.component';
|
|||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: BisqExplorerComponent,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: BisqDashboardComponent,
|
||||
},
|
||||
{
|
||||
path: 'transactions',
|
||||
component: BisqTransactionsComponent
|
||||
},
|
||||
{
|
||||
path: 'market/:pair',
|
||||
component: BisqMarketComponent,
|
||||
},
|
||||
{
|
||||
path: 'tx/:id',
|
||||
component: BisqTransactionComponent
|
||||
},
|
||||
{
|
||||
path: 'blocks',
|
||||
children: [],
|
||||
component: BisqBlocksComponent
|
||||
},
|
||||
{
|
||||
path: 'block/:id',
|
||||
component: BisqBlockComponent,
|
||||
},
|
||||
{
|
||||
path: 'address/:id',
|
||||
component: BisqAddressComponent,
|
||||
},
|
||||
{
|
||||
path: 'stats',
|
||||
component: BisqStatsComponent,
|
||||
},
|
||||
{
|
||||
path: 'about',
|
||||
component: AboutComponent,
|
||||
},
|
||||
{
|
||||
path: 'api',
|
||||
component: ApiDocsComponent,
|
||||
},
|
||||
{
|
||||
path: '**',
|
||||
redirectTo: ''
|
||||
}
|
||||
]
|
||||
}
|
||||
path: '',
|
||||
component: BisqDashboardComponent,
|
||||
},
|
||||
{
|
||||
path: 'transactions',
|
||||
component: BisqTransactionsComponent
|
||||
},
|
||||
{
|
||||
path: 'market/:pair',
|
||||
component: BisqMarketComponent,
|
||||
},
|
||||
{
|
||||
path: 'tx/:id',
|
||||
component: BisqTransactionComponent
|
||||
},
|
||||
{
|
||||
path: 'blocks',
|
||||
children: [],
|
||||
component: BisqBlocksComponent
|
||||
},
|
||||
{
|
||||
path: 'block/:id',
|
||||
component: BisqBlockComponent,
|
||||
},
|
||||
{
|
||||
path: 'address/:id',
|
||||
component: BisqAddressComponent,
|
||||
},
|
||||
{
|
||||
path: 'stats',
|
||||
component: BisqStatsComponent,
|
||||
},
|
||||
{
|
||||
path: 'about',
|
||||
component: AboutComponent,
|
||||
},
|
||||
{
|
||||
path: 'api',
|
||||
component: ApiDocsComponent,
|
||||
},
|
||||
{
|
||||
path: '**',
|
||||
redirectTo: ''
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
|
|
@ -20,6 +20,7 @@ export interface WebsocketResponse {
|
|||
'track-address'?: string;
|
||||
'track-asset'?: string;
|
||||
'watch-mempool'?: boolean;
|
||||
'track-bisq-market'?: string;
|
||||
}
|
||||
|
||||
export interface MempoolBlock {
|
||||
|
|
|
@ -23,7 +23,7 @@ export class WebsocketService {
|
|||
|
||||
private websocketSubject: WebSocketSubject<WebsocketResponse>;
|
||||
private goneOffline = false;
|
||||
private lastWant: string[] | null = null;
|
||||
private lastWant: string | null = null;
|
||||
private isTrackingTx = false;
|
||||
private latestGitCommit = '';
|
||||
private onlineCheckTimeout: number;
|
||||
|
@ -95,7 +95,7 @@ export class WebsocketService {
|
|||
if (this.goneOffline === true) {
|
||||
this.goneOffline = false;
|
||||
if (this.lastWant) {
|
||||
this.want(this.lastWant, true);
|
||||
this.want(JSON.parse(this.lastWant), true);
|
||||
}
|
||||
this.stateService.connectionState$.next(2);
|
||||
}
|
||||
|
@ -150,6 +150,14 @@ export class WebsocketService {
|
|||
this.websocketSubject.next({ 'track-asset': 'stop' });
|
||||
}
|
||||
|
||||
startTrackBisqMarket(market: string) {
|
||||
this.websocketSubject.next({ 'track-bisq-market': market });
|
||||
}
|
||||
|
||||
stopTrackingBisqMarket() {
|
||||
this.websocketSubject.next({ 'track-bisq-market': 'stop' });
|
||||
}
|
||||
|
||||
fetchStatistics(historicalDate: string) {
|
||||
this.websocketSubject.next({ historicalDate });
|
||||
}
|
||||
|
@ -158,11 +166,11 @@ export class WebsocketService {
|
|||
if (!this.stateService.isBrowser) {
|
||||
return;
|
||||
}
|
||||
if (data === this.lastWant && !force) {
|
||||
if (JSON.stringify(data) === this.lastWant && !force) {
|
||||
return;
|
||||
}
|
||||
this.websocketSubject.next({action: 'want', data: data});
|
||||
this.lastWant = data;
|
||||
this.lastWant = JSON.stringify(data);
|
||||
}
|
||||
|
||||
goOffline() {
|
||||
|
|
Loading…
Add table
Reference in a new issue