From ee5e054457f23c03cb1902ed434e4c55837cdf09 Mon Sep 17 00:00:00 2001 From: Alvar San Martin Date: Fri, 26 Dec 2025 15:30:18 +0100 Subject: [PATCH] Subscripciones iniciales y cliente para leer webhook --- .env | 1 + .gitignore | 2 ++ README.md | 29 +++++++++++++++++++ src/client.ts | 27 ++++++++++++++++++ src/config/index.ts | 6 +++- src/config/initial_hosts.ts | 55 +++++++++++++++++++++++++++++++++++++ src/routes/webhook.ts | 4 ++- src/server.ts | 9 +++++- 8 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 README.md create mode 100644 src/client.ts create mode 100644 src/config/initial_hosts.ts diff --git a/.env b/.env index 3e3665e..8db535c 100644 --- a/.env +++ b/.env @@ -12,5 +12,6 @@ SERVER_PORT=3300 # CLIENTE # Cliente simulado que va a recibir los webhooks +# puramente de debug para el servicio CLIENT_IP="127.0.0.1" CLIENT_PORT=3000 diff --git a/.gitignore b/.gitignore index 3c3629e..4175924 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules +dist + diff --git a/README.md b/README.md new file mode 100644 index 0000000..4be5ce2 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# Proyecto de automatizacion de desarrollo + +Tiene como objetivo levantar un servidor de Webhooks para servir al +desarrollo de shopify de forma local. + +Componentes: + +- Servidor de webhooks que emite peticiones +- Cliente (servidor express) que escucha al servidor para desarrollo + +Objetivos: + +- [x] Generar eventos por API REST +- [x] Subscripción a topics por API REST +- [x] Documentación de la API REST con Bruno +- [x] Firma de mesajes con HMAC sha256 +- [ ] Generar eventos periodicos +- [ ] Generar ordenes de shopify proceduralmente +- [ ] Generar ciclos de vida realistas create -> update -> delete +- [ ] Dockerizar +- [ ] Añadir clientes iniciales + +Webhooks Soportados: + +- [ ] orders/create +- [ ] orders/update +- [ ] orders/delete + +Propuestas: diff --git a/src/client.ts b/src/client.ts new file mode 100644 index 0000000..032e8d6 --- /dev/null +++ b/src/client.ts @@ -0,0 +1,27 @@ + +import express from 'express'; +import cors from 'cors'; +import { handleWebhook } from '#controllers/webhook.js'; +import { verifyWebhookSignature } from '#middleware/verifySig.js'; + +const client = express(); + +// Middleware +client.use(cors()); + +client.use(express.json({ + verify: (req: any, res, buf) => { + req.rawBody = buf; + } +})); +client.use(express.urlencoded({ extended: true })); + +// Webhook reception +client.post('/order/create', verifyWebhookSignature, handleWebhook); + +// Health check +client.get('/health', (req, res) => { + res.status(200).send({ resp: 'OK' }); +}); + +export default client; diff --git a/src/config/index.ts b/src/config/index.ts index bfc65e5..edf9be7 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -2,7 +2,7 @@ import dotenv from 'dotenv'; dotenv.config(); export const config = { - port: process.env.PORT || 3000, + port: process.env.PORT || 3300, webhookSecret: process.env.WEBHOOK_SECRET || 'default_secret_change_me', env: process.env.NODE_ENV || 'development', }; @@ -13,3 +13,7 @@ export const webhooksConfig = { clientIP: process.env.CLIENT_IP, clientPort: process.env.CLIENT_PORT, } + +export const clientConfig = { + port: process.env.CLIENT_PORT ?? 3000 +} diff --git a/src/config/initial_hosts.ts b/src/config/initial_hosts.ts new file mode 100644 index 0000000..26a4230 --- /dev/null +++ b/src/config/initial_hosts.ts @@ -0,0 +1,55 @@ +/** + * Configuracion de los host iniciales y a que topics escuchan + */ + +import { SubscriptionData, SubscriptorData } from "#controllers/subscriptions.js" +import { webhooksConfig } from "." + + +type SetupSubscription = SubscriptorData & { + topic: string, + options: { + /* En ms. Cada cuanto se envia un mensaje nuevo, para solo se envia un mensaje */ + period?: number, + /* Numero de mensajes, para undefiend solo se manda uno, para <= 0 seran infinitos */ + mesages?: number, + } +} + +export function generateSubscriptions(initialHosts?: SetupSubscription[]) { + const initialhs = initialHosts || INITIAL_HOSTS + const topicSubscriberMap = new Map() + + 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 +} + + +export const INITIAL_HOSTS: SetupSubscription[] = [ + { + topic: "order/create", + host: "localhost", + port: "3000", + endpoint: "/order/create", + method: "POST", + secretkey: webhooksConfig.apiSecret || "1234", + open: new Date, + options: { + period: 1000 + } + } +] + + diff --git a/src/routes/webhook.ts b/src/routes/webhook.ts index 6b26e9b..dabc2c1 100644 --- a/src/routes/webhook.ts +++ b/src/routes/webhook.ts @@ -1,10 +1,12 @@ import { Router } from 'express'; import { ordersHandlerBuilder } from '#controllers/orders.webhook.js'; import { SubscriptionManager, subscriptonHandlerBuilder } from '#controllers/subscriptions.js'; +import { generateSubscriptions } from '#config/initial_hosts.js'; const webhookRouter = Router(); -const subscriptions = new SubscriptionManager() +const baseSubscriptions = generateSubscriptions() +const subscriptions = new SubscriptionManager(baseSubscriptions) // subto webhookRouter.post('/subto', subscriptonHandlerBuilder(subscriptions)); diff --git a/src/server.ts b/src/server.ts index 9421011..c4098e2 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,9 +1,16 @@ import app from './app'; -import { config } from './config/index'; +import { clientConfig, config } from './config/index'; +import client from './client' const PORT = config.port; +const CLIENT_PORT = clientConfig.port; app.listen(PORT, () => { console.log(`Server is running on port ${PORT} in ${config.env} mode`); console.log(`Webhook endpoint: http://localhost:${PORT}/api/webhooks`); }); + + +client.listen(CLIENT_PORT, () => { + console.log(`Client ins running on port ${CLIENT_PORT}`) +})