separate home graph into it's own table

This commit is contained in:
Ben Wilson
2024-01-16 19:37:29 -05:00
parent bbc14e2272
commit 6bc42defef
8 changed files with 173 additions and 5 deletions
@@ -85,6 +85,34 @@ export class ClientStatisticsService {
} }
public async getChartDataForSiteSince(date: Date) {
const query = `
SELECT
time AS label,
ROUND(((SUM(shares) * 4294967296) / 600)) AS data
FROM
client_statistics_entity AS entry
WHERE
entry.time > ${date.getTime()}
GROUP BY
time
ORDER BY
time
LIMIT 144;
`;
const result: any[] = await this.clientStatisticsRepository.query(query);
return result.map(res => {
res.label = new Date(parseInt(res.label)).toISOString();
return res;
}).slice(0, result.length - 1)
}
// public async getHashRateForAddress(address: string) { // public async getHashRateForAddress(address: string) {
+14
View File
@@ -0,0 +1,14 @@
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class HomeGraphEntity {
@PrimaryGeneratedColumn()
id: number;
@Column({ type: 'bigint' })
label: number;
@Column({ type: 'bigint' })
data: number;
}
+15
View File
@@ -0,0 +1,15 @@
import { Global, Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { HomeGraphEntity } from './home-graph.entity';
import { HomeGraphService } from './home-graph.service';
@Global()
@Module({
imports: [TypeOrmModule.forFeature([HomeGraphEntity])],
providers: [HomeGraphService],
exports: [TypeOrmModule, HomeGraphService],
})
export class HomeGraphModule { }
+45
View File
@@ -0,0 +1,45 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { HomeGraphEntity } from './home-graph.entity';
@Injectable()
export class HomeGraphService {
constructor(
@InjectRepository(HomeGraphEntity) private homeGraphRepository: Repository<HomeGraphEntity>
) {
}
public async getLatestTime(): Promise<Date> {
const result = await this.homeGraphRepository.createQueryBuilder('entity')
.select('MAX(entity.label)', 'maxNumber')
.getRawOne();
if (result.maxNumber == null) {
return new Date(new Date().getTime() - (24 * 60 * 60 * 1000));
}
return new Date(parseInt(result.maxNumber));
}
public async save(graph: { label: number, data: number }[]) {
await this.homeGraphRepository.insert(graph);
}
public async getChartDataForSite(limit: number = 144 * 7) {
const records = await this.homeGraphRepository
.createQueryBuilder('homeGraph')
.orderBy('homeGraph.id', 'DESC')
.limit(limit)
.getRawMany();
return records.map(res => {
return {
label: new Date(parseInt(res.homeGraph_label)).toISOString(),
data: res.homeGraph_data
}
});
}
}
+15
View File
@@ -25,4 +25,19 @@ export class RpcBlockService {
public saveBlock(blockHeight: number, data: string) { public saveBlock(blockHeight: number, data: string) {
return this.rpcBlockRepository.update(blockHeight, { data }) return this.rpcBlockRepository.update(blockHeight, { data })
} }
public async deleteOldBlocks() {
const result = await this.rpcBlockRepository.createQueryBuilder('entity')
.select('MAX(entity.blockHeight)', 'maxNumber')
.getRawOne();
const newestBlock = result ? result.maxNumber : null;
await this.rpcBlockRepository.createQueryBuilder()
.delete()
.where('"blockHeight" < :newestBlock', { newestBlock })
.execute();
return;
}
} }
+4 -2
View File
@@ -6,6 +6,7 @@ import { firstValueFrom } from 'rxjs';
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';
import { ClientService } from './ORM/client/client.service'; import { ClientService } from './ORM/client/client.service';
import { HomeGraphService } from './ORM/home-graph/home-graph.service';
import { BitcoinRpcService } from './services/bitcoin-rpc.service'; import { BitcoinRpcService } from './services/bitcoin-rpc.service';
@Controller() @Controller()
@@ -18,7 +19,8 @@ export class AppController {
private readonly clientService: ClientService, private readonly clientService: ClientService,
private readonly clientStatisticsService: ClientStatisticsService, private readonly clientStatisticsService: ClientStatisticsService,
private readonly blocksService: BlocksService, private readonly blocksService: BlocksService,
private readonly bitcoinRpcService: BitcoinRpcService private readonly bitcoinRpcService: BitcoinRpcService,
private readonly homeGraphService: HomeGraphService
) { } ) { }
@Get('info') @Get('info')
@@ -66,7 +68,7 @@ export class AppController {
return cachedResult; return cachedResult;
} }
const chartData = await this.clientStatisticsService.getChartDataForSite(); const chartData = await this.homeGraphService.getChartDataForSite();
//10 min //10 min
await this.cacheManager.set(CACHE_KEY, chartData, 10 * 60 * 1000); await this.cacheManager.set(CACHE_KEY, chartData, 10 * 60 * 1000);
+6 -2
View File
@@ -17,6 +17,8 @@ import { ClientStatisticsEntity } from './ORM/client-statistics/client-statistic
import { ClientStatisticsModule } from './ORM/client-statistics/client-statistics.module'; import { ClientStatisticsModule } from './ORM/client-statistics/client-statistics.module';
import { ClientEntity } from './ORM/client/client.entity'; import { ClientEntity } from './ORM/client/client.entity';
import { ClientModule } from './ORM/client/client.module'; import { ClientModule } from './ORM/client/client.module';
import { HomeGraphEntity } from './ORM/home-graph/home-graph.entity';
import { HomeGraphModule } from './ORM/home-graph/home-graph.module';
import { RpcBlockEntity } from './ORM/rpc-block/rpc-block.entity'; import { RpcBlockEntity } from './ORM/rpc-block/rpc-block.entity';
import { RpcBlocksModule } from './ORM/rpc-block/rpc-block.module'; import { RpcBlocksModule } from './ORM/rpc-block/rpc-block.module';
import { TelegramSubscriptionsEntity } from './ORM/telegram-subscriptions/telegram-subscriptions.entity'; import { TelegramSubscriptionsEntity } from './ORM/telegram-subscriptions/telegram-subscriptions.entity';
@@ -39,7 +41,8 @@ const ORMModules = [
AddressSettingsModule, AddressSettingsModule,
TelegramSubscriptionsModule, TelegramSubscriptionsModule,
BlocksModule, BlocksModule,
RpcBlocksModule RpcBlocksModule,
HomeGraphModule
] ]
@Module({ @Module({
@@ -60,7 +63,8 @@ const ORMModules = [
BlocksEntity, BlocksEntity,
ClientStatisticsEntity, ClientStatisticsEntity,
RpcBlockEntity, RpcBlockEntity,
TelegramSubscriptionsEntity TelegramSubscriptionsEntity,
HomeGraphEntity
], ],
synchronize: configService.get('PRODUCTION') != 'true', synchronize: configService.get('PRODUCTION') != 'true',
logging: false, logging: false,
+46 -1
View File
@@ -4,6 +4,8 @@ import { DataSource } from 'typeorm';
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 { RpcBlockService } from '../ORM/rpc-block/rpc-block.service';
@Injectable() @Injectable()
export class AppService implements OnModuleInit { export class AppService implements OnModuleInit {
@@ -11,7 +13,9 @@ export class AppService implements OnModuleInit {
constructor( constructor(
private readonly clientStatisticsService: ClientStatisticsService, private readonly clientStatisticsService: ClientStatisticsService,
private readonly clientService: ClientService, private readonly clientService: ClientService,
private readonly dataSource: DataSource private readonly rpcBlockService: RpcBlockService,
private readonly homeGraphService: HomeGraphService,
private readonly dataSource: DataSource,
) { ) {
} }
@@ -39,4 +43,45 @@ export class AppService implements OnModuleInit {
} }
} }
@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() {
console.log('Updating Chart');
const latestGraphUpdate = await this.homeGraphService.getLatestTime();
const data = await this.dataSource.query(`
SELECT
time AS label,
ROUND(((SUM(shares) * 4294967296) / 600)) AS data
FROM
client_statistics_entity AS entry
WHERE
entry.time > ${latestGraphUpdate.getTime()}
GROUP BY
time
ORDER BY
time
LIMIT 144;
`)
console.log(`Fetched ${data.length} rows`);
if (data.length < 2) {
return;
}
const result = data.slice(0, data.length - 1);
this.homeGraphService.save(result);
}
} }