UNPKG

@apidaze/node-red-contrib-apidaze

Version:
125 lines (105 loc) 3.53 kB
module.exports = function (RED) { 'use strict'; const bodyParser = require('body-parser'); const multer = require('multer'); const url = require('url'); const upload = multer(); function Webhook(config) { RED.nodes.createNode(this, config); // methods names are case-sensitive. changing them will break functionality. const supportedHttpMethods = ['get', 'post']; this.accountNode = RED.nodes.getNode(config.account); this.path = config.path; const host = this.context().global.get('baseUrl'); if (!this.accountNode) { this.warn('Missing account node in the webhook!'); } if (!this.path) { this.warn('Missing path!'); } if (!this.path.startsWith('/')) { this.path = `/${this.path}`; } const node = this; this.errorHandler = function errorHandler(err, req, res) { node.warn(err); res.sendStatus(500); }; this.callback = function callback(req, res) { /** * debug context */ const flowContext = node.context().flow; const msgid = RED.util.generateId(); res._msgid = msgid; const httpMethod = req.method.toLowerCase(); const requestType = ((method, type, req) => { if (method === 'post') { if (type === 'recording' || req.get('content-type').includes('multipart/form-data')) { return 'recording'; } else if (type === 'incomingWebhookSMS') { return 'message'; } else if (type === 'CDR') { return 'cdr'; } else if (type === 'transcription') { return 'transcription'; } return 'unknown'; } else if (type === 'incomingRTCCall' || !!req.query.sessid) { return 'rtcCall'; } return 'voiceCall'; })(httpMethod, req.query.type || req.body.type, req); const response = { _msgid: msgid, req: req, res: { _res: res }, payload: { hookType: requestType, call: { custom: {} }, message: {}, body: req.body, query: req.query, headers: req.headers, webhookUrl: host ? url.resolve(host, node.path) : (req.query.url || req.url), file: req.file, responses: [], script: [], }, }; node.send(response); }; const maxApiRequestSize = RED.settings.apiMaxLength || '5mb'; const reqBodyParser = bodyParser.urlencoded({ limit: maxApiRequestSize, extended: true, }); supportedHttpMethods.forEach((supportedHttpMethod) => { RED.httpNode[supportedHttpMethod]( this.path, reqBodyParser, upload.single('mediafile'), this.callback, this.errorHandler ); }); this.on('close', function () { const routerStack = RED.httpNode._router.stack; const stackCount = routerStack.length; for (let i = stackCount - 1; i >= 0; i -= 1) { const layer = routerStack[i]; const routeLayer = layer.route; const hasRouteLayer = !!routeLayer; const pathMatches = hasRouteLayer && routeLayer.path === node.path; const methodMatches = supportedHttpMethods.some( (method) => routeLayer && routeLayer.methods[method] ); const routeMatches = hasRouteLayer && pathMatches && methodMatches; if (routeMatches) { routerStack.splice(i, 1); } } }); } RED.nodes.registerType('webhook', Webhook); };