Template del servicio de SIM
This commit is contained in:
9
.env
Normal file
9
.env
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
POSTGRES_PASSWORD='1234'
|
||||||
|
POSTGRES_USER=postgres
|
||||||
|
POSTGRES_DB=postgres
|
||||||
|
POSTGRES_PORT='5432'
|
||||||
|
DEV_POSTGRES_PORT='5432'
|
||||||
|
|
||||||
|
PORT=3000
|
||||||
|
RABBITMQ_USER='guest'
|
||||||
|
RABBITMQ_PASSWORD='guest'
|
||||||
5
.yarnrc.yml
Normal file
5
.yarnrc.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
compressionLevel: mixed
|
||||||
|
|
||||||
|
enableGlobalCache: false
|
||||||
|
|
||||||
|
nodeLinker: node-modules
|
||||||
2
build.local.sh
Executable file
2
build.local.sh
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
#/bin/bash
|
||||||
|
docker compose -f deployment/local/docker/docker-compose.yaml --project-directory ./ build
|
||||||
19
deployment/Dockerfile.dev
Normal file
19
deployment/Dockerfile.dev
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# stage base para coordinar las fases de build y ejecucion
|
||||||
|
FROM node:22-alpine AS base
|
||||||
|
WORKDIR /usr/local/app
|
||||||
|
COPY ./package.json ./yarn.lock ./
|
||||||
|
RUN corepack enable && \
|
||||||
|
corepack prepare yarn@4.12.0 --activate
|
||||||
|
|
||||||
|
# compilacion del ts -> js
|
||||||
|
FROM base AS backend
|
||||||
|
WORKDIR /usr/local/app
|
||||||
|
EXPOSE ${PORT}
|
||||||
|
COPY package*.json ./
|
||||||
|
# copia el codigo en general
|
||||||
|
COPY .tsconfig*.json ./
|
||||||
|
COPY ./packages ./packages
|
||||||
|
RUN yarn && cat package.json
|
||||||
|
CMD ["yarn", "run", "dev"]
|
||||||
|
|
||||||
|
|
||||||
31
deployment/database/test.sql
Normal file
31
deployment/database/test.sql
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
CREATE TABLE sim_job_queue (
|
||||||
|
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
||||||
|
job_type TEXT NOT NULL,
|
||||||
|
sim_id INT, -- NOT NULL???
|
||||||
|
payload JSONB NOT NULL,
|
||||||
|
status TEXT NOT NULL DEFAULT "pending", -- pasar a enum
|
||||||
|
priority SMALLINT NOT NULL DEFAULT 100, -- trabajamos entre 200 y 0 para 0 la maxima prioridad
|
||||||
|
retry_count INT NOT NULL DEFAULT 0,
|
||||||
|
max_retries INT NOT NULL DEFAULT 3, -- lo definiria en runtime
|
||||||
|
scheduled_for TIMESTAMP NOT NULL DEFAULT now(),
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT now(),
|
||||||
|
started_at TIMESTAMP,
|
||||||
|
completed_at TIMESTAMP,
|
||||||
|
error_msg TEXT,
|
||||||
|
|
||||||
|
-- En teoria el check es mas flexible que el enum
|
||||||
|
CONSTRAINT valid_status CHECK (
|
||||||
|
status IN ('pending', 'processing', 'completed', 'failed', 'dead')
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Revisar si interesa asociar cada trabajo a un id o permitir que sean independientes
|
||||||
|
CONSTRAINT fk_sim_id
|
||||||
|
FOREIGN KEY(sim_id) REFERENCES tableName(tarjetas_sim)
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Indice de pendientes de consumir
|
||||||
|
CREATE INDEX idx_job_fetch ON sim_job_queue (status, scheduled_for, priority DESC, created_at)
|
||||||
|
WHERE status = 'pending';
|
||||||
|
|
||||||
|
-- Indice del resto de procesos
|
||||||
|
CREATE INDEX idx_job_monitor ON sim_job_queue (job_type, status, created_at);
|
||||||
65
deployment/local/docker/docker-compose.yaml
Normal file
65
deployment/local/docker/docker-compose.yaml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
name: sim-eventos
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
name: network-test # Tiene que coincidir con el compose objetivo
|
||||||
|
services:
|
||||||
|
rabbitmq:
|
||||||
|
container_name: rabbitmq-broker
|
||||||
|
image: "rabbitmq:4.2.2-management"
|
||||||
|
ports:
|
||||||
|
- "5672:5672"
|
||||||
|
- "15672:15672"
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "rabbitmq-diagnostics", "check_port_connectivity"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 5
|
||||||
|
environment:
|
||||||
|
RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER}
|
||||||
|
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- ./rabbitmq_plugins/enabled_plugins:/etc/rabbitmq/enabled_plugins:ro
|
||||||
|
- ./deployment/rabbit/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf:ro
|
||||||
|
- ./deployment/rabbit/definitions.json:/etc/rabbitmq/definitions.json:ro
|
||||||
|
|
||||||
|
sim-gateway:
|
||||||
|
container_name: sim-gateway
|
||||||
|
volumes:
|
||||||
|
- ./:/usr/local/app
|
||||||
|
- ./node_modules:/usr/local/node_modules
|
||||||
|
build:
|
||||||
|
context: ./
|
||||||
|
dockerfile: deployment/Dockerfile.dev
|
||||||
|
args:
|
||||||
|
PORT: "${PORT:-3000}"
|
||||||
|
develop:
|
||||||
|
watch:
|
||||||
|
- path: ./src
|
||||||
|
action: sync
|
||||||
|
target: /usr/local/app/src
|
||||||
|
- path: ./package.json
|
||||||
|
action: rebuild
|
||||||
|
ports:
|
||||||
|
- ${PORT}:${PORT}
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
postgresql-sim:
|
||||||
|
image: postgres:16.1
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
ports:
|
||||||
|
- "5432:${DEV_POSTGRES_PORT}"
|
||||||
|
volumes:
|
||||||
|
- ./sql-data/:/var/lib/postgres/data
|
||||||
|
- ./deployment/database/test.sql:/docker-entrypoint-initdb.d/init.sql
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
|
interval: 10s
|
||||||
|
retries: 5
|
||||||
|
start_period: 30s
|
||||||
|
timeout: 10s
|
||||||
9
deployment/local/docker/rebuild.sh
Normal file
9
deployment/local/docker/rebuild.sh
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd /mnt/docker-storage/containers/savefamily/sf-shopify-orders
|
||||||
|
|
||||||
|
docker stop sf-shopify-orders-api || true
|
||||||
|
docker rm sf-shopify-orders-api || true
|
||||||
|
docker rmi sf-shopify-orders-api || true
|
||||||
|
|
||||||
|
docker compose -f docker-compose.yaml up --build -d
|
||||||
71
deployment/rabbit/definitions.json
Normal file
71
deployment/rabbit/definitions.json
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
{
|
||||||
|
"rabbit_version": "4.2.2",
|
||||||
|
"rabbitmq_version": "4.2.2",
|
||||||
|
"product_name": "RabbitMQ",
|
||||||
|
"product_version": "4.2.2",
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"name": "guest",
|
||||||
|
"password": "guest",
|
||||||
|
"hashing_algorithm": "rabbit_password_hashing_sha256",
|
||||||
|
"tags": "administrator"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vhosts": [
|
||||||
|
{
|
||||||
|
"name": "sim-vhost"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"user": "guest",
|
||||||
|
"vhost": "sim-vhost",
|
||||||
|
"configure": ".*",
|
||||||
|
"write": ".*",
|
||||||
|
"read": ".*"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"topic_permissions": [],
|
||||||
|
"parameters": [],
|
||||||
|
"global_parameters": [
|
||||||
|
{
|
||||||
|
"name": "cluster_name",
|
||||||
|
"value": "rabbit@a8d5c6e08439"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "internal_cluster_id",
|
||||||
|
"value": "rabbitmq-cluster-id-gXeBLbsUC2W2tU0Bx_QY_w"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"policies": [],
|
||||||
|
"exchanges": [
|
||||||
|
{
|
||||||
|
"name": "sim.exchange",
|
||||||
|
"vhost": "sim-vhost",
|
||||||
|
"type": "direct",
|
||||||
|
"durable": true,
|
||||||
|
"auto_delete": false,
|
||||||
|
"internal": false,
|
||||||
|
"argurments": {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queues": [
|
||||||
|
{
|
||||||
|
"name": "sim.queue",
|
||||||
|
"vhost": "sim-vhost",
|
||||||
|
"durable": true,
|
||||||
|
"auto_delete": false,
|
||||||
|
"arguments": {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bindings": [
|
||||||
|
{
|
||||||
|
"source": "sim.exchange",
|
||||||
|
"vhost": "sim-vhost",
|
||||||
|
"destination": "sim.queue",
|
||||||
|
"destination_type": "queue",
|
||||||
|
"routing_key": "sim.*",
|
||||||
|
"arguments": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
11
deployment/rabbit/rabbitmq.conf
Normal file
11
deployment/rabbit/rabbitmq.conf
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
default_user = guest
|
||||||
|
default_pass = guest
|
||||||
|
|
||||||
|
listeners.tcp.default = 5672
|
||||||
|
management.tcp.port = 15672
|
||||||
|
|
||||||
|
management.load_definitions = /etc/rabbitmq/definitions.json
|
||||||
|
|
||||||
|
default_queue_type = quorum
|
||||||
|
|
||||||
|
|
||||||
1843
package-lock.json
generated
Normal file
1843
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
36
package.json
36
package.json
@@ -1,4 +1,38 @@
|
|||||||
{
|
{
|
||||||
"name": "sim-cola-eventos",
|
"name": "sim-cola-eventos",
|
||||||
"packageManager": "yarn@4.12.0"
|
"packageManager": "yarn@4.12.0",
|
||||||
|
"workspaces": [
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"test": "vitest watch",
|
||||||
|
"build": "npx tsc",
|
||||||
|
"start": "node dist/index.js",
|
||||||
|
"typecheck": "npx tsc --noEmit",
|
||||||
|
"dev": "yarn workspaces foreach -A run dev",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"lint:fix": "eslint --fix .",
|
||||||
|
"format": "prettier --write .",
|
||||||
|
"format:check": "prettier --check ."
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@tsconfig/node22": "^22.0.5",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
|
"express": "^5.2.1",
|
||||||
|
"typescript": "^5.9.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/cors": "^2.8.19",
|
||||||
|
"@types/express": "^5.0.6",
|
||||||
|
"@types/node": "^25.0.3",
|
||||||
|
"@types/supertest": "^6.0.3",
|
||||||
|
"prettier": "^3.7.4",
|
||||||
|
"supertest": "^7.1.4",
|
||||||
|
"tsx": "^4.21.0",
|
||||||
|
"vitest": "^4.0.16"
|
||||||
|
},
|
||||||
|
"imports": {
|
||||||
|
"#*": "./src/*"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
7
packages/shared/config/env/env-validators.ts
vendored
Normal file
7
packages/shared/config/env/env-validators.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { makeValidator } from 'envalid';
|
||||||
|
|
||||||
|
import { isValidEnvString, isValidEnvStringArray } from '#shared/domain/utils/env-validators';
|
||||||
|
|
||||||
|
export const ensureEnvStringArray = makeValidator((value: unknown) => isValidEnvStringArray(value));
|
||||||
|
|
||||||
|
export const ensureEnvString = makeValidator((value: unknown) => isValidEnvString(value));
|
||||||
45
packages/shared/config/env/index.ts
vendored
Normal file
45
packages/shared/config/env/index.ts
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { bool, cleanEnv, num, port, str } from 'envalid';
|
||||||
|
|
||||||
|
import { USER_ROLES } from '#shared/domain/models/authorizer-user.entity';
|
||||||
|
|
||||||
|
import { ensureEnvString } from './env-validators';
|
||||||
|
|
||||||
|
export const env = cleanEnv(process.env, {
|
||||||
|
ENVIRONMENT: str({
|
||||||
|
choices: ['local', 'development', 'production']
|
||||||
|
}),
|
||||||
|
USE_IN_MEMORY_REPOSITORIES: bool(),
|
||||||
|
ALERTS_API_PORT: port(),
|
||||||
|
COMPANIES_COMMAND_URL: ensureEnvString(),
|
||||||
|
DEVICES_COMMAND_URL: ensureEnvString(),
|
||||||
|
USERS_COMMAND_URL: ensureEnvString(),
|
||||||
|
REDIS_PASSWORD: ensureEnvString(),
|
||||||
|
REDIS_PORT: port(),
|
||||||
|
REDIS_HOST: ensureEnvString(),
|
||||||
|
POSTGRES_USER: ensureEnvString(),
|
||||||
|
POSTGRES_PASSWORD: ensureEnvString(),
|
||||||
|
POSTGRES_PORT: port(),
|
||||||
|
POSTGRES_HOST: ensureEnvString(),
|
||||||
|
POSTGRES_DATABASE: ensureEnvString(),
|
||||||
|
RABBITMQ_HOST: ensureEnvString(),
|
||||||
|
RABBITMQ_USER: ensureEnvString(),
|
||||||
|
RABBITMQ_PASSWORD: ensureEnvString(),
|
||||||
|
RABBITMQ_EXCHANGE: ensureEnvString(),
|
||||||
|
RABBITMQ_PORT: port(),
|
||||||
|
RABBITMQ_MODULENAME: ensureEnvString(),
|
||||||
|
RABBITMQ_TTL: port(),
|
||||||
|
RABBITMQ_SECURE: bool(),
|
||||||
|
RABBITMQ_RETRY_INTERVAL: num(),
|
||||||
|
SYSTEM_USER_ID: ensureEnvString(),
|
||||||
|
SYSTEM_USER_EMAIL: ensureEnvString(),
|
||||||
|
SYSTEM_USER_ROLE: str({
|
||||||
|
choices: [
|
||||||
|
USER_ROLES.ADMIN,
|
||||||
|
USER_ROLES.CLIENT,
|
||||||
|
USER_ROLES.DELEGATION_MANAGER,
|
||||||
|
USER_ROLES.OPERATOR,
|
||||||
|
USER_ROLES.ROOM_STAFF
|
||||||
|
],
|
||||||
|
default: USER_ROLES.ADMIN
|
||||||
|
})
|
||||||
|
});
|
||||||
12
packages/shared/config/event-bus/index.ts
Normal file
12
packages/shared/config/event-bus/index.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { env } from '#api/config/env';
|
||||||
|
|
||||||
|
export const eventBusConfig = {
|
||||||
|
host: env.RABBITMQ_HOST,
|
||||||
|
user: env.RABBITMQ_USER,
|
||||||
|
password: env.RABBITMQ_PASSWORD,
|
||||||
|
exchange: env.RABBITMQ_EXCHANGE,
|
||||||
|
port: env.RABBITMQ_PORT,
|
||||||
|
modulename: env.RABBITMQ_MODULENAME,
|
||||||
|
ttl: env.RABBITMQ_TTL,
|
||||||
|
secure: env.RABBITMQ_SECURE
|
||||||
|
};
|
||||||
2
packages/shared/index.ts
Normal file
2
packages/shared/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
console.log("shared")
|
||||||
|
export default {}
|
||||||
31
packages/shared/package.json
Normal file
31
packages/shared/package.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "sim-shared",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "src/app.ts",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"dev": "tsx index.ts"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"private": true,
|
||||||
|
"packageManager": "yarn@4.12.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@tsconfig/node22": "*",
|
||||||
|
"cors": "*",
|
||||||
|
"dotenv": "*",
|
||||||
|
"express": "*",
|
||||||
|
"typescript": "*"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/cors": "*",
|
||||||
|
"@types/express": "*",
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/supertest": "*",
|
||||||
|
"prettier": "*",
|
||||||
|
"supertest": "*",
|
||||||
|
"tsx": "*",
|
||||||
|
"vitest": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
34
packages/shared/tsconfig.json
Normal file
34
packages/shared/tsconfig.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../dist/shared",
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"#adapters/*": [
|
||||||
|
"src/adapters/*"
|
||||||
|
],
|
||||||
|
"#domain/*": [
|
||||||
|
"src/domain/*"
|
||||||
|
],
|
||||||
|
"#ports/*": [
|
||||||
|
"src/ports/*"
|
||||||
|
],
|
||||||
|
"#tests/*": [
|
||||||
|
"__tests__/*"
|
||||||
|
],
|
||||||
|
"#shared/*": [
|
||||||
|
"./*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"**/*.ts",
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"index.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
13
packages/sim-gestor-eventos/.env
Normal file
13
packages/sim-gestor-eventos/.env
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
ENVIORMENT=development
|
||||||
|
|
||||||
|
RABBITMQ_HOST=rabittmq-broker
|
||||||
|
RABBITMQ_PORT=5672
|
||||||
|
RABBITMQ_USER=guest
|
||||||
|
RABBITMQ_PASSWORD=guest
|
||||||
|
RABBITMQ_SECURE=false
|
||||||
|
|
||||||
|
POSTGRES_DATABASE=postres
|
||||||
|
POSTGRES_HOST=postgresql-sim-1
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
POSTGRES_USER=postgres
|
||||||
|
POSTGRES_PASSWORD=postgres
|
||||||
7
packages/sim-gestor-eventos/config/env/env-validators.ts
vendored
Normal file
7
packages/sim-gestor-eventos/config/env/env-validators.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { makeValidator } from 'envalid';
|
||||||
|
|
||||||
|
import { isValidEnvString, isValidEnvStringArray } from '#shared/domain/utils/env-validators';
|
||||||
|
|
||||||
|
export const ensureEnvStringArray = makeValidator((value: unknown) => isValidEnvStringArray(value));
|
||||||
|
|
||||||
|
export const ensureEnvString = makeValidator((value: unknown) => isValidEnvString(value));
|
||||||
17
packages/sim-gestor-eventos/config/env/index.ts
vendored
Normal file
17
packages/sim-gestor-eventos/config/env/index.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
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: process.env.RABBITMQ_HOST,
|
||||||
|
RABBITMQ_USER: process.env.RABBITMQ_USER,
|
||||||
|
RABBITMQ_PASSWORD: process.env.RABBITMQ_PASSWORD,
|
||||||
|
RABBITMQ_EXCHANGE: process.env.RABBITMQ_EXCHANGE,
|
||||||
|
RABBITMQ_PORT: process.env.RABBITMQ_PORT,
|
||||||
|
RABBITMQ_MODULENAME: process.env.MODULENAME,
|
||||||
|
RABBITMQ_TTL: process.env.RABBITMQ_TTL,
|
||||||
|
RABBITMQ_SECURE: process.env.RABBITMQ_SECURE,
|
||||||
|
RABBITMQ_RETRY_INTERVAL: process.env.RABBITMQ_INTERVAL,
|
||||||
|
};
|
||||||
12
packages/sim-gestor-eventos/config/event-bus/index.ts
Normal file
12
packages/sim-gestor-eventos/config/event-bus/index.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { env } from '#api/config/env';
|
||||||
|
|
||||||
|
export const eventBusConfig = {
|
||||||
|
host: env.RABBITMQ_HOST,
|
||||||
|
user: env.RABBITMQ_USER,
|
||||||
|
password: env.RABBITMQ_PASSWORD,
|
||||||
|
exchange: env.RABBITMQ_EXCHANGE,
|
||||||
|
port: env.RABBITMQ_PORT,
|
||||||
|
modulename: env.RABBITMQ_MODULENAME,
|
||||||
|
ttl: env.RABBITMQ_TTL,
|
||||||
|
secure: env.RABBITMQ_SECURE
|
||||||
|
};
|
||||||
43
packages/sim-gestor-eventos/index.ts
Normal file
43
packages/sim-gestor-eventos/index.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import client, { ChannelModel, connect, Connection } from "amqplib"
|
||||||
|
import { env } from "config/env"
|
||||||
|
import { Channel } from "node:diagnostics_channel"
|
||||||
|
|
||||||
|
const rmqUser = env.RABBITMQ_USER
|
||||||
|
const rmqPass = env.RABBITMQ_PASSWORD
|
||||||
|
const rmqHost = env.RABBITMQ_HOST
|
||||||
|
const rmqPort = Number(env.RABBITMQ_PORT)
|
||||||
|
const rmqSecure = env.RABBITMQ_SECURE
|
||||||
|
|
||||||
|
class RabbitConnection {
|
||||||
|
connection?: Connection
|
||||||
|
channel?: Channel
|
||||||
|
connected: Boolean = false
|
||||||
|
|
||||||
|
|
||||||
|
protected async createConnection(): Promise<ChannelModel> {
|
||||||
|
const { hostname, port, secure } = { hostname: rmqHost, port: rmqPort, secure: rmqSecure }
|
||||||
|
const { username, password } = { username: rmqUser, password: rmqPass };
|
||||||
|
const protocol = secure ? 'amqps' : 'amqp';
|
||||||
|
|
||||||
|
const connection = await connect({
|
||||||
|
protocol,
|
||||||
|
hostname,
|
||||||
|
port,
|
||||||
|
username,
|
||||||
|
password
|
||||||
|
});
|
||||||
|
|
||||||
|
connection.on('error', (error: unknown) => {
|
||||||
|
console.error(`[EVENT BUS] Rabbitmq connection error :: ${error}`);
|
||||||
|
Promise.reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
console.log("test")
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {}
|
||||||
32
packages/sim-gestor-eventos/package.json
Normal file
32
packages/sim-gestor-eventos/package.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "sim-gestor-eventos",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.ts",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"dev": "tsx index.ts"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"packageManager": "yarn@4.12.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@tsconfig/node22": "*",
|
||||||
|
"amqplib": "^0.10.9",
|
||||||
|
"cors": "*",
|
||||||
|
"dotenv": "*",
|
||||||
|
"express": "*",
|
||||||
|
"typescript": "*"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/amqplib": "^0.10.8",
|
||||||
|
"@types/cors": "*",
|
||||||
|
"@types/express": "*",
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/supertest": "*",
|
||||||
|
"prettier": "*",
|
||||||
|
"supertest": "*",
|
||||||
|
"tsx": "*",
|
||||||
|
"vitest": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
34
packages/sim-gestor-eventos/tsconfig.json
Normal file
34
packages/sim-gestor-eventos/tsconfig.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../dist/sim-gestor-eventos",
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"#adapters/*": [
|
||||||
|
"src/adapters/*"
|
||||||
|
],
|
||||||
|
"#domain/*": [
|
||||||
|
"src/domain/*"
|
||||||
|
],
|
||||||
|
"#ports/*": [
|
||||||
|
"src/ports/*"
|
||||||
|
],
|
||||||
|
"#tests/*": [
|
||||||
|
"__tests__/*"
|
||||||
|
],
|
||||||
|
"#shared/*": [
|
||||||
|
"../shared/*"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"**/*.ts",
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"index.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
1
rabbitmq_plugins/enabled_plugins
Normal file
1
rabbitmq_plugins/enabled_plugins
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[rabbitmq_management].
|
||||||
2
run.local.sh
Executable file
2
run.local.sh
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
#/bin/bash
|
||||||
|
docker compose -f deployment/local/docker/docker-compose.yaml --project-directory ./ up
|
||||||
29
src/app.ts
Normal file
29
src/app.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import cors from 'cors';
|
||||||
|
import { config } from './config';
|
||||||
|
|
||||||
|
const PORT = config.port;
|
||||||
|
|
||||||
|
const server = express();
|
||||||
|
|
||||||
|
// Middleware
|
||||||
|
server.use(cors());
|
||||||
|
|
||||||
|
// Webhooks often require raw body for signature verification if not handled by express.json()
|
||||||
|
// using verify option in body-parser/express.json to get raw body if needed.
|
||||||
|
server.use(express.json({
|
||||||
|
verify: (req: any, res, buf) => {
|
||||||
|
req.rawBody = buf;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
server.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
|
// Health check
|
||||||
|
server.get('/health', (req, res) => {
|
||||||
|
res.status(200).send({ resp: 'OK' });
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(PORT, () => {
|
||||||
|
console.log(`[Server] Server is running on port ${PORT} in ${config.env} mode`);
|
||||||
|
console.log(`[Server] Webhook endpoint: http://localhost:${PORT}/api/webhooks`);
|
||||||
|
});
|
||||||
12
src/config/index.ts
Normal file
12
src/config/index.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import dotenv from 'dotenv';
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
port: process.env.PORT || 3000,
|
||||||
|
env: process.env.NODE_ENV || 'development',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const rabbitConfing = {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
70
src/config/initial_hosts.ts
Normal file
70
src/config/initial_hosts.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* Configuracion de los host iniciales y a que topics escuchan
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ScheduledEvent, SetupSubscription, SubscriptionData } from "#controllers/subscriptions.types.js"
|
||||||
|
import { webhooksConfig } from "."
|
||||||
|
|
||||||
|
|
||||||
|
export function generateSubscriptions(initialHosts?: SetupSubscription[]) {
|
||||||
|
const initialhs = initialHosts || INITIAL_HOSTS
|
||||||
|
const topicSubscriberMap = new Map<string, SubscriptionData>()
|
||||||
|
|
||||||
|
for (const setup of initialhs) {
|
||||||
|
const topic = setup.topic
|
||||||
|
if (topicSubscriberMap.get(topic) == undefined) {
|
||||||
|
topicSubscriberMap.set(topic, {
|
||||||
|
topic: topic,
|
||||||
|
subscriptors: []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
topicSubscriberMap.get(topic)!.subscriptors.push({
|
||||||
|
...setup
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return topicSubscriberMap
|
||||||
|
}
|
||||||
|
|
||||||
|
type InitialHost = {
|
||||||
|
topic: string,
|
||||||
|
host: string,
|
||||||
|
port: string,
|
||||||
|
endpoint: string,
|
||||||
|
method: "POST" | "PUT" | "DELETE",
|
||||||
|
secretkey: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const INITIAL_HOSTS: InitialHost[] = [
|
||||||
|
{
|
||||||
|
topic: "order/create",
|
||||||
|
host: "localhost",
|
||||||
|
port: "3500",
|
||||||
|
endpoint: "/order/create",
|
||||||
|
method: "POST",
|
||||||
|
secretkey: webhooksConfig.apiSecret || "1234",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topic: "order/create",
|
||||||
|
host: "localhost",
|
||||||
|
port: "3000",
|
||||||
|
endpoint: '/webhooks/shopify/orders',
|
||||||
|
method: "POST",
|
||||||
|
secretkey: webhooksConfig.apiSecret || "1234",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
topic: "order/create",
|
||||||
|
host: "sf-shopify-orders-api",
|
||||||
|
port: "3000",
|
||||||
|
endpoint: '/webhooks/shopify/orders',
|
||||||
|
method: "POST",
|
||||||
|
secretkey: webhooksConfig.apiSecret || "1234",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export const INITIAL_EVENTS: ScheduledEvent[] = [
|
||||||
|
{
|
||||||
|
topic: "order/create",
|
||||||
|
numberOfMessages: -1,
|
||||||
|
periodMs: 5000
|
||||||
|
}
|
||||||
|
]
|
||||||
3
src/rabbit.ts
Normal file
3
src/rabbit.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import rabbit from "rabbitmq-stream-js-client"
|
||||||
|
|
||||||
|
const client = await rabbit.connect()
|
||||||
2
stop.local.sh
Executable file
2
stop.local.sh
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
#/bin/bash
|
||||||
|
docker compose -f deployment/local/docker/docker-compose.yaml --project-directory ./ down -v
|
||||||
13
tsconfig.json
Normal file
13
tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"extends": "@tsconfig/node22/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user