diff --git a/package-lock.json b/package-lock.json index d7e934a..7b5a6ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.1", "license": "UNLICENSED", "dependencies": { + "@nestjs/cache-manager": "^2.0.1", "@nestjs/common": "^9.0.0", "@nestjs/config": "^2.3.2", "@nestjs/core": "^9.0.0", @@ -19,6 +20,7 @@ "bitcoin-address-validation": "^2.2.1", "bitcoinjs-lib": "^6.1.3", "bs58": "^5.0.0", + "cache-manager": "^5.2.3", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "discord.js": "^14.11.0", @@ -1654,6 +1656,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@nestjs/cache-manager": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@nestjs/cache-manager/-/cache-manager-2.0.1.tgz", + "integrity": "sha512-UxDeuarskoSPVzLRl6SVNaUlGnwclhq48JCvQ/zu7W2RRaBqlxzfM8/CaRjrpSwC7/LVrLKv+f9EoAWYOvSULg==", + "peerDependencies": { + "@nestjs/common": "^9.0.0 || ^10.0.0", + "@nestjs/core": "^9.0.0 || ^10.0.0", + "cache-manager": "<=5", + "reflect-metadata": "^0.1.12", + "rxjs": "^7.0.0" + } + }, "node_modules/@nestjs/cli": { "version": "9.5.0", "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-9.5.0.tgz", @@ -3671,6 +3685,23 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/cache-manager": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-5.2.3.tgz", + "integrity": "sha512-9OErI8fksFkxAMJ8Mco0aiZSdphyd90HcKiOMJQncSlU1yq/9lHHxrT8PDayxrmr9IIIZPOAEfXuGSD7g29uog==", + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "lru-cache": "^9.1.2" + } + }, + "node_modules/cache-manager/node_modules/lru-cache": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.2.tgz", + "integrity": "sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ==", + "engines": { + "node": "14 || >=16.14" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -7313,6 +7344,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -12272,6 +12308,12 @@ } } }, + "@nestjs/cache-manager": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@nestjs/cache-manager/-/cache-manager-2.0.1.tgz", + "integrity": "sha512-UxDeuarskoSPVzLRl6SVNaUlGnwclhq48JCvQ/zu7W2RRaBqlxzfM8/CaRjrpSwC7/LVrLKv+f9EoAWYOvSULg==", + "requires": {} + }, "@nestjs/cli": { "version": "9.5.0", "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-9.5.0.tgz", @@ -13815,6 +13857,22 @@ } } }, + "cache-manager": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-5.2.3.tgz", + "integrity": "sha512-9OErI8fksFkxAMJ8Mco0aiZSdphyd90HcKiOMJQncSlU1yq/9lHHxrT8PDayxrmr9IIIZPOAEfXuGSD7g29uog==", + "requires": { + "lodash.clonedeep": "^4.5.0", + "lru-cache": "^9.1.2" + }, + "dependencies": { + "lru-cache": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.2.tgz", + "integrity": "sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ==" + } + } + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -16536,6 +16594,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", diff --git a/package.json b/package.json index 08b2ecc..cc3e624 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "test:e2e": "jest --config ./test/jest-e2e.json" }, "dependencies": { + "@nestjs/cache-manager": "^2.0.1", "@nestjs/common": "^9.0.0", "@nestjs/config": "^2.3.2", "@nestjs/core": "^9.0.0", @@ -30,6 +31,7 @@ "bitcoin-address-validation": "^2.2.1", "bitcoinjs-lib": "^6.1.3", "bs58": "^5.0.0", + "cache-manager": "^5.2.3", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "discord.js": "^14.11.0", diff --git a/src/ORM/client-statistics/client-statistics.service.ts b/src/ORM/client-statistics/client-statistics.service.ts index fa94cef..e3c8210 100644 --- a/src/ORM/client-statistics/client-statistics.service.ts +++ b/src/ORM/client-statistics/client-statistics.service.ts @@ -9,8 +9,10 @@ import { ClientStatisticsEntity } from './client-statistics.entity'; export class ClientStatisticsService { constructor( + + @InjectRepository(ClientStatisticsEntity) - private clientStatisticsRepository: Repository + private clientStatisticsRepository: Repository, ) { } @@ -30,6 +32,38 @@ export class ClientStatisticsService { .execute(); } + public async getChartDataForSite() { + + + const query = ` + WITH result_set AS ( + SELECT + MAX(time) || 'GMT' AS label, + (SUM(difficulty) * 4294967296) / + ((JULIANDAY(MAX(time)) - JULIANDAY(MIN(time))) * 24 * 60 * 60 * 1000000000) AS data + FROM + client_statistics_entity AS entry + WHERE + entry.time > datetime("now", "-1 day") + GROUP BY + strftime('%Y-%m-%d %H', time, 'localtime') || (strftime('%M', time, 'localtime') / 10) + ORDER BY + time + ) + SELECT * + FROM result_set + WHERE label <> (SELECT MAX(label) FROM result_set); + `; + + const result = await this.clientStatisticsRepository.query(query); + + + + return result; + + } + + public async getHashRateForAddress(address: string) { const query = ` diff --git a/src/app.controller.ts b/src/app.controller.ts index a889df0..e83af13 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -1,18 +1,36 @@ -import { Controller, Get } from '@nestjs/common'; +import { CACHE_MANAGER } from '@nestjs/cache-manager'; +import { Controller, Get, Inject } from '@nestjs/common'; +import { Cache } from 'cache-manager'; +import { ClientStatisticsService } from './ORM/client-statistics/client-statistics.service'; import { ClientService } from './ORM/client/client.service'; - - @Controller() export class AppController { constructor( - private clientService: ClientService + @Inject(CACHE_MANAGER) private cacheManager: Cache, + private clientService: ClientService, + private clientStatisticsService: ClientStatisticsService ) { } @Get('info') - public info() { + public async info() { + const CACHE_KEY = 'SITE_HASHRATE_GRAPH'; + const cachedResult = await this.cacheManager.get(CACHE_KEY); + if (cachedResult != null) { + return { + chartData: cachedResult + }; + } + + const chartData = await this.clientStatisticsService.getChartDataForSite(); + + await this.cacheManager.set(CACHE_KEY, chartData, 600) + + return { + chartData + }; } } diff --git a/src/app.module.ts b/src/app.module.ts index ca61a54..e25ff07 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,3 +1,4 @@ +import { CacheModule } from '@nestjs/cache-manager'; import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { ScheduleModule } from '@nestjs/schedule'; @@ -35,7 +36,9 @@ const ORMModules = [ autoLoadEntities: true, logging: false }), + CacheModule.register(), ScheduleModule.forRoot(), + ...ORMModules ], controllers: [ diff --git a/src/services/discord.service.ts b/src/services/discord.service.ts index d1cd8dc..6caeebb 100644 --- a/src/services/discord.service.ts +++ b/src/services/discord.service.ts @@ -39,7 +39,11 @@ export class DiscordService implements OnModuleInit { this.guildId = this.configService.get('DISCORD_BOT_GUILD_ID'); this.channelId = this.configService.get('DISCORD_BOT_CHANNEL_ID') - if (this.token.length < 1 || this.clientId.length < 1 || this.guildId.length < 1 || this.channelId.length < 1) { + if (this.token == null || this.token.length < 1 || + this.clientId == null || this.clientId.length < 1 || + this.guildId == null || this.guildId.length < 1 || + this.channelId == null || this.channelId.length < 1 + ) { return; } diff --git a/src/services/telegram.service.ts b/src/services/telegram.service.ts index 78eec12..90f028c 100644 --- a/src/services/telegram.service.ts +++ b/src/services/telegram.service.ts @@ -15,7 +15,7 @@ export class TelegramService implements OnModuleInit { private readonly telegramSubscriptionsService: TelegramSubscriptionsService ) { const token: string | null = this.configService.get('TELEGRAM_BOT_TOKEN'); - if (token.length < 1) { + if (token == null || token.length < 1) { return; } this.bot = new TelegramBot(token, { polling: true });