Merge branch 'master' into taproot-fee-tooltip
This commit is contained in:
commit
75cd5a15b7
@ -66,7 +66,8 @@
|
|||||||
"MAXMIND": {
|
"MAXMIND": {
|
||||||
"ENABLED": false,
|
"ENABLED": false,
|
||||||
"GEOLITE2_CITY": "/usr/local/share/GeoIP/GeoLite2-City.mmdb",
|
"GEOLITE2_CITY": "/usr/local/share/GeoIP/GeoLite2-City.mmdb",
|
||||||
"GEOLITE2_ASN": "/usr/local/share/GeoIP/GeoLite2-ASN.mmdb"
|
"GEOLITE2_ASN": "/usr/local/share/GeoIP/GeoLite2-ASN.mmdb",
|
||||||
|
"GEOIP2_ISP": "/usr/local/share/GeoIP/GeoIP2-ISP.mmdb"
|
||||||
},
|
},
|
||||||
"BISQ": {
|
"BISQ": {
|
||||||
"ENABLED": false,
|
"ENABLED": false,
|
||||||
|
@ -96,11 +96,11 @@ class NodesApi {
|
|||||||
|
|
||||||
public async $getNodesISP() {
|
public async $getNodesISP() {
|
||||||
try {
|
try {
|
||||||
let query = `SELECT nodes.as_number as ispId, geo_names.names as names, COUNT(DISTINCT nodes.public_key) as nodesCount, SUM(capacity) as capacity
|
let query = `SELECT GROUP_CONCAT(DISTINCT(nodes.as_number)) as ispId, geo_names.names as names, COUNT(DISTINCT nodes.public_key) as nodesCount, SUM(capacity) as capacity
|
||||||
FROM nodes
|
FROM nodes
|
||||||
JOIN geo_names ON geo_names.id = nodes.as_number
|
JOIN geo_names ON geo_names.id = nodes.as_number
|
||||||
JOIN channels ON channels.node1_public_key = nodes.public_key OR channels.node2_public_key = nodes.public_key
|
JOIN channels ON channels.node1_public_key = nodes.public_key OR channels.node2_public_key = nodes.public_key
|
||||||
GROUP BY as_number
|
GROUP BY geo_names.names
|
||||||
ORDER BY COUNT(DISTINCT nodes.public_key) DESC
|
ORDER BY COUNT(DISTINCT nodes.public_key) DESC
|
||||||
`;
|
`;
|
||||||
const [nodesCountPerAS]: any = await DB.query(query);
|
const [nodesCountPerAS]: any = await DB.query(query);
|
||||||
@ -168,14 +168,14 @@ class NodesApi {
|
|||||||
FROM node_stats
|
FROM node_stats
|
||||||
GROUP BY public_key
|
GROUP BY public_key
|
||||||
) as b ON b.public_key = node_stats.public_key AND b.last_added = node_stats.added
|
) as b ON b.public_key = node_stats.public_key AND b.last_added = node_stats.added
|
||||||
JOIN nodes ON nodes.public_key = node_stats.public_key
|
RIGHT JOIN nodes ON nodes.public_key = node_stats.public_key
|
||||||
JOIN geo_names geo_names_country ON geo_names_country.id = nodes.country_id AND geo_names_country.type = 'country'
|
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_city ON geo_names_city.id = nodes.city_id AND geo_names_city.type = 'city'
|
||||||
WHERE nodes.as_number = ?
|
WHERE nodes.as_number IN (?)
|
||||||
ORDER BY capacity DESC
|
ORDER BY capacity DESC
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const [rows]: any = await DB.query(query, [ISPId]);
|
const [rows]: any = await DB.query(query, [ISPId.split(',')]);
|
||||||
for (let i = 0; i < rows.length; ++i) {
|
for (let i = 0; i < rows.length; ++i) {
|
||||||
rows[i].country = JSON.parse(rows[i].country);
|
rows[i].country = JSON.parse(rows[i].country);
|
||||||
rows[i].city = JSON.parse(rows[i].city);
|
rows[i].city = JSON.parse(rows[i].city);
|
||||||
|
@ -102,6 +102,7 @@ interface IConfig {
|
|||||||
ENABLED: boolean;
|
ENABLED: boolean;
|
||||||
GEOLITE2_CITY: string;
|
GEOLITE2_CITY: string;
|
||||||
GEOLITE2_ASN: string;
|
GEOLITE2_ASN: string;
|
||||||
|
GEOIP2_ISP: string;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +207,8 @@ const defaults: IConfig = {
|
|||||||
"MAXMIND": {
|
"MAXMIND": {
|
||||||
'ENABLED': false,
|
'ENABLED': false,
|
||||||
"GEOLITE2_CITY": "/usr/local/share/GeoIP/GeoLite2-City.mmdb",
|
"GEOLITE2_CITY": "/usr/local/share/GeoIP/GeoLite2-City.mmdb",
|
||||||
"GEOLITE2_ASN": "/usr/local/share/GeoIP/GeoLite2-ASN.mmdb"
|
"GEOLITE2_ASN": "/usr/local/share/GeoIP/GeoLite2-ASN.mmdb",
|
||||||
|
"GEOIP2_ISP": "/usr/local/share/GeoIP/GeoIP2-ISP.mmdb"
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as net from 'net';
|
import * as net from 'net';
|
||||||
import maxmind, { CityResponse, AsnResponse } from 'maxmind';
|
import maxmind, { CityResponse, AsnResponse, IspResponse } from 'maxmind';
|
||||||
import nodesApi from '../../../api/explorer/nodes.api';
|
import nodesApi from '../../../api/explorer/nodes.api';
|
||||||
import config from '../../../config';
|
import config from '../../../config';
|
||||||
import DB from '../../../database';
|
import DB from '../../../database';
|
||||||
@ -11,6 +11,7 @@ export async function $lookupNodeLocation(): Promise<void> {
|
|||||||
const nodes = await nodesApi.$getAllNodes();
|
const nodes = await nodesApi.$getAllNodes();
|
||||||
const lookupCity = await maxmind.open<CityResponse>(config.MAXMIND.GEOLITE2_CITY);
|
const lookupCity = await maxmind.open<CityResponse>(config.MAXMIND.GEOLITE2_CITY);
|
||||||
const lookupAsn = await maxmind.open<AsnResponse>(config.MAXMIND.GEOLITE2_ASN);
|
const lookupAsn = await maxmind.open<AsnResponse>(config.MAXMIND.GEOLITE2_ASN);
|
||||||
|
const lookupIsp = await maxmind.open<IspResponse>(config.MAXMIND.GEOIP2_ISP);
|
||||||
|
|
||||||
for (const node of nodes) {
|
for (const node of nodes) {
|
||||||
const sockets: string[] = node.sockets.split(',');
|
const sockets: string[] = node.sockets.split(',');
|
||||||
@ -20,9 +21,29 @@ export async function $lookupNodeLocation(): Promise<void> {
|
|||||||
if (hasClearnet && ip !== '127.0.1.1' && ip !== '127.0.0.1') {
|
if (hasClearnet && ip !== '127.0.1.1' && ip !== '127.0.0.1') {
|
||||||
const city = lookupCity.get(ip);
|
const city = lookupCity.get(ip);
|
||||||
const asn = lookupAsn.get(ip);
|
const asn = lookupAsn.get(ip);
|
||||||
if (city && asn) {
|
const isp = lookupIsp.get(ip);
|
||||||
const query = `UPDATE nodes SET as_number = ?, city_id = ?, country_id = ?, subdivision_id = ?, longitude = ?, latitude = ?, accuracy_radius = ? WHERE public_key = ?`;
|
|
||||||
const params = [asn.autonomous_system_number, city.city?.geoname_id, city.country?.geoname_id, city.subdivisions ? city.subdivisions[0].geoname_id : null, city.location?.longitude, city.location?.latitude, city.location?.accuracy_radius, node.public_key];
|
if (city && (asn || isp)) {
|
||||||
|
const query = `UPDATE nodes SET
|
||||||
|
as_number = ?,
|
||||||
|
city_id = ?,
|
||||||
|
country_id = ?,
|
||||||
|
subdivision_id = ?,
|
||||||
|
longitude = ?,
|
||||||
|
latitude = ?,
|
||||||
|
accuracy_radius = ?
|
||||||
|
WHERE public_key = ?`;
|
||||||
|
|
||||||
|
const params = [
|
||||||
|
isp?.autonomous_system_number ?? asn?.autonomous_system_number,
|
||||||
|
city.city?.geoname_id,
|
||||||
|
city.country?.geoname_id,
|
||||||
|
city.subdivisions ? city.subdivisions[0].geoname_id : null,
|
||||||
|
city.location?.longitude,
|
||||||
|
city.location?.latitude,
|
||||||
|
city.location?.accuracy_radius,
|
||||||
|
node.public_key
|
||||||
|
];
|
||||||
await DB.query(query, params);
|
await DB.query(query, params);
|
||||||
|
|
||||||
// Store Continent
|
// Store Continent
|
||||||
@ -61,10 +82,10 @@ export async function $lookupNodeLocation(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store AS name
|
// Store AS name
|
||||||
if (asn.autonomous_system_organization) {
|
if (isp?.autonomous_system_organization ?? asn?.autonomous_system_organization) {
|
||||||
await DB.query(
|
await DB.query(
|
||||||
`INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'as_organization', ?)`,
|
`INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'as_organization', ?)`,
|
||||||
[asn.autonomous_system_number, JSON.stringify(asn.autonomous_system_organization)]);
|
[isp?.autonomous_system_number ?? asn?.autonomous_system_number, JSON.stringify(isp?.isp ?? asn?.autonomous_system_organization)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
<tbody [attr.data-cy]="'pools-table'" *ngIf="(nodesPerAsObservable$ | async) as asList">
|
<tbody [attr.data-cy]="'pools-table'" *ngIf="(nodesPerAsObservable$ | async) as asList">
|
||||||
<tr *ngFor="let asEntry of asList">
|
<tr *ngFor="let asEntry of asList">
|
||||||
<td class="rank text-left pl-0">{{ asEntry.rank }}</td>
|
<td class="rank text-left pl-0">{{ asEntry.rank }}</td>
|
||||||
<td class="name text-left text-truncate" style="max-width: 100px">
|
<td class="name text-left text-truncate" style="max-width: 250px">
|
||||||
<a [routerLink]="[('/lightning/nodes/isp/' + asEntry.ispId) | relativeUrl]">{{ asEntry.name }}</a>
|
<a [routerLink]="[('/lightning/nodes/isp/' + asEntry.ispId) | relativeUrl]">{{ asEntry.name }}</a>
|
||||||
</td>
|
</td>
|
||||||
<td class="share text-right">{{ asEntry.share }}%</td>
|
<td class="share text-right">{{ asEntry.share }}%</td>
|
||||||
|
@ -36,14 +36,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.rank {
|
.rank {
|
||||||
width: 20%;
|
width: 15%;
|
||||||
@media (max-width: 576px) {
|
@media (max-width: 576px) {
|
||||||
display: none
|
display: none
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
width: 20%;
|
width: 25%;
|
||||||
@media (max-width: 576px) {
|
@media (max-width: 576px) {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
max-width: 150px;
|
max-width: 150px;
|
||||||
|
@ -61,7 +61,7 @@ export class NodesPerISPChartComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
generateChartSerieData(as) {
|
generateChartSerieData(as) {
|
||||||
const shareThreshold = this.isMobile() ? 2 : 1;
|
const shareThreshold = this.isMobile() ? 2 : 0.5;
|
||||||
const data: object[] = [];
|
const data: object[] = [];
|
||||||
let totalShareOther = 0;
|
let totalShareOther = 0;
|
||||||
let totalNodeOther = 0;
|
let totalNodeOther = 0;
|
||||||
@ -155,7 +155,7 @@ export class NodesPerISPChartComponent implements OnInit {
|
|||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
zlevel: 0,
|
zlevel: 0,
|
||||||
minShowLabelAngle: 3.6,
|
minShowLabelAngle: 1.8,
|
||||||
name: 'Lightning nodes',
|
name: 'Lightning nodes',
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
radius: pieSize,
|
radius: pieSize,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user