Router intermedio para las ops de objenious

This commit is contained in:
2026-01-28 17:21:30 +01:00
parent ca75f00e22
commit 4acc04fb51
9 changed files with 183 additions and 84 deletions

View File

@@ -27,10 +27,6 @@ export class RabbitMQEventBus implements EventBus {
async consume(queue: string, callback: (msg: ConsumeMessage | null) => void) {
// Comproaciones antes de escuchar
if (this.channel == undefined) throw new Error("[RMQ] Canal no iniciallizado");
// El binding (cola -> [routingkey] -> exchange) lo hago por configuracion. Meter colas a demanda?
//await this.channel.prefetch(1)
await this.channel.consume(queue, callback)
}
@@ -55,7 +51,7 @@ export class RabbitMQEventBus implements EventBus {
try {
this.connection = await this.createConnection();
if (this.connection == undefined) throw new Error("[RMQ] Error crecreando la conexion")
this.channel = await this.createConfirmChannel()
this.channel = await this.createChannel()
this.channel.on("close", () => {
console.log("[RMQ] Canal desconectado")
setTimeout(async () => {
@@ -116,14 +112,14 @@ export class RabbitMQEventBus implements EventBus {
console.log(`[RMQ] Reintentando conexion`)
});
connection.on("disconnect", (err) => {
console.error(`[RMQ] Servidor Rabbitmq desconectado, reintentando ...`)
connection.on("disconnect", (err: unknown) => {
console.error(`[RMQ] Servidor Rabbitmq desconectado, reintentando ... :: ${err}`)
})
return connection;
}
protected async createConfirmChannel() {
protected async createChannel() {
if (this.connection == undefined) throw new Error("[RMQ] Intentando crear un canal sin una conexion")
const channel = this.connection.createChannel({
json: true,

View File

@@ -38,7 +38,7 @@ type AuthHeaders = {
exp: number,
}
const PRIVATE_KEY_PATH = __dirname + "/../obj.pem"
const PRIVATE_KEY_PATH = env.OBJ_PEM_PATH
const GET_TOKEN_URL = "https://idp.docapost.io/auth/realms/GETWAY/protocol/openid-connect/token"
const REFRESH_TOKEN_URL = GET_TOKEN_URL

View File

@@ -0,0 +1,57 @@
import { EventBus } from "#shared/domain/EventBus.port";
import { ConsumeMessage } from "amqplib";
import { SimUseCases } from "./Sim.usecases";
export class SimController {
private eventBus: EventBus;
private useCases: SimUseCases
constructor(
eventBus: EventBus,
useCases: SimUseCases
) {
this.eventBus = eventBus
this.useCases = useCases
}
public async activateSim(msg: ConsumeMessage | null) {
return async () => {
if (!this.validateActivationMsg(msg)) {
throw new Error("Error consumiendo el mensaje no es valido")
}
const msgData = Buffer.from(JSON.parse(msg?.content.toString("utf-8") || "{}").data)
console.log("Mensaje procesado", String(msgData))
// Caso de uso de activaciones
await this.useCases.activate({
dueDate: new Date().toString(),
identifier: {
identifierType: "ICCID",
identifiers: ["1234"]
}
})()
// TODO: comprobar el resultado de la opreacion
this.eventBus.ack(msg!)
}
}
public async pauseSim(msg: ConsumeMessage | null) {
return async () => {
if (!this.validateActivationMsg(msg)) {
throw new Error("Error consumiendo el mensaje no es valido")
}
const msgData = Buffer.from(JSON.parse(msg?.content.toString("utf-8") || "{}").data)
console.log("Mensaje procesado", String(msgData))
}
}
/**
* TODO:
* - Loguear motivos de la no validacion
*/
private validateActivationMsg(msg: ConsumeMessage | null) {
if (msg == undefined) return false;
return true;
}
}

View File

@@ -0,0 +1,48 @@
/**
* Dirige cada mensaje dependiendo de el tipo de accion que contenga
*/
import { ConsumeMessage } from "amqplib";
import { SimController } from "./Sim.controller";
export class SimRouter {
private simController: SimController
private routeMap: Map<string, (m: ConsumeMessage | null) => void> = new Map()
constructor(simController: SimController) {
this.simController = simController
// No me gusta que se defina en el constructor
this.routeMap = new Map([
["activate", this.simController.activateSim],
["pause", this.simController.pauseSim],
])
this.route = this.route.bind(this)
}
public route(msg: ConsumeMessage | null) {
if (msg == undefined) {
console.error("Mensaje vacio")
return;
}
const routingKey = msg.fields.routingKey
const action = routingKey.split(".")[2]
if (action == undefined) {
console.error("La routing key no tiene una accion definida")
console.error(msg.fields)
}
const accionEjecutable = this.routeMap.get(action)
if (accionEjecutable == undefined) {
console.error("La accion del mensaje no tiene un controlador asociado")
} else {
console.log("Ejecutado operacion", action)
}
}
}

View File

@@ -0,0 +1,48 @@
import { ActivationData } from "#domain/DTOs/objeniousapi"
import { HttpClient } from "#shared/infrastructure/HTTPClient"
// TODO: Pasar a un archivo de DTOs
export class SimUseCases {
private httpClient: HttpClient
constructor(args: {
httpClient: HttpClient
}) {
this.httpClient = args.httpClient
}
public activate(activationData: ActivationData) {
const OPERATION_URL = "/actions/preactivate"
return async () => {
const req = this.httpClient.client.post(OPERATION_URL, {
...activationData
})
try {
const e = await req
console.log("Activacion con exito", e.data)
} catch (error) {
console.error("Error activando ", error)
}
}
}
public pause(activationData: ActivationData) {
const OPERATION_URL = "/actions/pause"
return async () => {
const req = this.httpClient.client.post("/actions/pause", {
...activationData
})
try {
const e = await req
console.log("Sim pausada con exito", e.data)
} catch (error) {
console.error("Error pausa", error)
}
}
}
}

View File

@@ -1,51 +0,0 @@
import { EventBus } from "#shared/domain/EventBus.port";
import { ConsumeMessage } from "amqplib";
import { SimActivationUseCase } from "./SimActivation.usecase";
export class SimActivationController {
private eventBus: EventBus;
private useCases: {
activation: SimActivationUseCase
}
constructor(
eventBus: EventBus,
useCases: {
activation: SimActivationUseCase
}
) {
this.eventBus = eventBus
this.useCases = useCases
// No se si hay un sistema mejor
// convertor en const () => {} para conservar el contexto??
this.activateSim = this.activateSim.bind(this)
}
public async activateSim(msg: ConsumeMessage | null) {
if (!this.validateActivationMsg(msg)) {
throw new Error("Error consumiendo el mensaje no es valido")
}
const msgData = Buffer.from(JSON.parse(msg?.content.toString("utf-8") || "{}").data)
console.log("Mensaje procesado", String(msgData))
// Caso de uso de activaciones
await this.useCases.activation.run({
dueDate: new Date().toString(),
identifier: {
identifierType: "ICCID",
identifiers: ["1234"]
}
})
// TODO: comprobar el resultado de la opreacion
this.eventBus.ack(msg!)
}
/**
* TODO:
* - Loguear motivos de la no validacion
*/
private validateActivationMsg(msg: ConsumeMessage | null) {
if (msg == undefined) return false;
return true;
}
}

View File

@@ -1,20 +1,6 @@
import { ActivationData } from "#domain/DTOs/objeniousapi"
import { HttpClient } from "#shared/infrastructure/HTTPClient"
// TODO: Pasar a un archivo de DTOs
export type ActivationData = {
dueDate: string, // isodate
filter?: {} // no se si hace falta
identifier: {
identifiers: string[]
identifierType: "IMSI" | "MSISDN" | "REFERENCE" | "ICCID" | "IMEI"
}
}
export type ResponseError = {
error: string,
detail: Object[]
}
export class SimActivationUseCase {
private httpClient: HttpClient

View File

@@ -0,0 +1,14 @@
export type ActivationData = {
dueDate: string, // isodate
filter?: {} // no se si hace falta
identifier: {
identifiers: string[]
identifierType: "IMSI" | "MSISDN" | "REFERENCE" | "ICCID" | "IMEI"
}
}
export type ResponseError = {
error: string,
detail: Object[]
}

View File

@@ -1,22 +1,23 @@
import { startRMQClient } from "#config/eventBus.config"
import { httpInstance } from "#config/httpClient.config"
import { SimActivationController } from "aplication/SimActivation.controller"
import { SimActivationUseCase } from "aplication/SimActivation.usecase"
import { SimController } from "aplication/Sim.controller"
import { SimRouter } from "aplication/Sim.router"
import { SimUseCases } from "aplication/Sim.usecases"
async function startWorker() {
const rmqClient = await startRMQClient()
const httpClient = httpInstance
const simActivationController = new SimActivationController(
const simActivationController = new SimController(
rmqClient,
{
activation: new SimActivationUseCase({
httpClient: httpClient
})
}
new SimUseCases({
httpClient: httpClient
})
)
const simRouter = new SimRouter(simActivationController)
rmqClient.consume("sim.objenious", simActivationController.activateSim)
// de momento solo una cola por simplificar
rmqClient.consume("sim.objenious", simRouter.route)
}
startWorker()