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;
 | |
|     });
 | |
|   }
 | |
| }
 |