85 lines
2.8 KiB
TypeScript
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;
|
|
});
|
|
}
|
|
}
|