Registro de peticiones y cron

Tambien mejora de las rutas de typescript
This commit is contained in:
2026-02-05 17:46:29 +01:00
parent c7d3423f66
commit 05138a44c9
22 changed files with 508 additions and 31 deletions

View File

@@ -0,0 +1,8 @@
# claves de Objenious
OBJ_PEM_PATH=./obj.pem
OBJ_AUTHORIZATION=XOc7FtwXD8hUX2SFVX94XSty8wkOmChkwDNF09O_aIxPubMDdFUdCDCB4zpzSIxi8nOcTg7r_LM_nmd5qm7uLbksf_XArjI8iAyhjKz_2BAXPhmvKs4Fc9f3vv5LDfCVrPB9lP8P7rJ66_qnWs4jvhLQxSfn29m96hgXeCf8oySdIDUjN2q9Js3KAS5LL52Ri6ryvUeO1PvMhaPQMWRqoHIqTV1wPfPtiqQwcjUPmu5GeW164Kq1JLgV3KaGzfCZ9Qv9lbv30EJrukXxWuLCAhBS0kzrBXZoWvf2pb9uh3Am_93_dDxiIGQfIap9ZU_m8ZD1HPgvZOMCY6ZkxQconQ
OBJ_CLI_ASSERTION=XOc7FtwXD8hUX2SFVX94XSty8wkOmChkwDNF09O_aIxPubMDdFUdCDCB4zpzSIxi8nOcTg7r_LM_nmd5qm7uLbksf_XArjI8iAyhjKz_2BAXPhmvKs4Fc9f3vv5LDfCVrPB9lP8P7rJ66_qnWs4jvhLQxSfn29m96hgXeCf8oySdIDUjN2q9Js3KAS5LL52Ri6ryvUeO1PvMhaPQMWRqoHIqTV1wPfPtiqQwcjUPmu5GeW164Kq1JLgV3KaGzfCZ9Qv9lbv30EJrukXxWuLCAhBS0kzrBXZoWvf2pb9uh3Am_93_dDxiIGQfIap9ZU_m8ZD1HPgvZOMCY6ZkxQconQ
OBJ_CLIENT_ID=savefamily_rest_ws
OBJ_KID=xNfbMiyL1ORXGP8lElhcv8nVaG3EJKye4Lc1YoN3I1E
OBJ_BASE_URL=https://api-getway.objenious.com/ws
//OBJ_BASE_URL=https://api-getway.objenious.com/ws/test

View File

@@ -0,0 +1,34 @@
import { loadEnvFile } from "node:process";
import path from "node:path";
loadEnvFile(path.join("../../.env")) // Global
loadEnvFile(path.join("./.env")) // base
export const env = {
ENVIRONMENT: process.env.ENVIORMENT,
POSTGRES_USER: process.env.POSTGRES_USER,
POSTGRES_PASSWORD: process.env.POSTGRES_PASSWORD,
POSTGRES_PORT: process.env.POSTGRES_PORT,
POSTGRES_HOST: process.env.POSTGRES_HOST,
POSTGRES_DATABASE: process.env.POSTGRES_DATABASE,
RABBITMQ_HOST: String(process.env.RABBITMQ_HOST ?? "localhost"),
RABBITMQ_USER: String(process.env.RABBITMQ_USER ?? "guest"),
RABBITMQ_PASSWORD: String(process.env.RABBITMQ_PASSWORD ?? "guest"),
RABBITMQ_EXCHANGE: String(process.env.RABBITMQ_EXCHANGE ?? "/"),
RABBITMQ_PORT: parseInt(process.env.RABBITMQ_PORT ?? "5672"),
RABBITMQ_MODULENAME: process.env.MODULENAME,
RABBITMQ_TTL: process.env.RABBITMQ_TTL,
RABBITMQ_SECURE: process.env.RABBITMQ_SECURE,
RABBITMQ_RETRY_INTERVAL: process.env.RABBITMQ_INTERVAL,
RABBITMQ_VHOST: String(process.env.RABBITMQ_VHOST),
// ESPECIFICO DE OBJENIOUS
OBJ_PEM_PATH: String(process.env.OBJ_PEM_PATH),
OBJ_AUTHOIZATION: String(process.env.OBJ_ATHORIZATION),
OBJ_CLI_ASSERTION: String(process.env.OBJ_CLI_ASSERTION),
OBJ_CLIENT_ID: String(process.env.OBJ_CLIENT_ID),
OBJ_KID: String(process.env.OBJ_KID),
OBJ_BASE_URL: String(process.env.OBJ_BASE_URL)
};

View File

@@ -0,0 +1,13 @@
import { HttpClient } from "#shared/infrastructure/HTTPClient.js"
import { JWTService } from "sim-consumidor-objenious/aplication/JWT.service.js"
import { env } from "./env/index.js"
const OBJ_BASE_URL = env.OBJ_BASE_URL
export const httpInstance = new HttpClient({
baseURL: OBJ_BASE_URL,
headers: {
"content-type": " application/json; charset=utf-8"
},
jwtManager: new JWTService()
})

View File

@@ -0,0 +1,18 @@
import { Pool, QueryResult } from 'pg';
import { PgClient } from 'sim-shared/infrastructure/PgClient.js'
import { env } from 'config/env/index.js';
// Configuracion de la conexion a la BDD, deberia ser la
// Misma para todos los servicios pero hasta que se unifique todo
// se hace una por servicio.
export const pgPool = new Pool({
user: env.POSTGRES_USER,
host: env.POSTGRES_HOST,
database: env.POSTGRES_DATABASE,
password: env.POSTGRES_PASSWORD,
port: Number(env.POSTGRES_PORT) || 5432,
});
export const postgrClient = new PgClient({
pool: pgPool
})

View File

@@ -0,0 +1,37 @@
import { pgPool } from "#config/postgreConfig.js"
import { PgClient } from "sim-shared/infrastructure/PgClient.js"
import { OperationsRepository } from "sim-consumidor-objenious/infrastructure/OperationRepository.js"
import cron from "node-cron"
import { httpInstance } from "#config/httpClient.config.js"
import { CheckObjeniousRequests } from "tasks/check_objenious_request.js"
async function startCron() {
const commonSettings = {
maxRandomDelay: 1000,
noOverlap: true
}
const httpClient = httpInstance
const pgClient = new PgClient({ pool: pgPool })
await pgClient.checkDatabaseConnection()
await pgClient.checkDatabaseConnection()
const operationRepository = new OperationsRepository(pgClient)
const objTask = new CheckObjeniousRequests(
operationRepository,
httpClient
)
/*
const task = cron.createTask("* * * * *", objTask.getPendingOperations
, {
...commonSettings,
name: "Test"
})
*/
await objTask.getPendingOperations()
console.log("Lanzando task")
//task.start()
}
startCron().then(e => console.log).catch(e => console.error)

View File

@@ -0,0 +1,38 @@
{
"name": "sim-objenious-cron",
"type": "module",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "yarn tsc --project tsconfig.json && yarn tsc-alias",
"dev": "tsx watch index.ts",
"start": "node ../../dist/packages/sim-objenious-cron/index.js"
},
"author": "",
"license": "ISC",
"packageManager": "yarn@4.12.0",
"dependencies": {
"@tsconfig/node22": "*",
"cors": "*",
"dotenv": "*",
"express": "*",
"node-cron": "^4.2.1",
"sim-consumidor-objenious": "sim-consumidor-objenious:*",
"sim-shared": "sim-shared:*",
"typescript": "*"
},
"devDependencies": {
"@types/amqplib": "^0.10.8",
"@types/cors": "*",
"@types/express": "*",
"@types/node": "*",
"@types/supertest": "*",
"prettier": "*",
"supertest": "*",
"tsc-alias": "^1.8.16",
"tsx": "*",
"vitest": "*"
}
}

View File

@@ -0,0 +1 @@
export const task = async () => console.log("Background " + new Date().toISOString())

View File

@@ -0,0 +1,176 @@
import { IOperationsRepository, Objenious, ObjeniousOperation, ObjeniousOperationChange } from "#objenious-shared/domain/operationsRepository.port.js"
import { HttpClient } from "#shared/infrastructure/HTTPClient.js";
export class CheckObjeniousRequests {
constructor(
private readonly operationsRepository: IOperationsRepository,
private readonly httpClient: HttpClient
) {
}
/**
* TODO: meter a una funcion a parte task con los 3 pasos
*/
public async getPendingOperations() {
const pendingOperations = await this.operationsRepository.getPendingOperations()
if (pendingOperations.error != undefined) {
throw new Error("Error obteniendo las tareas pendientes " + pendingOperations.error)
}
if (pendingOperations.data == undefined || pendingOperations.data.length == 0) {
//Nada pendiente
return;
}
const erroneas = pendingOperations.data
.filter((e) => e.request_id == undefined)
const operacionesValidas = pendingOperations.data
.filter((e) => e.request_id != undefined)
const solicitarMassId = operacionesValidas
.filter((e) => e.mass_action_id == undefined)
const consultarEstado = pendingOperations.data
.filter(e => e.mass_action_id != undefined)
console.log("validas", operacionesValidas)
console.log("Solicitando mass id para", solicitarMassId)
const newMassActions = await this.getMassIdFromRequest(solicitarMassId)
const merged = [...newMassActions || [], ...consultarEstado]
console.log("Solicitando status para", merged)
const result = await this.getMassActionsStatus(merged)
}
private async getMassActionsStatus(requestList: ObjeniousOperation[]) {
if (requestList.length == 0) return;
const operationsList = structuredClone(requestList)
const PATH = "/actions/massActions"
const updated = []
const iccids = operationsList
.map(e => e.iccids)
.flat()
const iccidSet = new Set<string>(iccids)
const req = this.httpClient.client.get<Objenious.ResponseGetMassAction[]>(PATH, {
params: <Objenious.ParametersGetMassAction>{
"identifier.identifierType": "ICCID",
"identifier.identifiers": Array.from(iccidSet)
}
})
let res;
// 1. Comprobacion de la request.
try {
res = await req
} catch (e) {
console.error("Error comprobando el estado de ", iccidSet, e)
return;
}
const { data, status } = res
if (status != 200 || data == undefined) {
console.error("Error buscando los massActions")
return
}
if (data.length == 0) return;
// 2. Por cada elemento de la respuesta se comprueba si ha habido un cambio de estado
for (const action of data) {
const { id, status } = action
const original = operationsList.find(e => e.id == id)
console.log("Comprobando", action, original)
if (original == undefined) continue;
if (status != original?.status) {
console.log("Actualizando", action, original)
const updateData: ObjeniousOperationChange = {
operation_id: original.id!,
new_status: status,
}
original.status = status;
original.last_change_date = new Date().toISOString()
if (action.info != undefined) {
updateData.info = action.info
}
try {
await this.operationsRepository.updateOperation(updateData)
updated.push(action)
} catch (e) {
console.error("Error actualizando el estado de ", action, e)
return;
}
}
}
}
/**
* Refrescar los requests hasta que conseguir una Id de mass action
* Como no se puede consultar por
*
*/
private async getMassIdFromRequest(requestList: ObjeniousOperation[]) {
if (requestList.length == 0) return;
const PATH = "/actions/requests/"
const operationsList = structuredClone(requestList)
for (const request of operationsList) {
if (request.id == undefined) continue;
const req = this.httpClient.client.get<Objenious.ResponseGetRequestById>(PATH + request.request_id, {
})
let res;
// 1. Comprobacion de la request.
try {
res = await req
} catch (e) {
console.error("Error comprobando el estado de ", request, e)
//todo actualizar el estado para incluir el error
continue;
}
// 2. Modificacion del massId si ha habido un cambio
const massActionId = res.data.massActionIds[0]
try {
if (res.status == 200 && res.data != undefined && massActionId != undefined) {
const updateData: ObjeniousOperationChange = {
operation_id: request.id,
new_status: "IN_PROGRESS",
new_mass_action_id: String(massActionId)
}
await this.operationsRepository.updateOperation(updateData)
//! Se actualiza el registro para futuras operaciones
request.mass_action_id = String(massActionId)
}
} catch (e) {
console.log("Error actualizando ell estado de ", request)
continue;
}
}
// 3. Se devuelve la lista de los requests con las actualizaciones
return operationsList
}
}

View File

@@ -0,0 +1,42 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../dist",
"baseUrl": ".",
"paths": {
"#config/*": [
"config/*"
],
"#adapters/*": [
"adapters/*"
],
"#domain/*": [
"domain/*"
],
"#ports/*": [
"ports/*"
],
"#tests/*": [
"__tests__/*"
],
"#shared/*": [
"../shared/*"
],
// De momento se usa el consumidor como principal
"#objenious-shared/*": [
"../sim-consumidor-objenious/*"
]
}
},
"exclude": [
"node_modules"
],
"include": [
"**/*.ts",
"src/**/*.d.ts",
"tasks/background1.js"
],
"files": [
"index.ts"
]
}