Se reciben webhooks simples desde el planificador
This commit is contained in:
@@ -17,11 +17,11 @@ client.use(express.json({
|
|||||||
client.use(express.urlencoded({ extended: true }));
|
client.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
// Webhook reception
|
// Webhook reception
|
||||||
client.post('/order/create', verifyWebhookSignature, handleWebhook);
|
client.post('/order/create', handleWebhook);
|
||||||
|
|
||||||
// Health check
|
// Health check
|
||||||
client.get('/health', (req, res) => {
|
client.get('/health', (req, res) => {
|
||||||
res.status(200).send({ resp: 'OK' });
|
res.status(200).send({ resp: 'OK - Client' });
|
||||||
});
|
});
|
||||||
|
|
||||||
export default client;
|
export default client;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Configuracion de los host iniciales y a que topics escuchan
|
* Configuracion de los host iniciales y a que topics escuchan
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SetupSubscription, SubscriptionData } from "#controllers/subscriptions.types.js"
|
import { ScheduledEvent, SetupSubscription, SubscriptionData } from "#controllers/subscriptions.types.js"
|
||||||
import { webhooksConfig } from "."
|
import { webhooksConfig } from "."
|
||||||
|
|
||||||
|
|
||||||
@@ -22,12 +22,19 @@ export function generateSubscriptions(initialHosts?: SetupSubscription[]) {
|
|||||||
...setup
|
...setup
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return topicSubscriberMap
|
return topicSubscriberMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InitialHost = {
|
||||||
|
topic: string,
|
||||||
|
host: string,
|
||||||
|
port: string,
|
||||||
|
endpoint: string,
|
||||||
|
method: "POST" | "PUT" | "DELETE",
|
||||||
|
secretkey: string,
|
||||||
|
}
|
||||||
|
|
||||||
export const INITIAL_HOSTS: SetupSubscription[] = [
|
export const INITIAL_HOSTS: InitialHost[] = [
|
||||||
{
|
{
|
||||||
topic: "order/create",
|
topic: "order/create",
|
||||||
host: "localhost",
|
host: "localhost",
|
||||||
@@ -35,11 +42,13 @@ export const INITIAL_HOSTS: SetupSubscription[] = [
|
|||||||
endpoint: "/order/create",
|
endpoint: "/order/create",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
secretkey: webhooksConfig.apiSecret || "1234",
|
secretkey: webhooksConfig.apiSecret || "1234",
|
||||||
open: new Date,
|
|
||||||
options: {
|
|
||||||
period: 1000
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const INITIAL_EVENTS: ScheduledEvent[] = [
|
||||||
|
{
|
||||||
|
topic: "order/create",
|
||||||
|
numberOfMessages: 5,
|
||||||
|
periodMs: 1000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
import { generateHMACSignature } from "#middleware/hmac.js";
|
import { generateHMACSignature } from "#middleware/hmac.js";
|
||||||
import { requestBuilder, shopifyHeaderBuilder } from "#shared/requests.js";
|
import { requestBuilder, shopifyHeaderBuilder } from "#shared/requests.js";
|
||||||
import { ShopifyEvent, SubscriptionData, SubscriptorData, Topic } from "./subscriptions.types";
|
import { ScheduledEvent, ShopifyEvent, SubscriptionData, SubscriptorData, Topic } from "./subscriptions.types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* De scheduler tiene poco
|
* De scheduler tiene poco
|
||||||
|
* TODO:
|
||||||
|
* - No se pueden crear eventos nuevos
|
||||||
*/
|
*/
|
||||||
export class EventScheduler {
|
export class EventScheduler {
|
||||||
public eventList: SubscriptorData[] = []
|
public eventList: ScheduledEvent[] = []
|
||||||
public activeIntervals: NodeJS.Timeout[] = []
|
public activeIntervals: NodeJS.Timeout[] = []
|
||||||
|
public subscriptionManager: SubscriptionManager
|
||||||
constructor(args: {
|
constructor(args: {
|
||||||
events?: SubscriptorData[],
|
events?: ScheduledEvent[],
|
||||||
|
subscriptionManager: SubscriptionManager
|
||||||
}) {
|
}) {
|
||||||
|
this.subscriptionManager = args.subscriptionManager
|
||||||
|
|
||||||
if (args.events != undefined) {
|
if (args.events != undefined) {
|
||||||
this.eventList = args.events
|
this.eventList = args.events
|
||||||
}
|
}
|
||||||
@@ -20,16 +25,25 @@ export class EventScheduler {
|
|||||||
|
|
||||||
private start() {
|
private start() {
|
||||||
for (const event of this.eventList) {
|
for (const event of this.eventList) {
|
||||||
|
console.log("Evento", event)
|
||||||
let sentMesages = 0
|
let sentMesages = 0
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
console.log("[Server] Lanzado evento ", event)
|
console.log("[Server] Lanzado evento ", event)
|
||||||
if (event.options?.mesages == undefined || event.options?.mesages < 1)
|
if (event.numberOfMessages == undefined || event.numberOfMessages < 1) {
|
||||||
|
console.log("xx")
|
||||||
return; // Se lannza de continuo
|
return; // Se lannza de continuo
|
||||||
|
}
|
||||||
|
|
||||||
|
this.subscriptionManager.poll(<ShopifyEvent>{
|
||||||
|
topic: event.topic,
|
||||||
|
data: { id: 123 }
|
||||||
|
})
|
||||||
|
|
||||||
sentMesages++;
|
sentMesages++;
|
||||||
if (sentMesages > event.options.mesages) {
|
if (sentMesages > event.numberOfMessages) {
|
||||||
clearInterval(interval)
|
clearInterval(interval)
|
||||||
}
|
}
|
||||||
}, event.options?.period ?? 1000)
|
}, event.periodMs ?? 1000)
|
||||||
this.activeIntervals.push(interval)
|
this.activeIntervals.push(interval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,13 +52,10 @@ export class EventScheduler {
|
|||||||
|
|
||||||
export class SubscriptionManager {
|
export class SubscriptionManager {
|
||||||
private subscriptions: Map<Topic, SubscriptionData> = new Map<Topic, SubscriptionData>()
|
private subscriptions: Map<Topic, SubscriptionData> = new Map<Topic, SubscriptionData>()
|
||||||
public scheduler: EventScheduler
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
scheduler: EventScheduler,
|
|
||||||
subs?: typeof this.subscriptions,
|
subs?: typeof this.subscriptions,
|
||||||
) {
|
) {
|
||||||
this.scheduler = scheduler
|
|
||||||
if (subs != undefined) {
|
if (subs != undefined) {
|
||||||
this.subscriptions = subs
|
this.subscriptions = subs
|
||||||
}
|
}
|
||||||
@@ -64,15 +75,18 @@ export class SubscriptionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public poll(event: ShopifyEvent) {
|
public poll(event: ShopifyEvent) {
|
||||||
|
console.log("!! -- !!")
|
||||||
const topic = event.topic
|
const topic = event.topic
|
||||||
|
|
||||||
if (!this.subscriptions.has(topic)) {
|
if (!this.subscriptions.has(topic)) {
|
||||||
console.error("Topic desconocido: " + topic)
|
console.error("[Server] Topic desconocido: " + topic)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const subscriptors = this.subscriptions.get(topic)
|
const subscriptors = this.subscriptions.get(topic)
|
||||||
|
|
||||||
|
console.log("[Server] Enviando evento a ", subscriptors)
|
||||||
|
|
||||||
for (const sub of subscriptors!.subscriptors) {
|
for (const sub of subscriptors!.subscriptors) {
|
||||||
const body = {
|
const body = {
|
||||||
id: 1234
|
id: 1234
|
||||||
@@ -90,13 +104,14 @@ export class SubscriptionManager {
|
|||||||
endpoint: sub.endpoint
|
endpoint: sub.endpoint
|
||||||
})
|
})
|
||||||
request.write(parsedBody)
|
request.write(parsedBody)
|
||||||
|
|
||||||
// Data puede venir en chunks!
|
// Data puede venir en chunks!
|
||||||
request.on("data", () => console.log)
|
request.on("data", () => console.log)
|
||||||
request.on("end", () => console.log)
|
request.on("end", () => console.log)
|
||||||
request.on("error", () => console.error)
|
request.on("error", () => console.error)
|
||||||
|
|
||||||
request.end()
|
request.end()
|
||||||
console.debug("Enviado evento a ", sub.host, ":", sub.port, sub.endpoint)
|
console.log("[Server] Enviado evento a ", sub.host, ":", sub.port, sub.endpoint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,14 +10,7 @@ export type SubscriptorData = {
|
|||||||
port: string,
|
port: string,
|
||||||
endpoint: string,
|
endpoint: string,
|
||||||
secretkey: string,
|
secretkey: string,
|
||||||
method: "POST" | "GET" | "PUT" | "DELETE"
|
method: "POST" | "PUT" | "DELETE"
|
||||||
open: Date,
|
|
||||||
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 type ShopifyEvent = {
|
export type ShopifyEvent = {
|
||||||
@@ -33,3 +26,9 @@ export type Topic = string
|
|||||||
export type SetupSubscription = SubscriptorData & {
|
export type SetupSubscription = SubscriptorData & {
|
||||||
topic: string
|
topic: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ScheduledEvent = {
|
||||||
|
topic: string // Meter una lista de topics/plantilla
|
||||||
|
numberOfMessages?: number,
|
||||||
|
periodMs?: number
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,21 +1,25 @@
|
|||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
import { ordersHandlerBuilder } from '#controllers/orders.webhook.js';
|
import { ordersHandlerBuilder } from '#controllers/orders.webhook.js';
|
||||||
import { subscriptonHandlerBuilder } from '#controllers/subscriptions.js';
|
import { subscriptonHandlerBuilder } from '#controllers/subscriptions.js';
|
||||||
import { generateSubscriptions } from '#config/initial_hosts.js';
|
import { generateSubscriptions, INITIAL_EVENTS, INITIAL_HOSTS } from '#config/initial_hosts.js';
|
||||||
import { EventScheduler, SubscriptionManager } from '#controllers/subscription_manager.js';
|
import { EventScheduler, SubscriptionManager } from '#controllers/subscription_manager.js';
|
||||||
|
|
||||||
const webhookRouter = Router();
|
const webhookRouter = Router();
|
||||||
|
|
||||||
const baseSubscriptions = generateSubscriptions()
|
const initialSubscriptions = generateSubscriptions()
|
||||||
const subscriptionList = [...baseSubscriptions.values()].map(e => e.subscriptors).flat()
|
const eventosIniciales = INITIAL_EVENTS
|
||||||
const scheduler = new EventScheduler({ events: subscriptionList })
|
|
||||||
const subscriptions = new SubscriptionManager(scheduler, baseSubscriptions)
|
const subscriptionsManager = new SubscriptionManager(initialSubscriptions)
|
||||||
|
const scheduler = new EventScheduler({
|
||||||
|
events: eventosIniciales,
|
||||||
|
subscriptionManager: subscriptionsManager
|
||||||
|
})
|
||||||
|
|
||||||
// subto
|
// subto
|
||||||
webhookRouter.post('/subto', subscriptonHandlerBuilder(subscriptions));
|
webhookRouter.post('/subto', subscriptonHandlerBuilder(subscriptionsManager));
|
||||||
|
|
||||||
// Simulacion de los webhook de shopify
|
// Simulacion de los webhook de shopify
|
||||||
// Al llamar se supone que se genera el evento
|
// Al llamar se supone que se genera el evento
|
||||||
webhookRouter.post('/shopify/orders', ordersHandlerBuilder(subscriptions));
|
webhookRouter.post('/shopify/orders', ordersHandlerBuilder(subscriptionsManager));
|
||||||
|
|
||||||
export default webhookRouter;
|
export default webhookRouter;
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ export function requestBuilder(args: {
|
|||||||
const request = http.request({
|
const request = http.request({
|
||||||
host: args.host,
|
host: args.host,
|
||||||
port: args.port,
|
port: args.port,
|
||||||
path: args.endpoint
|
path: args.endpoint,
|
||||||
|
method: args.method
|
||||||
})
|
})
|
||||||
|
|
||||||
Object.entries(args.headers).forEach(([name, value]) => {
|
Object.entries(args.headers).forEach(([name, value]) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user