UNPKG

node-red-contrib-spark

Version:

Node-RED Nodes to integrate with the Cisco Webex Teams API

320 lines (251 loc) 9.16 kB
module.exports = function(RED) { 'use strict'; var bodyParser = require('body-parser'); var jsonParser = bodyParser.json(); var request = require('request'); var path = require('path'); var fs = require('fs'); var _ = require('lodash'); function SparkWebhookNode(n) { RED.nodes.createNode(this, n); var node = this; var httpNodeRoot; if(RED.settings.httpNodeRoot) { httpNodeRoot = RED.settings.httpNodeRoot; } else { httpNodeRoot = '/'; } var webhookReq = { url: 'https://api.ciscospark.com/v1/webhooks/', json: true }; node.profileConfig = RED.nodes.getNode(n.profileConfig); node.name = n.name || 'webhhook'; node.resource = n.resource; node.event = n.event; node.host = n.host; node.basename = 'node_red_contrib_spark_' + node.id.replace(/\./g, ''); node.pathname = httpNodeRoot + node.basename; node.webhookTarget = node.host + node.pathname; node.webhookId = n.webhookId || null; node.webhookObj = n.webhookObj || null; node.reqCount = 0; node.reqReceiving = false; // set default status node.status({ fill: 'blue', shape: 'ring', text: 'Webex Teams Webhook: ready' }); // remove webhooks node.removeWebhooks = function(callback) { // if Webex Teams api token and webhook id are defined... if(node.profileConfig.credentials && node.profileConfig.credentials.token) { // clone module request template var _webhookReq = _.clone(webhookReq); // set credentials for request object _webhookReq.auth = { bearer: node.profileConfig.credentials.token }; // send request to delete webhook request.get(_webhookReq, function(err, res) { // if request error... if(err) { node.log('error: ' + err.message); if(callback) callback(err); } // else, if webhooks returned... else if(res && res.body && res.body.items && res.body.items instanceof Array && node.webhookTarget) { _.forEach(res.body.items, function(webhook) { if(webhook.targetUrl == node.webhookTarget) { node.removeWebhook(webhook.id); node.log('Removed existing webhook for: ' + webhook.targetUrl); } }); if(callback) callback(null); } // else... else { if(callback) callback(null); } }); } else { if(callback) callback(null); } }; // remove a webhook node.removeWebhook = function(id) { var webhookId = node.webhookId; if(typeof id !== 'undefined') { webhookId = id; } // if Webex Teams api token and webhook id are defined... if(node.profileConfig.credentials && node.profileConfig.credentials.token && webhookId) { // clone module request template var _webhookReq = _.clone(webhookReq); // set credentials for request object _webhookReq.auth = { bearer: node.profileConfig.credentials.token }; // set delete url for request object _webhookReq.url = _webhookReq.url + webhookId; // send request to delete webhook request.delete(_webhookReq, function(err, res) { // if request error... if(err) { node.log('error: ' + err.message); } // else, if response ok or webhook not found... else if(res && res.statusCode && (res.statusCode == 204 || res.statusCode == 404)) { if(typeof id !== 'undefined') { node.webhookId = null; node.webhookObj = null; } } // else, response not ok... else { var statusCode = res && res.statusCode && res.statusCode > 1 ? res.statusCode : 500; var errorMsg = 'response code "' + res.statusCode + '" received removing webhook for "' + node.name + '"'; node.log('error: ' + errorMsg); } }); } }; // create new webhook node.createWebhook = function() { // if Webex Teams api token and webhook target are defined... if(node.profileConfig.credentials && node.profileConfig.credentials.token && node.webhookTarget) { // clone module request template var _webhookReq = _.clone(webhookReq); // set credentials for request object _webhookReq.auth = { bearer: node.profileConfig.credentials.token }; // set body for request object _webhookReq.body = { name: 'NODE-RED:' + node.id, targetUrl: node.webhookTarget, resource: node.resource, event: 'all' }; // send request to add a webhook request.post(_webhookReq, function(err, res) { // if request error... if(err) { node.warn('error: ' + err.message); } // else, if response ok... else if(res && res.statusCode && res.statusCode == 200 && typeof res.body === 'object') { node.webhookObj = res.body; node.webhookId = res.body.id; node.log('Created webhook for: ' + node.webhookTarget); } // else, response not ok... else { var statusCode = res && res.statusCode && res.statusCode > 1 ? res.statusCode : 500; var errorMsg = 'response code "' + res.statusCode + '" received adding webhook for "' + node.name + '"'; node.error('error: ' + errorMsg); } }); } // else, Webex Teams api token not defined... else { var errorMsg = 'api token or webhookTarget not defined'; node.error('error: ' + errorMsg); } }; // indicate traffic via status node.reqPing = function() { // increment request counter node.reqCount++; var timeout; var online = { fill: 'blue', shape: 'ring', text: 'Webex Teams Webhook: online (' + node.reqCount + ')' }; var recieving = { fill: 'blue', shape: 'dot', text: 'Webex Teams Webhook: online (' + node.reqCount + ')' }; if(node.reqReceiving) { clearTimeout(timeout); } else { node.status(recieving); } node.reqReceiving = true; timeout = setTimeout(function() { node.reqReceiving = false; node.status(online); }, 200); }; node.processError = function(err, req, res, next) { node.log(err); res.sendStatus(500); }; node.processRequest = function(req, res, next) { var msg = {}; msg.payload = {}; msg.error = null; // if req and res if(req && res) { // if properties in body are valid... if(typeof req.body === 'object' && req.body.resource && req.body.event) { // if webhook matches resource and event if(req.body.resource === node.resource && req.body.event === node.event) { // attach headers to msg msg.headers = req.headers; // attach message body msg.payload = req.body; // ping the metric counter node.reqPing(); // send msg node.send(msg); } } // send 200 OK res.status(200).send('OK'); } // else next else if(typeof next === 'function') { node.log('error: could not process request'); next(); } // else else { node.log('error: could not process request'); } }; // cleanup node on deploy node.on('close',function() { var node = this; // remove route RED.httpNode._router.stack.forEach(function(route,i,routes) { if (route.route && route.route.path.match(/^\/node_red_contrib_spark_.*/)) { routes.splice(i,1); node.log('Removed existing route for: ' + node.pathname); } }); // remove webhook node.removeWebhook(); }); // create route for this node RED.httpNode.post('/' + node.basename, jsonParser, node.processRequest, node.processError); node.log('Created new route for: ' + node.pathname); // remove webhooks with same Target Url and then create a new one... node.removeWebhooks(function(err) { // create webhook node.createWebhook(); }); } if(RED.settings.httpNodeRoot !== false) { RED.httpNode.get('/webhook/cisco_spark_v1.json', function(req, res) { var swaggerPath = path.resolve(__dirname, './webhook/cisco_spark_v1.json'); fs.readFile(swaggerPath, function(err, data) { if(err) { res.set('Content-Type', 'text/javascript').send('{ "error": "' + err.message + '", "message": "Error reading webhook/cisco_spark_v1.json" }'); } else { res.set('Content-Type', 'text/javascript').send(data); } }); }); } else { this.warn('httpNodeRoot is disabled in node-red settings'); } RED.nodes.registerType('Webex Teams Webhook', SparkWebhookNode); };