Files
public-pool/src/ORM/client/client.service.ts
T
2026-06-21 17:30:06 -04:00

149 lines
4.6 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Repository } from 'typeorm';
import { ClientEntity } from './client.entity';
const DEFAULT_CLIENT_ACTIVE_WINDOW_MS = 30 * 60 * 1000;
@Injectable()
export class ClientService {
private readonly activeWindowMs = this.readPositiveInt('CLIENT_REPORT_ACTIVE_WINDOW_MS', DEFAULT_CLIENT_ACTIVE_WINDOW_MS);
constructor(
@InjectRepository(ClientEntity)
private clientRepository: Repository<ClientEntity>
) {
}
public async insert(partialClient: Partial<ClientEntity>): Promise<ClientEntity> {
const insertResult = await this.clientRepository.insert(partialClient);
const client = {
...partialClient,
...insertResult.generatedMaps[0]
};
return client as ClientEntity;
}
public async delete(id: string) {
return await this.clientRepository.softDelete({ id });
}
public async deleteOldClients() {
const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
return await this.clientRepository
.createQueryBuilder()
.delete()
.from(ClientEntity)
.where('deletedAt < :deletedAt', { deletedAt: oneDayAgo })
.execute();
}
public async updateBestDifficulty(id: string, bestDifficulty: number) {
return await this.clientRepository.update({ id }, { bestDifficulty });
}
public async updateBestDifficultyIfHigher(id: string, bestDifficulty: number) {
return await this.clientRepository
.createQueryBuilder()
.update(ClientEntity)
.set({ bestDifficulty })
.where('id = :id', { id })
.andWhere('"bestDifficulty" < :bestDifficulty', { bestDifficulty })
.execute();
}
public async updateHashRate(id: string, hashRate: number, updatedAt = new Date()) {
return await this.clientRepository.update({ id }, { hashRate, updatedAt, deletedAt: null });
}
public async connectedClientCount(): Promise<number> {
return await this.clientRepository.count();
}
public async getActiveIds(ids: string[]): Promise<Set<string>> {
if (ids.length === 0) {
return new Set();
}
const clients = await this.clientRepository.find({
select: {
id: true,
},
where: {
id: In(ids),
},
});
return new Set(clients.map(client => client.id));
}
public async getByAddress(address: string): Promise<ClientEntity[]> {
const activeSince = new Date(Date.now() - this.activeWindowMs);
return await this.clientRepository
.createQueryBuilder('client')
.where('client.address = :address', { address })
.andWhere('client.deletedAt IS NULL')
.andWhere('client.updatedAt > :activeSince', { activeSince })
.andWhere('client.hashRate > 0')
.orderBy('client.updatedAt', 'DESC')
.getMany();
}
public async getByName(address: string, clientName: string): Promise<ClientEntity[]> {
return await this.clientRepository.find({
where: {
address,
clientName
}
})
}
public async getBySessionId(address: string, clientName: string, sessionId: string): Promise<ClientEntity> {
return await this.clientRepository.findOne({
where: {
address,
clientName,
sessionId
}
})
}
public async deleteAll() {
return await this.clientRepository
.createQueryBuilder()
.delete()
.from(ClientEntity)
.where('"deletedAt" IS NULL')
.execute();
}
// public async getUserAgents() {
// const result = await this.clientRepository.createQueryBuilder('client')
// .select('client.userAgent as "userAgent"')
// .addSelect('COUNT(client.userAgent)', 'count')
// .addSelect('MAX(client.bestDifficulty)', 'bestDifficulty')
// .addSelect('SUM(client.hashRate)', 'totalHashRate')
// .groupBy('client.userAgent')
// .orderBy('"totalHashRate"', 'DESC')
// .getRawMany();
// return result;
// }
private readPositiveInt(name: string, defaultValue: number): number {
const value = Number(process.env[name]);
if (Number.isInteger(value) && value > 0) {
return value;
}
return defaultValue;
}
}