Node and channel API
This commit is contained in:
17
lightning-backend/src/api/nodes/channels.api.ts
Normal file
17
lightning-backend/src/api/nodes/channels.api.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import logger from '../../logger';
|
||||
import DB from '../../database';
|
||||
|
||||
class ChannelsApi {
|
||||
public async $getChannelsForNode(public_key: string): Promise<any> {
|
||||
try {
|
||||
const query = `SELECT * FROM channels WHERE node1_public_key = ? OR node2_public_key = ?`;
|
||||
const [rows]: any = await DB.query(query, [public_key, public_key]);
|
||||
return rows;
|
||||
} catch (e) {
|
||||
logger.err('$getChannelsForNode error: ' + (e instanceof Error ? e.message : e));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new ChannelsApi();
|
||||
23
lightning-backend/src/api/nodes/channels.routes.ts
Normal file
23
lightning-backend/src/api/nodes/channels.routes.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import config from '../../config';
|
||||
import { Express, Request, Response } from 'express';
|
||||
import channelsApi from './channels.api';
|
||||
|
||||
class ChannelsRoutes {
|
||||
constructor(app: Express) {
|
||||
app
|
||||
.get(config.MEMPOOL.API_URL_PREFIX + 'channels/:public_key', this.$getChannels)
|
||||
;
|
||||
}
|
||||
|
||||
private async $getChannels(req: Request, res: Response) {
|
||||
try {
|
||||
const channels = await channelsApi.$getChannelsForNode(req.params.public_key);
|
||||
res.json(channels);
|
||||
} catch (e) {
|
||||
res.status(500).send(e instanceof Error ? e.message : e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ChannelsRoutes;
|
||||
@@ -2,9 +2,20 @@ import logger from '../../logger';
|
||||
import DB from '../../database';
|
||||
|
||||
class NodesApi {
|
||||
public async $getNode(public_key: string): Promise<any> {
|
||||
try {
|
||||
const query = `SELECT * FROM nodes WHERE public_key = ?`;
|
||||
const [rows]: any = await DB.query(query, [public_key]);
|
||||
return rows[0];
|
||||
} catch (e) {
|
||||
logger.err('$getNode error: ' + (e instanceof Error ? e.message : e));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public async $getTopCapacityNodes(): Promise<any> {
|
||||
try {
|
||||
const query = `SELECT nodes.*, nodes_stats.capacity_left, nodes_stats.capacity_right, nodes_stats.channels_left, nodes_stats.channels_right FROM nodes LEFT JOIN nodes_stats ON nodes_stats.public_key = nodes.public_key ORDER BY nodes_stats.capacity_left + nodes_stats.capacity_right DESC LIMIT 10`;
|
||||
const query = `SELECT nodes.*, nodes_stats.capacity_left, nodes_stats.capacity_right, nodes_stats.channels_left, nodes_stats.channels_right FROM nodes LEFT JOIN nodes_stats ON nodes_stats.public_key = nodes.public_key ORDER BY nodes_stats.added DESC, nodes_stats.capacity_left + nodes_stats.capacity_right DESC LIMIT 10`;
|
||||
const [rows]: any = await DB.query(query);
|
||||
return rows;
|
||||
} catch (e) {
|
||||
@@ -15,7 +26,7 @@ class NodesApi {
|
||||
|
||||
public async $getTopChannelsNodes(): Promise<any> {
|
||||
try {
|
||||
const query = `SELECT nodes.*, nodes_stats.capacity_left, nodes_stats.capacity_right, nodes_stats.channels_left, nodes_stats.channels_right FROM nodes LEFT JOIN nodes_stats ON nodes_stats.public_key = nodes.public_key ORDER BY nodes_stats.channels_left + nodes_stats.channels_right DESC LIMIT 10`;
|
||||
const query = `SELECT nodes.*, nodes_stats.capacity_left, nodes_stats.capacity_right, nodes_stats.channels_left, nodes_stats.channels_right FROM nodes LEFT JOIN nodes_stats ON nodes_stats.public_key = nodes.public_key ORDER BY nodes_stats.added DESC, nodes_stats.channels_left + nodes_stats.channels_right DESC LIMIT 10`;
|
||||
const [rows]: any = await DB.query(query);
|
||||
return rows;
|
||||
} catch (e) {
|
||||
@@ -27,13 +38,13 @@ class NodesApi {
|
||||
public async $getLatestStatistics(): Promise<any> {
|
||||
try {
|
||||
const [rows]: any = await DB.query(`SELECT * FROM statistics ORDER BY id DESC LIMIT 1`);
|
||||
const [rows2]: any = await DB.query(`SELECT * FROM statistics ORDER BY id DESC LIMIT 1 OFFSET 24`);
|
||||
const [rows2]: any = await DB.query(`SELECT * FROM statistics ORDER BY id DESC LIMIT 1 OFFSET 71`);
|
||||
return {
|
||||
latest: rows[0],
|
||||
previous: rows2[0],
|
||||
};
|
||||
} catch (e) {
|
||||
logger.err('$getTopChannelsNodes error: ' + (e instanceof Error ? e.message : e));
|
||||
logger.err('$getLatestStatistics error: ' + (e instanceof Error ? e.message : e));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,29 @@
|
||||
import config from '../../config';
|
||||
import { Express, Request, Response } from 'express';
|
||||
import nodesApi from './nodes.api';
|
||||
import channelsApi from './channels.api';
|
||||
class NodesRoutes {
|
||||
constructor(app: Express) {
|
||||
app
|
||||
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/latest', this.$getGeneralStats)
|
||||
.get(config.MEMPOOL.API_URL_PREFIX + 'nodes/top', this.$getTopNodes)
|
||||
.get(config.MEMPOOL.API_URL_PREFIX + 'nodes/:public_key', this.$getNode)
|
||||
;
|
||||
}
|
||||
|
||||
private async $getNode(req: Request, res: Response) {
|
||||
try {
|
||||
const node = await nodesApi.$getNode(req.params.public_key);
|
||||
if (!node) {
|
||||
res.status(404).send('Node not found');
|
||||
return;
|
||||
}
|
||||
res.json(node);
|
||||
} catch (e) {
|
||||
res.status(500).send(e instanceof Error ? e.message : e);
|
||||
}
|
||||
}
|
||||
|
||||
private async $getGeneralStats(req: Request, res: Response) {
|
||||
try {
|
||||
const statistics = await nodesApi.$getLatestStatistics();
|
||||
|
||||
@@ -125,6 +125,7 @@ class DatabaseMigration {
|
||||
|
||||
// Set initial values
|
||||
await this.$executeQuery(`INSERT INTO state VALUES('schema_version', 0, NULL);`);
|
||||
await this.$executeQuery(`INSERT INTO state VALUES('last_node_stats', 0, '1970-01-01');`);
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import databaseMigration from './database-migration';
|
||||
import statsUpdater from './tasks/stats-updater.service';
|
||||
import nodeSyncService from './tasks/node-sync.service';
|
||||
import NodesRoutes from './api/nodes/nodes.routes';
|
||||
import ChannelsRoutes from './api/nodes/channels.routes';
|
||||
|
||||
logger.notice(`Mempool Server is running on port ${config.MEMPOOL.HTTP_PORT}`);
|
||||
|
||||
@@ -46,6 +47,7 @@ class LightningServer {
|
||||
});
|
||||
|
||||
const nodeRoutes = new NodesRoutes(this.app);
|
||||
const channelsRoutes = new ChannelsRoutes(this.app);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,22 +15,35 @@ class LightningStatsUpdater {
|
||||
|
||||
setTimeout(() => {
|
||||
this.$logLightningStats();
|
||||
this.$logNodeStatsDaily();
|
||||
setInterval(() => {
|
||||
this.$logLightningStats();
|
||||
this.$logNodeStatsDaily();
|
||||
}, 1000 * 60 * 60);
|
||||
}, difference);
|
||||
|
||||
// this.$logNodeStatsDaily();
|
||||
}
|
||||
|
||||
private async $logNodeStatsDaily() {
|
||||
const query = `SELECT nodes.public_key, COUNT(DISTINCT c1.id) AS channels_count_left, COUNT(DISTINCT c2.id) AS channels_count_right, SUM(DISTINCT c1.capacity) AS channels_capacity_left, SUM(DISTINCT c2.capacity) AS channels_capacity_right FROM nodes LEFT JOIN channels AS c1 ON c1.node1_public_key = nodes.public_key LEFT JOIN channels AS c2 ON c2.node2_public_key = nodes.public_key GROUP BY nodes.public_key`;
|
||||
const [nodes]: any = await DB.query(query);
|
||||
const currentDate = new Date().toISOString().split('T')[0];
|
||||
try {
|
||||
const [state]: any = await DB.query(`SELECT string FROM state WHERE name = 'last_node_stats'`);
|
||||
// Only store once per day
|
||||
if (state[0] === currentDate) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const node of nodes) {
|
||||
await DB.query(
|
||||
`INSERT INTO nodes_stats(public_key, added, capacity_left, capacity_right, channels_left, channels_right) VALUES (?, NOW(), ?, ?, ?, ?)`,
|
||||
[node.public_key, node.channels_capacity_left, node.channels_capacity_right, node.channels_count_left, node.channels_count_right]);
|
||||
const query = `SELECT nodes.public_key, c1.channels_count_left, c2.channels_count_right, c1.channels_capacity_left, c2.channels_capacity_right FROM nodes LEFT JOIN (SELECT node1_public_key, COUNT(id) AS channels_count_left, SUM(capacity) AS channels_capacity_left FROM channels GROUP BY node1_public_key) c1 ON c1.node1_public_key = nodes.public_key LEFT JOIN (SELECT node2_public_key, COUNT(id) AS channels_count_right, SUM(capacity) AS channels_capacity_right FROM channels GROUP BY node2_public_key) c2 ON c2.node2_public_key = nodes.public_key`;
|
||||
const [nodes]: any = await DB.query(query);
|
||||
|
||||
for (const node of nodes) {
|
||||
await DB.query(
|
||||
`INSERT INTO nodes_stats(public_key, added, capacity_left, capacity_right, channels_left, channels_right) VALUES (?, NOW(), ?, ?, ?, ?)`,
|
||||
[node.public_key, node.channels_capacity_left, node.channels_capacity_right,
|
||||
node.channels_count_left, node.channels_count_right]);
|
||||
}
|
||||
await DB.query(`UPDATE state SET string = ? WHERE name = 'last_node_stats'`, [currentDate]);
|
||||
} catch (e) {
|
||||
logger.err('$logNodeStatsDaily() error: ' + (e instanceof Error ? e.message : e));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user