webhook-sender.js 3.23 KB
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 validUrl = require('valid-url');
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');

const DO_WEBHOOK = config.webhook && config.webhook.url && validUrl.isWebUri(config.webhook.url);

if (!fs.existsSync(baseDumpDir)) {
    fs.mkdirSync(baseDumpDir, { recursive: true });
}

const sleepMs = (ms) => new Promise((resolve) => {
    setTimeout(() => {
        resolve();
    }, ms);
});

const dumper = async (xid, webhookType, body) => {
    if (!config.webhook || !config.webhook.dump) {
        return;
    }

    try {
        const filename = [
            [moment().format('YYYYMMDD-HHmmssSSS'), xid].join('_'),
            webhookType,
            body.request_id && ['reqid', body.request_id].join('_'),
            'json',
        ].filter((item) => item).join('.');

        // write dump file
        await fs.promises.writeFile(
            path.join(baseDumpDir, filename),
            stringify({ webhookType, body }),
        );

        // write last dump file
        await fs.promises.writeFile(
            path.join(baseDumpDir, ['last', webhookType].join('.')),
            stringify({ webhookType, body }),
        );
    } catch (e) {
        logger.warn(`${MODULE_NAME} D3EF00D9: Exception on dumper`, {
            xid,
            eCode: e.code,
            eMessage: e.message || e.toString(),
        });
    }
};

const sender = async (xid, webhookType, body, retry) => {
    if (!DO_WEBHOOK) {
        return;
    }

    try {
        logger.verbose(`${MODULE_NAME} 2CA59ED3: Sending webhook`, {
            xid,
            webhookType,
            partner: config.webhook.url,
            trxId: body.transaction_id,
            request_id: body.request_id,
            retried: retry || 0,
        });

        await axios.post(config.webhook.url, {
            webhookType,
            body,
        });

        await dumper(xid, webhookType, body);

        logger.verbose(`${MODULE_NAME} 50BE8D98: Webhook sent`, {
            xid,
            webhookType,
            partner: config.webhook.url,
        });
    } catch (e) {
        logger.warn(`${MODULE_NAME} ECC37ECA: Exception on calling webhook`, {
            xid,
            httpStatusCode: e.response && e.response.status,
            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;
        }

        await sleepMs(sleepBeforeRetryMs);
        await sender(xid, webhookType, body, (retry || 0) + 1);
    }
};
module.exports = sender;