From a9aef2698af6df3b6134632af50b65f7d08afe62 Mon Sep 17 00:00:00 2001 From: Adhidarma Hadiwinoto <me@adhisimon.org> Date: Tue, 6 Aug 2024 14:08:06 +0700 Subject: [PATCH] Separate webhook sender --- config.sample.json | 6 ++- lib/core-callback/sender.js | 44 ++--------------- lib/partner-listener/routers/topup.js | 38 ++------------- lib/webhook-sender.js | 89 +++++++++++++++++++++++++++++++++++ package-lock.json | 25 +++++++--- package.json | 1 + 6 files changed, 123 insertions(+), 80 deletions(-) create mode 100644 lib/webhook-sender.js diff --git a/config.sample.json b/config.sample.json index 56d3d9e..cb2cce5 100644 --- a/config.sample.json +++ b/config.sample.json @@ -8,7 +8,6 @@ "partner": { "trust_proxy": ["loopback", "linklocal"], "port": 25614, - "# webhook": "http://PLEASE_CHANGE_ME/PLEASE_CHANGE_ME", "dump": false }, "core": { @@ -27,6 +26,11 @@ "max_retry": 10 }, + "webhook": { + "url": null, + "dump": false + }, + "terminals_with_location": [], "# cluster": "Isi dengan boolean atau angka jumlah anak yang akan dibuat. Jika diisi boolean true, jumlah anak akan dihitung otomatis", diff --git a/lib/core-callback/sender.js b/lib/core-callback/sender.js index 49b52be..0687151 100644 --- a/lib/core-callback/sender.js +++ b/lib/core-callback/sender.js @@ -7,6 +7,8 @@ const logger = require('tektrans-logger'); const dumper = require('./dumper/sender'); const matrix = require('../matrix'); +const webhookSender = require('../webhook-sender'); + const HTTP_TIMEOUT = Number( config.callback_sender && config.callback_sender.http_timeout_ms, ) || 30 * 1000; @@ -180,45 +182,6 @@ const sender = async (data, xid, retry) => { delete matrix.callback_sender.active_sending[xid]; } - if (config.listener.partner.webhook) { - try { - const webhookType = 'KOMODO-CENTER-HTTPGETX.CORE-CALLBACK'; - - logger.verbose(`${MODULE_NAME} E21E3DC6: Sending webhook`, { - xid, - webhookType, - partner: config.listener.partner.webhook, - trxId: data.transaction_id && data.transaction_id.toString(), - request_id: data.request_id && data.request_id.toString(), - product_name: data.product_name, - destination: data.destination, - rc: data.rc, - }); - - axios.post(config.listener.partner.webhook, { - webhookType: 'KOMODO-CENTER-HTTPGETX.CORE-CALLBACK', - body: params, - }); - - logger.verbose(`${MODULE_NAME} 26BCA07F: Webhook sent`, { - xid, - webhookType, - partner: config.listener.partner.webhook, - trxId: data.transaction_id && data.transaction_id.toString(), - request_id: data.request_id && data.request_id.toString(), - product_name: data.product_name, - destination: data.destination, - rc: data.rc, - }); - } catch (e) { - logger.warn(`${MODULE_NAME} F722520A: Exception on calling webhook`, { - xid, - eCode: e.code, - eMessage: e.message || e.toString(), - }); - } - } - dumper( xid, isHttpPost ? 'POST' : 'GET', @@ -227,6 +190,9 @@ const sender = async (data, xid, retry) => { responseToDump, errorResponseToDump, ); + + const webhookType = 'KOMODO-CENTER-HTTPGETX.CORE-CALLBACK'; + webhookSender(xid, webhookType, params); } }; diff --git a/lib/partner-listener/routers/topup.js b/lib/partner-listener/routers/topup.js index 470e152..1c94ab0 100644 --- a/lib/partner-listener/routers/topup.js +++ b/lib/partner-listener/routers/topup.js @@ -1,7 +1,6 @@ const MODULE_NAME = 'PARTNER-LISTENER.ROUTER.TOPUP'; const express = require('express'); -const axios = require('axios'); const config = require('komodo-sdk/config'); const logger = require('tektrans-logger'); @@ -9,6 +8,7 @@ const coreapi = require('komodo-sdk/coreapi'); // const coreapi = require('../../coreapi'); const matrix = require('../../matrix'); const dumper = require('../dumper'); +const webhookSender = require('../../webhook-sender'); const router = express.Router(); module.exports = router; @@ -151,40 +151,10 @@ async function pageIndex(req, res) { res.json(responseToPartner); - if (config.listener.partner.webhook) { - try { - const webhookType = 'KOMODO-CENTER-HTTPGETX.PARTNER-LISTENER.DIRECT-RESPONSE'; - - logger.verbose(`${MODULE_NAME} 2CA59ED3: Sending webhook`, { - xid, - webhookType, - partner: config.listener.partner.webhook, - trxId: coreResponse.transaction_id, - request_id: req.body.request_id || req.query.request_id, - }); - - axios.post(config.listener.partner.webhook, { - webhookType, - body: responseToPartner, - }); - - logger.verbose(`${MODULE_NAME} 50BE8D98: Webhook sent`, { - xid, - webhookType, - partner: config.listener.partner.webhook, - trxId: coreResponse.transaction_id, - request_id: req.body.request_id || req.query.request_id, - }); - } catch (e) { - logger.warn(`${MODULE_NAME} ECC37ECA: Exception on calling webhook`, { - xid, - eCode: e.code, - eMessage: e.message || e.toString(), - }); - } - } - dumper(xid, req, responseToPartner); + + const webhookType = 'KOMODO-CENTER-HTTPGETX.PARTNER-LISTENER.DIRECT-RESPONSE'; + webhookSender(xid, webhookType, responseToPartner); } // router.all('/', (req, res) => { res.status(404).end('404: Not implemented yet'); }); diff --git a/lib/webhook-sender.js b/lib/webhook-sender.js new file mode 100644 index 0000000..ae4eb08 --- /dev/null +++ b/lib/webhook-sender.js @@ -0,0 +1,89 @@ +const MODULE_NAME = 'WEBHOOK-SENDER'; + +const axios = require('axios'); +const moment = require('moment'); +const fs = require('fs'); +const path = require('path'); +const stringify = require('json-stringify-pretty-compact'); +const config = require('komodo-sdk/config'); +const logger = require('tektrans-logger'); + +const DEFAULT_MAX_RETRY = 10; +const DEFAULT_SLEEP_BEFORE_RETRY_MS = 10 * 1000; + +const maxRetry = Number(config.webhook && config.webhook.max_retry) + || DEFAULT_MAX_RETRY; +const sleepBeforeRetryMs = Number(config.webhook && config.webhook.sleep_before_retry_ms) + || DEFAULT_SLEEP_BEFORE_RETRY_MS; + +const baseDumpDir = path.join('dump', 'webhook-sender'); +if (!fs.existsSync(baseDumpDir)) { + fs.mkdirSync(baseDumpDir, { recursive: true }); +} +const lastDumpFileName = path.join(baseDumpDir, 'last'); + +const dumper = async (xid, webhookType, body) => { + if (!config.webhook || !config.webhook.dump) { + return; + } + + await fs.promises.writeFile( + path.join(baseDumpDir, [moment().format('YYYYMMDD-HHmmssSSS'), xid].join('_')), + stringify({ webhookType, body }), + ); + + await fs.promises.writeFile( + lastDumpFileName, + stringify({ webhookType, body }), + ); +}; + +const sender = async (xid, webhookType, body, retry) => { + if (!config.webhook || !config.webhook.url) { + return; + } + + try { + logger.verbose(`${MODULE_NAME} 2CA59ED3: Sending webhook`, { + xid, + webhookType, + partner: config.webhook.url, + trxId: body.transaction_id, + request_id: body.request_id, + }); + + axios.post(config.listener.partner.webhook, { + webhookType, + body, + }); + + await dumper(xid, webhookType, body); + + logger.verbose(`${MODULE_NAME} 50BE8D98: Webhook sent`, { + xid, + webhookType, + partner: config.listener.partner.webhook, + }); + } catch (e) { + logger.warn(`${MODULE_NAME} ECC37ECA: Exception on calling webhook`, { + xid, + eCode: e.code, + eMessage: e.message || e.toString(), + retried: retry || 0, + maxRetry, + }); + + if ((retry || 0) >= maxRetry) { + logger.warn(`${MODULE_NAME} 4A60B406: Max retry exceeded`, { + xid, + }); + + return; + } + + setTimeout(() => { + sender(xid, webhookType, body, (retry || 0) + 1); + }, sleepBeforeRetryMs); + } +}; +module.exports = sender; diff --git a/package-lock.json b/package-lock.json index 7d84eee..4effd40 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "express": "^4.17.1", "express-rate-limit": "^6.6.0", "join-path": "^1.1.1", + "json-stringify-pretty-compact": "^4.0.0", "komodo-sdk": "^1.45.6", "mkdirp": "^1.0.4", "moment": "^2.24.0", @@ -2087,9 +2088,10 @@ "dev": true }, "node_modules/json-stringify-pretty-compact": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz", - "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==", + "license": "MIT" }, "node_modules/json-stringify-safe": { "version": "5.0.1", @@ -2148,6 +2150,12 @@ "sd-notify": "^2.8.0" } }, + "node_modules/komodo-sdk/node_modules/json-stringify-pretty-compact": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz", + "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==", + "license": "MIT" + }, "node_modules/komodo-sdk/node_modules/uniqid": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.1.tgz", @@ -6327,9 +6335,9 @@ "dev": true }, "json-stringify-pretty-compact": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz", - "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==" }, "json-stringify-safe": { "version": "5.0.1", @@ -6383,6 +6391,11 @@ "uuid": "^3.4.0" }, "dependencies": { + "json-stringify-pretty-compact": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz", + "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==" + }, "uniqid": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.1.tgz", diff --git a/package.json b/package.json index 6426353..6c62c8a 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "express": "^4.17.1", "express-rate-limit": "^6.6.0", "join-path": "^1.1.1", + "json-stringify-pretty-compact": "^4.0.0", "komodo-sdk": "^1.45.6", "mkdirp": "^1.0.4", "moment": "^2.24.0", -- 1.9.0