mirror of
https://github.com/benjamin-wilson/public-pool.git
synced 2026-09-29 09:05:06 -07:00
user agent report
This commit is contained in:
@@ -0,0 +1,15 @@
|
|||||||
|
import { Global, Module } from '@nestjs/common';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
|
||||||
|
import { UserAgentReportService } from './user-agent-report.service';
|
||||||
|
import { UserAgentReportView } from './user-agent-report.view';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Global()
|
||||||
|
@Module({
|
||||||
|
imports: [TypeOrmModule.forFeature([UserAgentReportView])],
|
||||||
|
providers: [UserAgentReportService],
|
||||||
|
exports: [TypeOrmModule, UserAgentReportService],
|
||||||
|
})
|
||||||
|
export class UserAgentReportModule { }
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
|
||||||
|
import { UserAgentReportView } from './user-agent-report.view';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UserAgentReportService {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@InjectRepository(UserAgentReportView)
|
||||||
|
private userAgentReport: Repository<UserAgentReportView>,
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getReport() {
|
||||||
|
return await this.userAgentReport.find();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async refreshReport() {
|
||||||
|
try {
|
||||||
|
return await this.userAgentReport.query(`
|
||||||
|
COMMIT;
|
||||||
|
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
|
||||||
|
REFRESH MATERIALIZED VIEW user_agent_report_view;
|
||||||
|
COMMIT;
|
||||||
|
`);
|
||||||
|
} catch (e) {
|
||||||
|
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { DataSource, ViewColumn, ViewEntity } from 'typeorm';
|
||||||
|
|
||||||
|
import { ClientEntity } from '../../client/client.entity';
|
||||||
|
|
||||||
|
@ViewEntity({
|
||||||
|
materialized: true,
|
||||||
|
expression: (dataSource: DataSource) =>
|
||||||
|
dataSource
|
||||||
|
.createQueryBuilder()
|
||||||
|
.select('client.userAgent as "userAgent"')
|
||||||
|
.addSelect('COUNT(client.userAgent)', 'count')
|
||||||
|
.addSelect('MAX(client.bestDifficulty)', 'bestDifficulty')
|
||||||
|
.addSelect('SUM(client.hashRate)', 'totalHashRate')
|
||||||
|
.from(ClientEntity, 'client')
|
||||||
|
.groupBy('client.userAgent')
|
||||||
|
.orderBy('"totalHashRate"', 'DESC')
|
||||||
|
})
|
||||||
|
export class UserAgentReportView {
|
||||||
|
@ViewColumn()
|
||||||
|
userAgent: string;
|
||||||
|
@ViewColumn()
|
||||||
|
count: number;
|
||||||
|
@ViewColumn()
|
||||||
|
bestDifficulty: number;
|
||||||
|
@ViewColumn()
|
||||||
|
totalHashRate: number;
|
||||||
|
}
|
||||||
@@ -104,16 +104,16 @@ export class ClientService {
|
|||||||
return await this.clientRepository.softDelete({})
|
return await this.clientRepository.softDelete({})
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getUserAgents() {
|
// public async getUserAgents() {
|
||||||
const result = await this.clientRepository.createQueryBuilder('client')
|
// const result = await this.clientRepository.createQueryBuilder('client')
|
||||||
.select('client.userAgent as "userAgent"')
|
// .select('client.userAgent as "userAgent"')
|
||||||
.addSelect('COUNT(client.userAgent)', 'count')
|
// .addSelect('COUNT(client.userAgent)', 'count')
|
||||||
.addSelect('MAX(client.bestDifficulty)', 'bestDifficulty')
|
// .addSelect('MAX(client.bestDifficulty)', 'bestDifficulty')
|
||||||
.addSelect('SUM(client.hashRate)', 'totalHashRate')
|
// .addSelect('SUM(client.hashRate)', 'totalHashRate')
|
||||||
.groupBy('client.userAgent')
|
// .groupBy('client.userAgent')
|
||||||
.orderBy('"totalHashRate"', 'DESC')
|
// .orderBy('"totalHashRate"', 'DESC')
|
||||||
.getRawMany();
|
// .getRawMany();
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ import { Controller, Get, Inject } from '@nestjs/common';
|
|||||||
import { Cache } from 'cache-manager';
|
import { Cache } from 'cache-manager';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
|
||||||
|
import { UserAgentReportService } from './ORM/_views/user-agent-report/user-agent-report.service';
|
||||||
import { AddressSettingsService } from './ORM/address-settings/address-settings.service';
|
import { AddressSettingsService } from './ORM/address-settings/address-settings.service';
|
||||||
import { BlocksService } from './ORM/blocks/blocks.service';
|
import { BlocksService } from './ORM/blocks/blocks.service';
|
||||||
import { ClientStatisticsService } from './ORM/client-statistics/client-statistics.service';
|
import { ClientStatisticsService } from './ORM/client-statistics/client-statistics.service';
|
||||||
@@ -22,7 +23,8 @@ export class AppController {
|
|||||||
private readonly blocksService: BlocksService,
|
private readonly blocksService: BlocksService,
|
||||||
private readonly bitcoinRpcService: BitcoinRpcService,
|
private readonly bitcoinRpcService: BitcoinRpcService,
|
||||||
private readonly homeGraphService: HomeGraphService,
|
private readonly homeGraphService: HomeGraphService,
|
||||||
private readonly addressSettingsService: AddressSettingsService
|
private readonly addressSettingsService: AddressSettingsService,
|
||||||
|
private readonly userAgentReportService: UserAgentReportService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
@Get('info')
|
@Get('info')
|
||||||
@@ -38,7 +40,7 @@ export class AppController {
|
|||||||
|
|
||||||
|
|
||||||
const blockData = await this.blocksService.getFoundBlocks();
|
const blockData = await this.blocksService.getFoundBlocks();
|
||||||
const userAgents = await this.clientService.getUserAgents();
|
const userAgents = await this.userAgentReportService.getReport();
|
||||||
const highScores = await this.addressSettingsService.getHighScores();
|
const highScores = await this.addressSettingsService.getHighScores();
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
@@ -48,8 +50,8 @@ export class AppController {
|
|||||||
uptime: this.uptime
|
uptime: this.uptime
|
||||||
};
|
};
|
||||||
|
|
||||||
//1 min
|
//5 min
|
||||||
await this.cacheManager.set(CACHE_KEY, data, 1 * 60 * 1000);
|
await this.cacheManager.set(CACHE_KEY, data, 5 * 60 * 1000);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
@@ -66,9 +68,9 @@ export class AppController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const userAgents = await this.clientService.getUserAgents();
|
const userAgents = await this.userAgentReportService.getReport();
|
||||||
const totalHashRate = userAgents.reduce((acc, userAgent) => acc + parseFloat(userAgent.totalHashRate), 0);
|
const totalHashRate = userAgents.reduce((acc, userAgent) => acc + userAgent.totalHashRate, 0);
|
||||||
const totalMiners = userAgents.reduce((acc, userAgent) => acc + parseInt(userAgent.count), 0);
|
const totalMiners = userAgents.reduce((acc, userAgent) => acc + userAgent.count, 0);
|
||||||
const blockHeight = (await firstValueFrom(this.bitcoinRpcService.newBlock$)).blocks;
|
const blockHeight = (await firstValueFrom(this.bitcoinRpcService.newBlock$)).blocks;
|
||||||
const blocksFound = await this.blocksService.getFoundBlocks();
|
const blocksFound = await this.blocksService.getFoundBlocks();
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -10,6 +10,8 @@ import { AddressController } from './controllers/address/address.controller';
|
|||||||
import { ClientController } from './controllers/client/client.controller';
|
import { ClientController } from './controllers/client/client.controller';
|
||||||
import { BitcoinAddressValidator } from './models/validators/bitcoin-address.validator';
|
import { BitcoinAddressValidator } from './models/validators/bitcoin-address.validator';
|
||||||
import { UniqueNonceIndex } from './ORM/_migrations/UniqueNonceIndex';
|
import { UniqueNonceIndex } from './ORM/_migrations/UniqueNonceIndex';
|
||||||
|
import { UserAgentReportModule } from './ORM/_views/user-agent-report/user-agent-report.module';
|
||||||
|
import { UserAgentReportView } from './ORM/_views/user-agent-report/user-agent-report.view';
|
||||||
import { AddressSettingsEntity } from './ORM/address-settings/address-settings.entity';
|
import { AddressSettingsEntity } from './ORM/address-settings/address-settings.entity';
|
||||||
import { AddressSettingsModule } from './ORM/address-settings/address-settings.module';
|
import { AddressSettingsModule } from './ORM/address-settings/address-settings.module';
|
||||||
import { BlocksEntity } from './ORM/blocks/blocks.entity';
|
import { BlocksEntity } from './ORM/blocks/blocks.entity';
|
||||||
@@ -43,7 +45,8 @@ const ORMModules = [
|
|||||||
TelegramSubscriptionsModule,
|
TelegramSubscriptionsModule,
|
||||||
BlocksModule,
|
BlocksModule,
|
||||||
RpcBlocksModule,
|
RpcBlocksModule,
|
||||||
HomeGraphModule
|
HomeGraphModule,
|
||||||
|
UserAgentReportModule
|
||||||
]
|
]
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
@@ -65,7 +68,8 @@ const ORMModules = [
|
|||||||
ClientStatisticsEntity,
|
ClientStatisticsEntity,
|
||||||
RpcBlockEntity,
|
RpcBlockEntity,
|
||||||
TelegramSubscriptionsEntity,
|
TelegramSubscriptionsEntity,
|
||||||
HomeGraphEntity
|
HomeGraphEntity,
|
||||||
|
UserAgentReportView
|
||||||
],
|
],
|
||||||
synchronize: configService.get('PRODUCTION') != 'true',
|
synchronize: configService.get('PRODUCTION') != 'true',
|
||||||
logging: false,
|
logging: false,
|
||||||
|
|||||||
+37
-24
@@ -1,7 +1,7 @@
|
|||||||
import { Injectable, OnModuleInit } from '@nestjs/common';
|
import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||||
import { Interval } from '@nestjs/schedule';
|
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
|
|
||||||
|
import { UserAgentReportService } from '../ORM/_views/user-agent-report/user-agent-report.service';
|
||||||
import { ClientStatisticsService } from '../ORM/client-statistics/client-statistics.service';
|
import { ClientStatisticsService } from '../ORM/client-statistics/client-statistics.service';
|
||||||
import { ClientService } from '../ORM/client/client.service';
|
import { ClientService } from '../ORM/client/client.service';
|
||||||
import { HomeGraphService } from '../ORM/home-graph/home-graph.service';
|
import { HomeGraphService } from '../ORM/home-graph/home-graph.service';
|
||||||
@@ -16,41 +16,54 @@ export class AppService implements OnModuleInit {
|
|||||||
private readonly rpcBlockService: RpcBlockService,
|
private readonly rpcBlockService: RpcBlockService,
|
||||||
private readonly homeGraphService: HomeGraphService,
|
private readonly homeGraphService: HomeGraphService,
|
||||||
private readonly dataSource: DataSource,
|
private readonly dataSource: DataSource,
|
||||||
|
private readonly userAgentReportService: UserAgentReportService
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async onModuleInit() {
|
async onModuleInit() {
|
||||||
|
if (process.env.ENABLE_SOLO == 'true' && (process.env.NODE_APP_INSTANCE == null || process.env.NODE_APP_INSTANCE == '0')) {
|
||||||
|
|
||||||
|
setInterval(async () => {
|
||||||
|
await this.deleteOldStatistics();
|
||||||
|
}, 1000 * 60 * 60);
|
||||||
|
|
||||||
|
setInterval(async () => {
|
||||||
|
console.log('Killing dead clients');
|
||||||
|
await this.clientService.killDeadClients();
|
||||||
|
}, 1000 * 60 * 5);
|
||||||
|
|
||||||
|
setInterval(async () => {
|
||||||
|
console.log('Deleting Old Blocks');
|
||||||
|
await this.rpcBlockService.deleteOldBlocks();
|
||||||
|
}, 1000 * 60 * 60 * 24);
|
||||||
|
|
||||||
|
setInterval(async () => {
|
||||||
|
await this.updateChart();
|
||||||
|
}, 1000 * 60 * 10);
|
||||||
|
|
||||||
|
|
||||||
|
setInterval(async () => {
|
||||||
|
console.log('Refreshing user agent report view')
|
||||||
|
await this.userAgentReportService.refreshReport();
|
||||||
|
console.log('Finished Refreshing user agent report view')
|
||||||
|
}, 1000 * 60 * 5);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Interval(1000 * 60 * 60)
|
|
||||||
private async deleteOldStatistics() {
|
private async deleteOldStatistics() {
|
||||||
console.log('Deleting statistics');
|
console.log('Deleting statistics');
|
||||||
if (process.env.ENABLE_SOLO == 'true' && (process.env.NODE_APP_INSTANCE == null || process.env.NODE_APP_INSTANCE == '0')) {
|
|
||||||
const deletedStatistics = await this.clientStatisticsService.deleteOldStatistics();
|
const deletedStatistics = await this.clientStatisticsService.deleteOldStatistics();
|
||||||
console.log(`Deleted ${deletedStatistics.affected} old statistics`);
|
console.log(`Deleted ${deletedStatistics.affected} old statistics`);
|
||||||
const deletedClients = await this.clientService.deleteOldClients();
|
const deletedClients = await this.clientService.deleteOldClients();
|
||||||
console.log(`Deleted ${deletedClients.affected} old clients`);
|
console.log(`Deleted ${deletedClients.affected} old clients`);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Interval(1000 * 60 * 5)
|
|
||||||
private async killDeadClients() {
|
|
||||||
console.log('Killing dead clients');
|
|
||||||
if (process.env.ENABLE_SOLO == 'true' && (process.env.NODE_APP_INSTANCE == null || process.env.NODE_APP_INSTANCE == '0')) {
|
|
||||||
await this.clientService.killDeadClients();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Interval(1000 * 60 * 60 * 24)
|
|
||||||
private async deleteOldBlocks() {
|
|
||||||
console.log('Deleting Old Blocks');
|
|
||||||
if (process.env.ENABLE_SOLO == 'true' && (process.env.NODE_APP_INSTANCE == null || process.env.NODE_APP_INSTANCE == '0')) {
|
|
||||||
await this.rpcBlockService.deleteOldBlocks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Interval(1000 * 60 * 10)
|
|
||||||
private async updateChart() {
|
private async updateChart() {
|
||||||
console.log('Updating Chart');
|
console.log('Updating Chart');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user