Merge branch 'master' into nymkappa/unify-blocks-apis
This commit is contained in:
commit
6c271ab6ee
@ -237,14 +237,21 @@ export class Common {
|
|||||||
].join('x');
|
].join('x');
|
||||||
}
|
}
|
||||||
|
|
||||||
static utcDateToMysql(date?: number): string {
|
static utcDateToMysql(date?: number | null): string | null {
|
||||||
|
if (date === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const d = new Date((date || 0) * 1000);
|
const d = new Date((date || 0) * 1000);
|
||||||
return d.toISOString().split('T')[0] + ' ' + d.toTimeString().split(' ')[0];
|
return d.toISOString().split('T')[0] + ' ' + d.toTimeString().split(' ')[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
static findSocketNetwork(addr: string): {network: string | null, url: string} {
|
static findSocketNetwork(addr: string): {network: string | null, url: string} {
|
||||||
let network: string | null = null;
|
let network: string | null = null;
|
||||||
let url = addr.split('://')[1];
|
let url: string = addr;
|
||||||
|
|
||||||
|
if (config.LIGHTNING.BACKEND === 'cln') {
|
||||||
|
url = addr.split('://')[1];
|
||||||
|
}
|
||||||
|
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return {
|
return {
|
||||||
@ -261,7 +268,7 @@ export class Common {
|
|||||||
}
|
}
|
||||||
} else if (addr.indexOf('i2p') !== -1) {
|
} else if (addr.indexOf('i2p') !== -1) {
|
||||||
network = 'i2p';
|
network = 'i2p';
|
||||||
} else if (addr.indexOf('ipv4') !== -1) {
|
} else if (addr.indexOf('ipv4') !== -1 || (config.LIGHTNING.BACKEND === 'lnd' && isIP(url.split(':')[0]) === 4)) {
|
||||||
const ipv = isIP(url.split(':')[0]);
|
const ipv = isIP(url.split(':')[0]);
|
||||||
if (ipv === 4) {
|
if (ipv === 4) {
|
||||||
network = 'ipv4';
|
network = 'ipv4';
|
||||||
@ -271,7 +278,7 @@ export class Common {
|
|||||||
url: addr,
|
url: addr,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else if (addr.indexOf('ipv6') !== -1) {
|
} else if (addr.indexOf('ipv6') !== -1 || (config.LIGHTNING.BACKEND === 'lnd' && url.indexOf(']:'))) {
|
||||||
url = url.split('[')[1].split(']')[0];
|
url = url.split('[')[1].split(']')[0];
|
||||||
const ipv = isIP(url);
|
const ipv = isIP(url);
|
||||||
if (ipv === 6) {
|
if (ipv === 6) {
|
||||||
|
@ -7,7 +7,7 @@ import cpfpRepository from '../repositories/CpfpRepository';
|
|||||||
import { RowDataPacket } from 'mysql2';
|
import { RowDataPacket } from 'mysql2';
|
||||||
|
|
||||||
class DatabaseMigration {
|
class DatabaseMigration {
|
||||||
private static currentVersion = 56;
|
private static currentVersion = 57;
|
||||||
private queryTimeout = 3600_000;
|
private queryTimeout = 3600_000;
|
||||||
private statisticsAddedIndexed = false;
|
private statisticsAddedIndexed = false;
|
||||||
private uniqueLogs: string[] = [];
|
private uniqueLogs: string[] = [];
|
||||||
@ -500,6 +500,11 @@ class DatabaseMigration {
|
|||||||
this.uniqueLog(logger.notice, '`pools` table has been truncated`');
|
this.uniqueLog(logger.notice, '`pools` table has been truncated`');
|
||||||
await this.updateToSchemaVersion(56);
|
await this.updateToSchemaVersion(56);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (databaseSchemaVersion < 57) {
|
||||||
|
await this.$executeQuery(`ALTER TABLE nodes MODIFY updated_at datetime NULL`);
|
||||||
|
await this.updateToSchemaVersion(57);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -559,6 +559,17 @@ class ChannelsApi {
|
|||||||
const policy1: Partial<ILightningApi.RoutingPolicy> = channel.node1_policy || {};
|
const policy1: Partial<ILightningApi.RoutingPolicy> = channel.node1_policy || {};
|
||||||
const policy2: Partial<ILightningApi.RoutingPolicy> = channel.node2_policy || {};
|
const policy2: Partial<ILightningApi.RoutingPolicy> = channel.node2_policy || {};
|
||||||
|
|
||||||
|
// https://github.com/mempool/mempool/issues/3006
|
||||||
|
if ((channel.last_update ?? 0) < 1514736061) { // January 1st 2018
|
||||||
|
channel.last_update = null;
|
||||||
|
}
|
||||||
|
if ((policy1.last_update ?? 0) < 1514736061) { // January 1st 2018
|
||||||
|
policy1.last_update = null;
|
||||||
|
}
|
||||||
|
if ((policy2.last_update ?? 0) < 1514736061) { // January 1st 2018
|
||||||
|
policy2.last_update = null;
|
||||||
|
}
|
||||||
|
|
||||||
const query = `INSERT INTO channels
|
const query = `INSERT INTO channels
|
||||||
(
|
(
|
||||||
id,
|
id,
|
||||||
|
@ -228,7 +228,7 @@ class NodesApi {
|
|||||||
nodes.capacity
|
nodes.capacity
|
||||||
FROM nodes
|
FROM nodes
|
||||||
ORDER BY capacity DESC
|
ORDER BY capacity DESC
|
||||||
LIMIT 100
|
LIMIT 6
|
||||||
`;
|
`;
|
||||||
|
|
||||||
[rows] = await DB.query(query);
|
[rows] = await DB.query(query);
|
||||||
@ -269,14 +269,26 @@ class NodesApi {
|
|||||||
let query: string;
|
let query: string;
|
||||||
if (full === false) {
|
if (full === false) {
|
||||||
query = `
|
query = `
|
||||||
SELECT nodes.public_key as publicKey, IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias,
|
SELECT
|
||||||
nodes.channels
|
nodes.public_key as publicKey,
|
||||||
|
IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias,
|
||||||
|
nodes.channels,
|
||||||
|
geo_names_city.names as city, geo_names_country.names as country,
|
||||||
|
geo_names_iso.names as iso_code, geo_names_subdivision.names as subdivision
|
||||||
FROM nodes
|
FROM nodes
|
||||||
|
LEFT JOIN geo_names geo_names_country ON geo_names_country.id = nodes.country_id AND geo_names_country.type = 'country'
|
||||||
|
LEFT JOIN geo_names geo_names_city ON geo_names_city.id = nodes.city_id AND geo_names_city.type = 'city'
|
||||||
|
LEFT JOIN geo_names geo_names_iso ON geo_names_iso.id = nodes.country_id AND geo_names_iso.type = 'country_iso_code'
|
||||||
|
LEFT JOIN geo_names geo_names_subdivision on geo_names_subdivision.id = nodes.subdivision_id AND geo_names_subdivision.type = 'division'
|
||||||
ORDER BY channels DESC
|
ORDER BY channels DESC
|
||||||
LIMIT 100;
|
LIMIT 6;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
[rows] = await DB.query(query);
|
[rows] = await DB.query(query);
|
||||||
|
for (let i = 0; i < rows.length; ++i) {
|
||||||
|
rows[i].country = JSON.parse(rows[i].country);
|
||||||
|
rows[i].city = JSON.parse(rows[i].city);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
query = `
|
query = `
|
||||||
SELECT nodes.public_key AS publicKey, IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias,
|
SELECT nodes.public_key AS publicKey, IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias,
|
||||||
@ -630,6 +642,11 @@ class NodesApi {
|
|||||||
*/
|
*/
|
||||||
public async $saveNode(node: ILightningApi.Node): Promise<void> {
|
public async $saveNode(node: ILightningApi.Node): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
// https://github.com/mempool/mempool/issues/3006
|
||||||
|
if ((node.last_update ?? 0) < 1514736061) { // January 1st 2018
|
||||||
|
node.last_update = null;
|
||||||
|
}
|
||||||
|
|
||||||
const sockets = (node.addresses?.map(a => a.addr).join(',')) ?? '';
|
const sockets = (node.addresses?.map(a => a.addr).join(',')) ?? '';
|
||||||
const query = `INSERT INTO nodes(
|
const query = `INSERT INTO nodes(
|
||||||
public_key,
|
public_key,
|
||||||
|
@ -21,7 +21,7 @@ export namespace ILightningApi {
|
|||||||
export interface Channel {
|
export interface Channel {
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
chan_point: string;
|
chan_point: string;
|
||||||
last_update: number;
|
last_update: number | null;
|
||||||
node1_pub: string;
|
node1_pub: string;
|
||||||
node2_pub: string;
|
node2_pub: string;
|
||||||
capacity: string;
|
capacity: string;
|
||||||
@ -36,11 +36,11 @@ export namespace ILightningApi {
|
|||||||
fee_rate_milli_msat: string;
|
fee_rate_milli_msat: string;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
max_htlc_msat: string;
|
max_htlc_msat: string;
|
||||||
last_update: number;
|
last_update: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Node {
|
export interface Node {
|
||||||
last_update: number;
|
last_update: number | null;
|
||||||
pub_key: string;
|
pub_key: string;
|
||||||
alias: string;
|
alias: string;
|
||||||
addresses: {
|
addresses: {
|
||||||
|
@ -72,7 +72,7 @@ class NetworkSyncService {
|
|||||||
const graphNodesPubkeys: string[] = [];
|
const graphNodesPubkeys: string[] = [];
|
||||||
for (const node of nodes) {
|
for (const node of nodes) {
|
||||||
const latestUpdated = await channelsApi.$getLatestChannelUpdateForNode(node.pub_key);
|
const latestUpdated = await channelsApi.$getLatestChannelUpdateForNode(node.pub_key);
|
||||||
node.last_update = Math.max(node.last_update, latestUpdated);
|
node.last_update = Math.max(node.last_update ?? 0, latestUpdated);
|
||||||
|
|
||||||
await nodesApi.$saveNode(node);
|
await nodesApi.$saveNode(node);
|
||||||
graphNodesPubkeys.push(node.pub_key);
|
graphNodesPubkeys.push(node.pub_key);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, OnInit, OnDestroy, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
import { Component, OnInit, OnDestroy, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
||||||
import { StateService } from '../../services/state.service';
|
import { StateService } from '../../services/state.service';
|
||||||
import { Observable, Subscription } from 'rxjs';
|
import { Observable, Subscription } from 'rxjs';
|
||||||
import { Price } from 'src/app/services/price.service';
|
import { Price } from '../../services/price.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-amount',
|
selector: 'app-amount',
|
||||||
|
@ -5,7 +5,7 @@ import BlockScene from './block-scene';
|
|||||||
import TxSprite from './tx-sprite';
|
import TxSprite from './tx-sprite';
|
||||||
import TxView from './tx-view';
|
import TxView from './tx-view';
|
||||||
import { Position } from './sprite-types';
|
import { Position } from './sprite-types';
|
||||||
import { Price } from 'src/app/services/price.service';
|
import { Price } from '../../services/price.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-block-overview-graph',
|
selector: 'app-block-overview-graph',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, ElementRef, ViewChild, Input, OnChanges, ChangeDetectionStrategy } from '@angular/core';
|
import { Component, ElementRef, ViewChild, Input, OnChanges, ChangeDetectionStrategy } from '@angular/core';
|
||||||
import { TransactionStripped } from '../../interfaces/websocket.interface';
|
import { TransactionStripped } from '../../interfaces/websocket.interface';
|
||||||
import { Position } from '../../components/block-overview-graph/sprite-types.js';
|
import { Position } from '../../components/block-overview-graph/sprite-types.js';
|
||||||
import { Price } from 'src/app/services/price.service';
|
import { Price } from '../../services/price.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-block-overview-tooltip',
|
selector: 'app-block-overview-tooltip',
|
||||||
|
@ -13,7 +13,7 @@ import { BlockAudit, BlockExtended, TransactionStripped } from '../../interfaces
|
|||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component';
|
import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component';
|
||||||
import { detectWebGL } from '../../shared/graphs.utils';
|
import { detectWebGL } from '../../shared/graphs.utils';
|
||||||
import { PriceService, Price } from 'src/app/services/price.service';
|
import { PriceService, Price } from '../../services/price.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-block',
|
selector: 'app-block',
|
||||||
|
@ -267,6 +267,7 @@ export class StartComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
resetScroll(): void {
|
resetScroll(): void {
|
||||||
this.scrollToBlock(this.chainTip);
|
this.scrollToBlock(this.chainTip);
|
||||||
|
this.blockchainContainer.nativeElement.scrollLeft = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPageIndexOf(height: number): number {
|
getPageIndexOf(height: number): number {
|
||||||
|
@ -22,7 +22,7 @@ import { SeoService } from '../../services/seo.service';
|
|||||||
import { BlockExtended, CpfpInfo } from '../../interfaces/node-api.interface';
|
import { BlockExtended, CpfpInfo } from '../../interfaces/node-api.interface';
|
||||||
import { LiquidUnblinding } from './liquid-ublinding';
|
import { LiquidUnblinding } from './liquid-ublinding';
|
||||||
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
|
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
|
||||||
import { Price, PriceService } from 'src/app/services/price.service';
|
import { Price, PriceService } from '../../services/price.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-transaction',
|
selector: 'app-transaction',
|
||||||
|
@ -9,7 +9,7 @@ import { AssetsService } from '../../services/assets.service';
|
|||||||
import { filter, map, tap, switchMap, shareReplay } from 'rxjs/operators';
|
import { filter, map, tap, switchMap, shareReplay } from 'rxjs/operators';
|
||||||
import { BlockExtended } from '../../interfaces/node-api.interface';
|
import { BlockExtended } from '../../interfaces/node-api.interface';
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { PriceService } from 'src/app/services/price.service';
|
import { PriceService } from '../../services/price.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-transactions-list',
|
selector: 'app-transactions-list',
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Component, ElementRef, ViewChild, Input, OnChanges, OnInit } from '@angular/core';
|
import { Component, ElementRef, ViewChild, Input, OnChanges, OnInit } from '@angular/core';
|
||||||
import { tap } from 'rxjs';
|
import { tap } from 'rxjs';
|
||||||
import { Price, PriceService } from 'src/app/services/price.service';
|
import { Price, PriceService } from '../../services/price.service';
|
||||||
|
|
||||||
interface Xput {
|
interface Xput {
|
||||||
type: 'input' | 'output' | 'fee';
|
type: 'input' | 'output' | 'fee';
|
||||||
|
@ -199,8 +199,8 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
|||||||
this.outputs = this.initLines('out', voutWithFee, totalValue, this.maxStrands);
|
this.outputs = this.initLines('out', voutWithFee, totalValue, this.maxStrands);
|
||||||
|
|
||||||
this.middle = {
|
this.middle = {
|
||||||
path: `M ${(this.width / 2) - this.midWidth} ${(this.height / 2) + 0.25} L ${(this.width / 2) + this.midWidth} ${(this.height / 2) + 0.25}`,
|
path: `M ${(this.width / 2) - this.midWidth} ${(this.height / 2) + 0.5} L ${(this.width / 2) + this.midWidth} ${(this.height / 2) + 0.5}`,
|
||||||
style: `stroke-width: ${this.combinedWeight + 0.5}; stroke: ${this.gradient[1]}`
|
style: `stroke-width: ${this.combinedWeight + 1}; stroke: ${this.gradient[1]}`
|
||||||
};
|
};
|
||||||
|
|
||||||
this.hasLine = this.inputs.reduce((line, put) => line || !put.zeroValue, false)
|
this.hasLine = this.inputs.reduce((line, put) => line || !put.zeroValue, false)
|
||||||
@ -257,7 +257,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
|||||||
const lineParams = weights.map((w, i) => {
|
const lineParams = weights.map((w, i) => {
|
||||||
return {
|
return {
|
||||||
weight: w,
|
weight: w,
|
||||||
thickness: xputs[i].value === 0 ? this.zeroValueThickness : Math.min(this.combinedWeight + 0.5, Math.max(this.minWeight - 1, w) + 1),
|
thickness: xputs[i].value === 0 ? this.zeroValueThickness : Math.max(this.minWeight - 1, w) + 1,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
innerY: 0,
|
innerY: 0,
|
||||||
outerY: 0,
|
outerY: 0,
|
||||||
@ -269,7 +269,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
// bounds of the middle segment
|
// bounds of the middle segment
|
||||||
const innerTop = (this.height / 2) - (this.combinedWeight / 2);
|
const innerTop = (this.height / 2) - (this.combinedWeight / 2);
|
||||||
const innerBottom = innerTop + this.combinedWeight + 0.5;
|
const innerBottom = innerTop + this.combinedWeight;
|
||||||
// tracks the visual bottom of the endpoints of the previous line
|
// tracks the visual bottom of the endpoints of the previous line
|
||||||
let lastOuter = 0;
|
let lastOuter = 0;
|
||||||
let lastInner = innerTop;
|
let lastInner = innerTop;
|
||||||
@ -294,7 +294,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
// set the vertical position of the (center of the) outer side of the line
|
// set the vertical position of the (center of the) outer side of the line
|
||||||
line.outerY = lastOuter + (line.thickness / 2);
|
line.outerY = lastOuter + (line.thickness / 2);
|
||||||
line.innerY = Math.min(innerBottom - (line.thickness / 2), Math.max(innerTop + (line.thickness / 2), lastInner + (line.weight / 2)));
|
line.innerY = Math.min(innerBottom + (line.thickness / 2), Math.max(innerTop + (line.thickness / 2), lastInner + (line.weight / 2)));
|
||||||
|
|
||||||
// special case to center single input/outputs
|
// special case to center single input/outputs
|
||||||
if (xputs.length === 1) {
|
if (xputs.length === 1) {
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Top nodes per capacity -->
|
<!-- Top nodes per capacity -->
|
||||||
<div class="col">
|
<div class="col" style="max-height: 410px">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/liquidity' | relativeUrl]">
|
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/liquidity' | relativeUrl]">
|
||||||
@ -69,7 +69,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Top nodes per channels -->
|
<!-- Top nodes per channels -->
|
||||||
<div class="col">
|
<div class="col" style="max-height: 410px">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/connectivity' | relativeUrl]">
|
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/connectivity' | relativeUrl]">
|
||||||
|
@ -1,71 +1,56 @@
|
|||||||
<div [class]="!widget ? 'container-xl full-height' : ''">
|
|
||||||
<h1 *ngIf="!widget" class="float-left">
|
|
||||||
<span i18n="lightning.top-100-liquidity">Top 100 nodes liquidity ranking</span>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div [class]="widget ? 'widget' : 'full'">
|
|
||||||
<table class="table table-borderless table-fixed">
|
<div class="container-xl" style="min-height: 335px" [ngClass]="{'widget': widget, 'full-height': !widget}">
|
||||||
|
<h1 *ngIf="!widget" class="float-left" i18n="lightning.liquidity-ranking">Liquidity Ranking</h1>
|
||||||
|
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
|
<div style="min-height: 295px">
|
||||||
|
<table class="table table-borderless">
|
||||||
<thead>
|
<thead>
|
||||||
<th class="rank"></th>
|
<th class="text-left" i18n="nodes.alias">Alias</th>
|
||||||
<th class="alias text-left" i18n="nodes.alias">Alias</th>
|
<th class="liquidity text-right" i18n="node.liquidity">Liquidity</th>
|
||||||
<th class="capacity text-right" i18n="node.liquidity">Liquidity</th>
|
<th class="d-table-cell fiat text-right" [class]="{'widget': widget}">{{ currency$ | async }}</th>
|
||||||
<th *ngIf="!widget" class="channels text-right" i18n="lightning.channels">Channels</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell channels text-right" i18n="lightning.channels">Channels</th>
|
||||||
<th *ngIf="!widget" class="timestamp-first text-left" i18n="transaction.first-seen|Transaction first seen">First seen</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell timestamp text-right" i18n="transaction.first-seen|Transaction first seen">First seen</th>
|
||||||
<th *ngIf="!widget" class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell timestamp text-right" i18n="lightning.last_update">Last update</th>
|
||||||
<th *ngIf="!widget" class="location text-right" i18n="lightning.location">Location</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell text-right" i18n="lightning.location">Location</th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody *ngIf="topNodesPerCapacity$ | async as nodes; else skeleton">
|
<tbody *ngIf="topNodesPerCapacity$ | async as nodes">
|
||||||
<tr *ngFor="let node of nodes; let i = index;">
|
<tr *ngFor="let node of nodes;">
|
||||||
<td class="rank text-left">
|
<td class="pool text-left">
|
||||||
{{ i + 1 }}
|
<div class="tooltip-custom d-block w-100">
|
||||||
|
<a class="link d-block w-100" [routerLink]="['/lightning/node' | relativeUrl, node.publicKey]">
|
||||||
|
<span class="pool-name w-100">{{ node.alias }}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="alias text-left">
|
<td class="text-right">
|
||||||
<a [routerLink]="['/lightning/node' | relativeUrl, node.publicKey]">{{ node.alias }}</a>
|
|
||||||
</td>
|
|
||||||
<td class="capacity text-right">
|
|
||||||
<app-amount [satoshis]="node.capacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
<app-amount [satoshis]="node.capacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!widget" class="channels text-right">
|
<td class="d-table-cell fiat text-right" [ngClass]="{'widget': widget}">
|
||||||
|
<app-fiat [value]="node.capacity"></app-fiat>
|
||||||
|
</td>
|
||||||
|
<td *ngIf="!widget" class="d-none d-md-table-cell text-right">
|
||||||
{{ node.channels | number }}
|
{{ node.channels | number }}
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!widget" class="timestamp-first text-left">
|
<td *ngIf="!widget" class="d-none d-md-table-cell text-right">
|
||||||
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.firstSeen" [hideTimeSince]="true"></app-timestamp>
|
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.firstSeen" [hideTimeSince]="true"></app-timestamp>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!widget" class="timestamp-update text-left">
|
<td *ngIf="!widget" class="d-none d-md-table-cell text-right">
|
||||||
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.updatedAt" [hideTimeSince]="true"></app-timestamp>
|
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.updatedAt" [hideTimeSince]="true"></app-timestamp>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!widget" class="location text-right text-truncate">
|
<td *ngIf="!widget" class="d-none d-md-table-cell text-right text-truncate">
|
||||||
<app-geolocation [data]="node.geolocation" [type]="'list-isp'"></app-geolocation>
|
<app-geolocation [data]="node.geolocation" [type]="'list-isp'"></app-geolocation>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
<ng-template #skeleton>
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let item of skeletonRows">
|
|
||||||
<td class="rank text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td class="alias text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td class="capacity text-right">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="channels text-right">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="timestamp-first text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="timestamp-update text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="location text-right text-truncate">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</ng-template>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<ng-template [ngIf]="!widget">
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
<br>
|
||||||
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
</div>
|
||||||
|
@ -1,91 +1,52 @@
|
|||||||
.container-xl {
|
.container-xl {
|
||||||
max-width: 1400px;
|
max-width: 1400px;
|
||||||
padding-bottom: 100px;
|
}
|
||||||
@media (min-width: 960px) {
|
.container-xl.widget {
|
||||||
padding-left: 50px;
|
padding-right: 0px;
|
||||||
padding-right: 50px;
|
padding-left: 0px;
|
||||||
}
|
padding-bottom: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table td, .table th {
|
tr, td, th {
|
||||||
padding: 0.5rem;
|
border: 0px;
|
||||||
|
padding-top: 0.65rem !important;
|
||||||
|
padding-bottom: 0.7rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .rank {
|
.clear-link {
|
||||||
width: 5%;
|
color: white;
|
||||||
}
|
|
||||||
.widget .rank {
|
|
||||||
@media (min-width: 960px) {
|
|
||||||
width: 13%;
|
|
||||||
}
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
padding-left: 0px;
|
|
||||||
padding-right: 0px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .alias {
|
.pool {
|
||||||
width: 20%;
|
width: 15%;
|
||||||
|
@media (max-width: 575px) {
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
max-width: 350px;
|
white-space: nowrap;
|
||||||
@media (max-width: 960px) {
|
max-width: 160px;
|
||||||
width: 40%;
|
|
||||||
max-width: 500px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.widget .alias {
|
.pool-name {
|
||||||
width: 60%;
|
display: inline-block;
|
||||||
overflow: hidden;
|
vertical-align: text-top;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
max-width: 350px;
|
overflow: hidden;
|
||||||
@media (max-width: 960px) {
|
|
||||||
max-width: 175px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .capacity {
|
.liquidity {
|
||||||
width: 10%;
|
width: 10%;
|
||||||
@media (max-width: 960px) {
|
@media (max-width: 575px) {
|
||||||
width: 30%;
|
width: 25%;
|
||||||
}
|
|
||||||
}
|
|
||||||
.widget .capacity {
|
|
||||||
width: 32%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
padding-left: 0px;
|
|
||||||
padding-right: 0px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .channels {
|
.fiat {
|
||||||
width: 15%;
|
width: 15%;
|
||||||
padding-right: 50px;
|
@media (min-width: 768px) and (max-width: 991px) {
|
||||||
@media (max-width: 960px) {
|
display: none !important;
|
||||||
display: none;
|
}
|
||||||
|
@media (max-width: 575px) {
|
||||||
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .timestamp-first {
|
|
||||||
width: 10%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.full .timestamp-update {
|
|
||||||
width: 10%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.full .location {
|
|
||||||
width: 15%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
width: 30%;
|
|
||||||
}
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +1,8 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||||
import { map, Observable } from 'rxjs';
|
import { map, Observable } from 'rxjs';
|
||||||
|
import { StateService } from 'src/app/services/state.service';
|
||||||
import { INodesRanking, ITopNodesPerCapacity } from '../../../interfaces/node-api.interface';
|
import { INodesRanking, ITopNodesPerCapacity } from '../../../interfaces/node-api.interface';
|
||||||
import { SeoService } from '../../../services/seo.service';
|
import { SeoService } from '../../../services/seo.service';
|
||||||
import { isMobile } from '../../../shared/common.utils';
|
|
||||||
import { GeolocationData } from '../../../shared/components/geolocation/geolocation.component';
|
import { GeolocationData } from '../../../shared/components/geolocation/geolocation.component';
|
||||||
import { LightningApiService } from '../../lightning-api.service';
|
import { LightningApiService } from '../../lightning-api.service';
|
||||||
|
|
||||||
@ -18,18 +18,22 @@ export class TopNodesPerCapacity implements OnInit {
|
|||||||
|
|
||||||
topNodesPerCapacity$: Observable<ITopNodesPerCapacity[]>;
|
topNodesPerCapacity$: Observable<ITopNodesPerCapacity[]>;
|
||||||
skeletonRows: number[] = [];
|
skeletonRows: number[] = [];
|
||||||
|
currency$: Observable<string>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: LightningApiService,
|
private apiService: LightningApiService,
|
||||||
private seoService: SeoService
|
private seoService: SeoService,
|
||||||
|
private stateService: StateService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.currency$ = this.stateService.fiatCurrency$;
|
||||||
|
|
||||||
if (!this.widget) {
|
if (!this.widget) {
|
||||||
this.seoService.setTitle($localize`:@@2d9883d230a47fbbb2ec969e32a186597ea27405:Liquidity Ranking`);
|
this.seoService.setTitle($localize`:@@2d9883d230a47fbbb2ec969e32a186597ea27405:Liquidity Ranking`);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 1; i <= (this.widget ? (isMobile() ? 8 : 7) : 100); ++i) {
|
for (let i = 1; i <= (this.widget ? 6 : 100); ++i) {
|
||||||
this.skeletonRows.push(i);
|
this.skeletonRows.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +54,7 @@ export class TopNodesPerCapacity implements OnInit {
|
|||||||
} else {
|
} else {
|
||||||
this.topNodesPerCapacity$ = this.nodes$.pipe(
|
this.topNodesPerCapacity$ = this.nodes$.pipe(
|
||||||
map((ranking) => {
|
map((ranking) => {
|
||||||
return ranking.topByCapacity.slice(0, isMobile() ? 8 : 7);
|
return ranking.topByCapacity.slice(0, 6);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,71 +1,56 @@
|
|||||||
<div [class]="!widget ? 'container-xl full-height' : ''">
|
|
||||||
<h1 *ngIf="!widget" class="float-left">
|
|
||||||
<span i18n="lightning.top-100-connectivity">Top 100 nodes connectivity ranking</span>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div [class]="widget ? 'widget' : 'full'">
|
|
||||||
|
<div class="container-xl" style="min-height: 335px" [ngClass]="{'widget': widget, 'full-height': !widget}">
|
||||||
|
<h1 *ngIf="!widget" class="float-left" i18n="lightning.liquidity-ranking">Liquidity Ranking</h1>
|
||||||
|
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
|
<div style="min-height: 295px">
|
||||||
<table class="table table-borderless">
|
<table class="table table-borderless">
|
||||||
<thead>
|
<thead>
|
||||||
<th class="rank"></th>
|
<th class="pool text-left" i18n="nodes.alias" [ngClass]="{'widget': widget}">Alias</th>
|
||||||
<th class="alias text-left" i18n="nodes.alias">Alias</th>
|
<th class="liquidity text-right" i18n="node.channels">Channels</th>
|
||||||
<th class="channels text-right" i18n="node.channels">Channels</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell channels text-right" i18n="lightning.channels">Capacity</th>
|
||||||
<th *ngIf="!widget" class="capacity text-right" i18n="lightning.liquidity">Liquidity</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell text-right" i18n="node.liquidity">{{ currency$ | async }}</th>
|
||||||
<th *ngIf="!widget" class="timestamp-first text-left" i18n="transaction.first-seen|Transaction first seen">First seen</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell timestamp text-right" i18n="transaction.first-seen|Transaction first seen">First seen</th>
|
||||||
<th *ngIf="!widget" class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell timestamp text-right" i18n="lightning.last_update">Last update</th>
|
||||||
<th *ngIf="!widget" class="location text-right" i18n="lightning.location">Location</th>
|
<th class="geolocation d-table-cell text-right" i18n="lightning.location">Location</th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody *ngIf="topNodesPerChannels$ | async as nodes; else skeleton">
|
<tbody *ngIf="topNodesPerChannels$ | async as nodes">
|
||||||
<tr *ngFor="let node of nodes; let i = index;">
|
<tr *ngFor="let node of nodes;">
|
||||||
<td class="rank text-left">
|
<td class="pool text-left">
|
||||||
{{ i + 1 }}
|
<div class="tooltip-custom d-block w-100">
|
||||||
|
<a class="link d-block w-100" [routerLink]="['/lightning/node' | relativeUrl, node.publicKey]">
|
||||||
|
<span class="pool-name w-100">{{ node.alias }}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="alias text-left">
|
<td class="text-right">
|
||||||
<a [routerLink]="['/lightning/node' | relativeUrl, node.publicKey]">{{ node.alias }}</a>
|
{{ node.channels ? (node.channels | number) : '~' }}
|
||||||
</td>
|
</td>
|
||||||
<td class="channels text-right">
|
<td *ngIf="!widget" class="d-none d-md-table-cell capacity text-right">
|
||||||
{{ node.channels | number }}
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="capacity text-right">
|
|
||||||
<app-amount [satoshis]="node.capacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
<app-amount [satoshis]="node.capacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!widget" class="timestamp-first text-left">
|
<td *ngIf="!widget" class="fiat d-none d-md-table-cell text-right">
|
||||||
|
<app-fiat [value]="node.capacity"></app-fiat>
|
||||||
|
</td>
|
||||||
|
<td *ngIf="!widget" class="d-none d-md-table-cell text-right">
|
||||||
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.firstSeen" [hideTimeSince]="true"></app-timestamp>
|
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.firstSeen" [hideTimeSince]="true"></app-timestamp>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!widget" class="timestamp-update text-left">
|
<td *ngIf="!widget" class="d-none d-md-table-cell text-right">
|
||||||
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.updatedAt" [hideTimeSince]="true"></app-timestamp>
|
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.updatedAt" [hideTimeSince]="true"></app-timestamp>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!widget" class="location text-right text-truncate">
|
<td class="geolocation d-table-cell text-right text-truncate">
|
||||||
<app-geolocation [data]="node.geolocation" [type]="'list-isp'"></app-geolocation>
|
<app-geolocation [data]="node.geolocation" [type]="'list-isp'"></app-geolocation>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
<ng-template #skeleton>
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let item of skeletonRows">
|
|
||||||
<td class="rank text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td class="alias text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td class="channels text-right">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="capacity text-right">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="timestamp-first text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="timestamp-update text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="location text-right text-truncate">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</ng-template>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<ng-template [ngIf]="!widget">
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
<br>
|
||||||
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
</div>
|
||||||
|
@ -1,91 +1,54 @@
|
|||||||
.container-xl {
|
.container-xl {
|
||||||
max-width: 1400px;
|
max-width: 1400px;
|
||||||
padding-bottom: 100px;
|
}
|
||||||
@media (min-width: 960px) {
|
.container-xl.widget {
|
||||||
padding-left: 50px;
|
padding-right: 0px;
|
||||||
padding-right: 50px;
|
padding-left: 0px;
|
||||||
}
|
padding-bottom: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table td, .table th {
|
tr, td, th {
|
||||||
padding: 0.5rem;
|
border: 0px;
|
||||||
|
padding-top: 0.65rem !important;
|
||||||
|
padding-bottom: 0.7rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .rank {
|
.clear-link {
|
||||||
width: 5%;
|
color: white;
|
||||||
}
|
|
||||||
.widget .rank {
|
|
||||||
@media (min-width: 960px) {
|
|
||||||
width: 13%;
|
|
||||||
}
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
padding-left: 0px;
|
|
||||||
padding-right: 0px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .alias {
|
.pool {
|
||||||
width: 20%;
|
width: 15%;
|
||||||
|
@media (max-width: 576px) {
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
max-width: 350px;
|
white-space: nowrap;
|
||||||
@media (max-width: 960px) {
|
max-width: 160px;
|
||||||
width: 40%;
|
|
||||||
max-width: 500px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.widget .alias {
|
.pool-name {
|
||||||
width: 60%;
|
display: inline-block;
|
||||||
overflow: hidden;
|
vertical-align: text-top;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
max-width: 350px;
|
overflow: hidden;
|
||||||
@media (max-width: 960px) {
|
}
|
||||||
max-width: 175px;
|
.pool.widget {
|
||||||
}
|
width: 45%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .capacity {
|
.liquidity {
|
||||||
width: 10%;
|
width: 10%;
|
||||||
@media (max-width: 960px) {
|
@media (max-width: 576px) {
|
||||||
width: 30%;
|
width: 25%;
|
||||||
}
|
|
||||||
}
|
|
||||||
.widget .capacity {
|
|
||||||
width: 32%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
padding-left: 0px;
|
|
||||||
padding-right: 0px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .channels {
|
.geolocation {
|
||||||
width: 15%;
|
@media (min-width: 768px) and (max-width: 991px) {
|
||||||
padding-right: 50px;
|
display: none !important;
|
||||||
@media (max-width: 960px) {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
}
|
@media (max-width: 575px) {
|
||||||
|
display: none !important;
|
||||||
.full .timestamp-first {
|
|
||||||
width: 10%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.full .timestamp-update {
|
|
||||||
width: 10%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.full .location {
|
|
||||||
width: 15%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
width: 30%;
|
|
||||||
}
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||||
import { map, Observable } from 'rxjs';
|
import { map, Observable } from 'rxjs';
|
||||||
|
import { StateService } from 'src/app/services/state.service';
|
||||||
import { INodesRanking, ITopNodesPerChannels } from '../../../interfaces/node-api.interface';
|
import { INodesRanking, ITopNodesPerChannels } from '../../../interfaces/node-api.interface';
|
||||||
import { isMobile } from '../../../shared/common.utils';
|
|
||||||
import { GeolocationData } from '../../../shared/components/geolocation/geolocation.component';
|
import { GeolocationData } from '../../../shared/components/geolocation/geolocation.component';
|
||||||
import { LightningApiService } from '../../lightning-api.service';
|
import { LightningApiService } from '../../lightning-api.service';
|
||||||
|
|
||||||
@ -17,13 +17,17 @@ export class TopNodesPerChannels implements OnInit {
|
|||||||
|
|
||||||
topNodesPerChannels$: Observable<ITopNodesPerChannels[]>;
|
topNodesPerChannels$: Observable<ITopNodesPerChannels[]>;
|
||||||
skeletonRows: number[] = [];
|
skeletonRows: number[] = [];
|
||||||
|
currency$: Observable<string>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: LightningApiService,
|
private apiService: LightningApiService,
|
||||||
|
private stateService: StateService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
for (let i = 1; i <= (this.widget ? (isMobile() ? 8 : 7) : 100); ++i) {
|
this.currency$ = this.stateService.fiatCurrency$;
|
||||||
|
|
||||||
|
for (let i = 1; i <= (this.widget ? 6 : 100); ++i) {
|
||||||
this.skeletonRows.push(i);
|
this.skeletonRows.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +48,15 @@ export class TopNodesPerChannels implements OnInit {
|
|||||||
} else {
|
} else {
|
||||||
this.topNodesPerChannels$ = this.nodes$.pipe(
|
this.topNodesPerChannels$ = this.nodes$.pipe(
|
||||||
map((ranking) => {
|
map((ranking) => {
|
||||||
return ranking.topByChannels.slice(0, isMobile() ? 8 : 7);
|
for (const i in ranking.topByChannels) {
|
||||||
|
ranking.topByChannels[i].geolocation = <GeolocationData>{
|
||||||
|
country: ranking.topByChannels[i].country?.en,
|
||||||
|
city: ranking.topByChannels[i].city?.en,
|
||||||
|
subdivision: ranking.topByChannels[i].subdivision?.en,
|
||||||
|
iso: ranking.topByChannels[i].iso_code,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return ranking.topByChannels.slice(0, 6);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ export class CacheService {
|
|||||||
|
|
||||||
txCache: { [txid: string]: Transaction } = {};
|
txCache: { [txid: string]: Transaction } = {};
|
||||||
|
|
||||||
|
network: string;
|
||||||
blockCache: { [height: number]: BlockExtended } = {};
|
blockCache: { [height: number]: BlockExtended } = {};
|
||||||
blockLoading: { [height: number]: boolean } = {};
|
blockLoading: { [height: number]: boolean } = {};
|
||||||
copiesInBlockQueue: { [height: number]: number } = {};
|
copiesInBlockQueue: { [height: number]: number } = {};
|
||||||
@ -33,6 +34,10 @@ export class CacheService {
|
|||||||
this.stateService.chainTip$.subscribe((height) => {
|
this.stateService.chainTip$.subscribe((height) => {
|
||||||
this.tip = height;
|
this.tip = height;
|
||||||
});
|
});
|
||||||
|
this.stateService.networkChanged$.subscribe((network) => {
|
||||||
|
this.network = network;
|
||||||
|
this.resetBlockCache();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setTxCache(transactions) {
|
setTxCache(transactions) {
|
||||||
@ -68,15 +73,17 @@ export class CacheService {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("failed to load blocks: ", e.message);
|
console.log("failed to load blocks: ", e.message);
|
||||||
}
|
}
|
||||||
for (let i = 0; i < chunkSize; i++) {
|
|
||||||
delete this.blockLoading[maxHeight - i];
|
|
||||||
}
|
|
||||||
if (result && result.length) {
|
if (result && result.length) {
|
||||||
result.forEach(block => {
|
result.forEach(block => {
|
||||||
this.addBlockToCache(block);
|
if (this.blockLoading[block.height]) {
|
||||||
this.loadedBlocks$.next(block);
|
this.addBlockToCache(block);
|
||||||
|
this.loadedBlocks$.next(block);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
for (let i = 0; i < chunkSize; i++) {
|
||||||
|
delete this.blockLoading[maxHeight - i];
|
||||||
|
}
|
||||||
this.clearBlocks();
|
this.clearBlocks();
|
||||||
} else {
|
} else {
|
||||||
this.bumpBlockPriority(height);
|
this.bumpBlockPriority(height);
|
||||||
@ -104,6 +111,14 @@ export class CacheService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove all blocks from the cache
|
||||||
|
resetBlockCache() {
|
||||||
|
this.blockCache = {};
|
||||||
|
this.blockLoading = {};
|
||||||
|
this.copiesInBlockQueue = {};
|
||||||
|
this.blockPriorities = [];
|
||||||
|
}
|
||||||
|
|
||||||
getCachedBlock(height) {
|
getCachedBlock(height) {
|
||||||
return this.blockCache[height];
|
return this.blockCache[height];
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user