UNPKG

node-red-contrib-spark

Version:

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

438 lines (352 loc) 11.4 kB
module.exports = function(RED) { 'use strict'; var SwaggerClient = require('swagger-client'); var path = require('path'); var fs = require('fs'); var _ = require('lodash'); var swaggerClient = null; var swaggerUrl = null; // create swagger client function createClient(url, callback) { // if swagger client already exists... if(swaggerClient && swaggerUrl) { return callback(null); } // if swagger url has changed... if(swaggerClient && url !== swaggerUrl) { swaggerUrl = null; swaggerClient = null; } // update swagger url swaggerUrl = url; // create swagger client swaggerClient = new SwaggerClient({ url: swaggerUrl, success: function() { callback(null); }, function(err) { callback(new Error('error')); } }); } // send api request function sendRequest(msg, resource, method, params, opts, token, processResponse, processError) { if(token && swaggerClient) { swaggerClient.clientAuthorizations.add('apiKey', new SwaggerClient.ApiKeyAuthorization('Authorization', 'Bearer ' + token, 'header')); swaggerClient[resource][method](params, opts, function(response) { processResponse(msg, response); }, function(err) { processError(msg, err); }); } else { node.error('webex teams api token or swagger client invalid or not defined'); } } function SparkApiNode(n) { RED.nodes.createNode(this, n); var node = this; node.profileConfig = RED.nodes.getNode(n.profileConfig); node.apiUrl = n.apiUrl; node.resource = n.resource; node.method = n.method; node.id = n.id; node.reqCount = 0; node.reqReceiving = false; // set node status visual indicators function setNodeStatus(state) { var status = {}; switch(state) { case 'warning': status = { fill: 'yellow', shape: 'dot', text: 'Webex Teams API: warning' }; break; case 'error': status = { fill: 'red', shape: 'dot', text: 'Webex Teams API: error' }; break; case 'input_error': status = { fill: 'red', shape: 'dot', text: 'Webex Teams API: invalid input' }; break; default: status = { fill: 'blue', shape: 'ring', text: 'Webex Teams API: ready' }; break; } node.status(status); } // indicate traffic via status function reqPing() { // increment request counter node.reqCount++; var timeout; var online = { fill: 'blue', shape: 'ring', text: 'Webex Teams API: online (' + node.reqCount + ')' }; var recieving = { fill: 'blue', shape: 'dot', text: 'Webex Teams API: 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); } function processResponse(msg, response) { reqPing(); var newMsg = {}; newMsg.topic = node.resource + '.' + node.method; // handle object response if(response && typeof response === 'object') { // capture headers if(response.hasOwnProperty('headers') && typeof response.headers === 'object') { newMsg.headers = response.headers; } // capture status if(response.hasOwnProperty('status')) { newMsg.status = response.status; } else { newMsg.status = 500; } // if response is from a delete... if(newMsg.status === 204) { newMsg.payload = {}; // send message node.send(newMsg); return null; } // if response.data if(response.hasOwnProperty('data')) { var data = response.data; // if empty response... if(typeof data === 'string' && (data === '' || data === '{}')) { // show warning node.warn('error processsing response'); // set node status setNodeStatus('warning'); return null; } // if response.data is valid... if(typeof data === 'string') { // attempt parsing of json try { data = JSON.parse(data); } catch(err) { // show warning node.warn('error: ' + err.message || 'undefined'); // set node status setNodeStatus('warning'); return null; } // if response is array of items if(typeof data === 'object' && data.hasOwnProperty('items') && data.items instanceof Array) { // if as multiple messages if(true) { // define _msgid newMsg._msgid = RED.util.generateId(); // define messages var newMsgArray = _.map(data.items, function(item, index) { var msg = _.cloneDeep(newMsg); msg.payload = item; msg.parts = { "id": msg._msgid, "type": "array", "index": index, "count": data.items.length }; return msg; }); // send message node.send([newMsgArray]); } // else, as single message else { // define _msgid newMsg._msgid = msg._msgid; // define paypload newMsg.payload = data.items; // send message node.send(newMsg); } } // else, response is single item else { newMsg.payload = data; // send message node.send(newMsg); } } } // else, response.data does not exist... else { // show warning node.warn('response has no content'); // set node status setNodeStatus('warning'); } } else { node.warn('response invalid or not received'); // set node status setNodeStatus('warning'); } } function processError(msg, response) { if(response && typeof response === 'object') { var status; var data; var errMessage; var trackingId; // capture status if(response.hasOwnProperty('status')) { status = response.status; } else { status = 500; } // capture response body if(response.hasOwnProperty('data')) { data = response.data; // if response.data is valid... if(typeof data === 'string') { // attempt parsing of json try { data = JSON.parse(data); } catch(err) { node.error('error ' + status + ': ' + err.message || 'undefined'); // set node status setNodeStatus('error'); return null; } if(data.hasOwnProperty('trackingId')) { trackingId = data.trackingId; } else { trackingId = 'unknown'; } if(data.hasOwnProperty('message')) { errMessage = data.message; } else { errMessage = 'unknown'; } node.error('error ' + status + ': ' + errMessage + ' | trackingId: ' + trackingId); } } else { node.error('error ' + status + ': undefined error'); } } else { node.error('error: unknown API response'); } // set node status setNodeStatus('error'); } // start node if profileConfig is defined if(node.profileConfig) { // set default status setNodeStatus(); // create client createClient(node.apiUrl, function(err) { // if error creating client if(err) { // show warning node.warn('invalid input'); // set node status setNodeStatus('input_error'); return; } // else, client created else { // create input event node.on('input', function(msg) { var opts = { requestContentType: 'application/json', responseContentType: 'application/json' }; var params = {}; // if input is non empty string if(msg && typeof msg.payload === 'string' && msg.payload.length > 0) { // atempt parsing of json try { params = JSON.parse(msg.payload); if(params instanceof Array) { // show warning node.warn('invalid input'); // set node status setNodeStatus('input_error'); return; } } catch(err) { // show warning node.warn(err.message); // set node status setNodeStatus('input_error'); return; } } // else if input is object else if(msg && typeof msg.payload === 'object' && !(msg.payload instanceof Array)) { params = msg.payload; } // else input is invalid else { // show warning node.warn('invalid input'); // set node status setNodeStatus('input_error'); return; } // Send Spark API Request sendRequest(msg, node.resource, node.method, params, opts, node.profileConfig.credentials.token, processResponse, processError); }); } }); } } if(RED.settings.httpNodeRoot !== false) { RED.httpNode.get('/swagger-client-web.js', function(req, res) { var clientPath = path.resolve(__dirname, './swagger-client-web.js'); fs.readFile(clientPath, function(err, data) { if(err) { res.set('Content-Type', 'text/javascript').send('{ "error": "' + err.message + '", "message": "Error reading swagger-client-web.js" }'); } else { res.set('Content-Type', 'text/javascript').send(data); } }); }); RED.httpNode.get('/api/cisco_spark_v1.json', function(req, res) { var apiPath = path.resolve(__dirname, './api/cisco_spark_v1.json'); fs.readFile(apiPath, function(err, data) { if(err) { res.set('Content-Type', 'text/javascript').send('{ "error": "' + err.message + '", "message": "Error reading api/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 API', SparkApiNode); };