This repository has been archived on 2025-03-21. You can view files and clone it, but cannot push or open issues or pull requests.
insiemesalute-3p-nx/apps/ebitemp-api/src/modules/request-logging/endpoints/endpoints.service.ts

85 lines
2.8 KiB
TypeScript

import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import AsyncLock from 'async-lock';
import { Keyv } from 'cacheable';
import { Repository } from 'typeorm';
import { runInTransaction } from 'typeorm-transactional';
import { AccountsEntity, ApiEndpointEntity, ApiEndpointInvocazioniEntity } from '../../database/connections/ebitemp-api';
import { EBITEMP_API_DATASOURCE } from '../../database/connections/ebitemp-api/database.constants';
import { KeyvService } from '../../keyv/keyv.service';
import { RequestLog } from '../request-logger.interceptor';
import { isError } from '@stdlib/assert';
@Injectable()
export class EndpointsService {
private readonly logger = new Logger(EndpointsService.name);
private readonly lock = new AsyncLock();
private readonly keyv: Keyv;
constructor(
keyvService: KeyvService,
@InjectRepository(ApiEndpointEntity, EBITEMP_API_DATASOURCE)
private readonly endpointRepository: Repository<ApiEndpointEntity>,
@InjectRepository(ApiEndpointInvocazioniEntity, EBITEMP_API_DATASOURCE)
private readonly endpointInvocazioniRepository: Repository<ApiEndpointInvocazioniEntity>
) {
this.keyv = keyvService.create({
namespace: EndpointsService.name,
});
}
async insertOne(
user: AccountsEntity,
route: string,
method: string,
requestLog: RequestLog,
responseLog: any,
hasFailed: boolean
) {
try {
return await runInTransaction(
async () => {
const endpoint = await this.getEndpoint(route, method);
if (!endpoint) return;
const payload = JSON.stringify(requestLog);
const response = JSON.stringify(responseLog);
const invocazione = this.endpointInvocazioniRepository.create({
idAccount: user.id,
idEndpoint: endpoint.id,
timestamp: new Date(),
richiesta: payload,
risposta: response,
flagErrore: hasFailed,
});
await this.endpointInvocazioniRepository.insert(invocazione);
return invocazione;
},
{ connectionName: EBITEMP_API_DATASOURCE }
);
} catch (err) {
if (!isError(err)) throw err;
this.logger.error(`Unexpected error: ${err.message}`);
throw err;
}
}
private async getEndpoint(route: string, method: string) {
const key = `endpoint:route,method#${route},${method}`;
return await this.lock.acquire(key, async () => {
let endpoint = await this.keyv.get<ApiEndpointEntity>(key);
const isInCache = endpoint != null;
if (!isInCache) {
endpoint ??=
(await this.endpointRepository.findOne({ where: { percorso: route, metodo: method } })) ?? undefined;
if (endpoint) this.keyv.set(key, endpoint);
}
return endpoint;
});
}
}