node-red-contrib-mqrest-client
Advanced tools
Comparing version
@@ -17,33 +17,161 @@ /** | ||
const https = require('https'); | ||
const axios = require('axios'); | ||
class MQRESTUtils { | ||
constructor(node) { | ||
this._node = node; | ||
this.headerMap = new Map(); | ||
this.headerMap.set('csrf','ibm-mq-rest-csrf-token'); | ||
this.headerMap.set('corrId','ibm-mq-md-correlationId'); | ||
this.headerMap.set('expiry', 'ibm-mq-md-expiry'); | ||
this.headerMap.set('persistence', 'ibm-mq-md-persistence'); | ||
this.headerMap.set('replyTo', 'ibm-mq-md-replyTo'); | ||
} | ||
constructor(node) { | ||
this._node = node; | ||
} | ||
reportError(msg, err) { | ||
var messageTxt = err; | ||
//if (err.code && 'ENOENT' === err.code) { | ||
// messageTxt = 'Invalid File Path'; | ||
//} | ||
if (err.error) { | ||
messageTxt = err.error; | ||
} else if (err.description) { | ||
messageTxt = err.description; | ||
} else if (err.message) { | ||
messageTxt = err.message; | ||
} | ||
this._node.status({ | ||
fill: 'red', | ||
shape: 'dot', | ||
text: messageTxt | ||
}); | ||
reportError(msg, err) { | ||
var messageTxt = err; | ||
//if (err.code && 'ENOENT' === err.code) { | ||
// messageTxt = 'Invalid File Path'; | ||
//} | ||
if (err.error) { | ||
messageTxt = err.error; | ||
} else if (err.description) { | ||
messageTxt = err.description; | ||
} else if (err.message) { | ||
messageTxt = err.message; | ||
} | ||
this._node.status({ | ||
fill: 'red', | ||
shape: 'dot', | ||
text: messageTxt | ||
}); | ||
msg.result = {}; | ||
msg.result['error'] = err; | ||
this._node.error(messageTxt, msg); | ||
} | ||
msg.result = {}; | ||
msg.result['error'] = err; | ||
this._node.error(messageTxt, msg); | ||
} | ||
processResponseData(msg, data, expectedType) { | ||
if (expectedType !== typeof data) { | ||
return Promise.reject('Unexpected type data ' + typeof data); | ||
} else { | ||
let b = data; | ||
try { | ||
b = JSON.parse(data); | ||
} | ||
catch (e) { | ||
} | ||
msg.payload = b; | ||
// console.log("here", b); | ||
} | ||
return Promise.resolve(msg); | ||
} | ||
verifyPayload(msg, config) { | ||
let error = null; | ||
let stringPayload = msg.payload; | ||
let type = typeof msg.payload | ||
if (!config.contentType || config.contentType.includes('text/plain')) { | ||
if ('string' !== type) { | ||
error = 'Expecting a string in msg.payload'; | ||
} | ||
} else if (config.contentType.includes('application/json')) { | ||
if ('object' !== type) { | ||
error = 'Expecting a json object in msg.payload'; | ||
} else { | ||
stringPayload = JSON.stringify(msg.payload); | ||
} | ||
} | ||
if (error) { | ||
return Promise.reject(error); | ||
} else { | ||
return Promise.resolve(stringPayload); | ||
} | ||
} | ||
generateOptionalParams(msg) { | ||
var optionalParams="?"; | ||
for (var x in msg.mqparams) { | ||
optionalParams += `${x}=${msg.mqparams[x]}&` | ||
} | ||
return optionalParams.slice(0,-1); | ||
} | ||
generateOptionalHeaders(msg, axiosCommand) { | ||
for (var x in msg.headers) { | ||
axiosCommand.headers[this.headerMap.get(x)] = msg.headers[x]; | ||
} | ||
return axiosCommand; | ||
} | ||
axiosCommand(user, config, msg, url) { | ||
var axiosCommand = { | ||
url: url+this.generateOptionalParams(msg), | ||
method: config.operation, | ||
auth: { | ||
username: user.username, | ||
password: user.password, | ||
}, | ||
httpsAgent: new https.Agent({ rejectUnauthorized: false }) | ||
} | ||
switch (config.operation) { | ||
case "PATCH": | ||
case "POST": | ||
axiosCommand.data = msg.payload; | ||
case "DELETE": | ||
axiosCommand.headers = { | ||
'ibm-mq-rest-csrf-token': msg.csrf ?? '', | ||
'Content-Type': config.contentType??"application/json" | ||
} | ||
break; | ||
case "GET": | ||
axiosCommand.headers = { | ||
'Accept': config.accept??'application/json' | ||
} | ||
break; | ||
default: | ||
break; | ||
} | ||
axiosCommand.headers['Accept'] = config.accept??'application/json'; | ||
axiosCommand = this.generateOptionalHeaders(msg, axiosCommand); | ||
return axiosCommand; | ||
} | ||
axiosRequest(axiosCommand){ | ||
return new Promise(function resolver(resolve, reject){ | ||
axios(axiosCommand) | ||
.then(function(response) { | ||
switch (response.status) { | ||
case 200: | ||
case 201: | ||
case 204: | ||
resolve(response.data); | ||
break; | ||
default: | ||
reject(response.status); | ||
break; | ||
} | ||
}) | ||
.catch(function (error) { | ||
if (error.response) { | ||
console.log(error.response.data); | ||
// console.log(error.response.status); | ||
// console.log(error.response.headers); | ||
} else if (error.request) { | ||
console.log(error.request); | ||
} else { | ||
console.log("Error", error.message); | ||
} | ||
reject(error); | ||
}); | ||
}); | ||
} | ||
} | ||
module.exports = MQRESTUtils; |
{ | ||
"name": "node-red-contrib-mqrest-client", | ||
"version": "0.0.2", | ||
"description": "MQI Clients", | ||
"version": "0.2.0", | ||
"description": "MQ REST Clients", | ||
"dependencies": { | ||
"request": "^2.85.0" | ||
"axios": "^0.26.1" | ||
}, | ||
@@ -22,2 +22,6 @@ "repository": { | ||
"email": "soheel_chughtai@uk.ibm.com" | ||
}, | ||
{ | ||
"name": "Hayden Banes", | ||
"email": "hayden.banes@ibm.com" | ||
} | ||
@@ -27,10 +31,20 @@ ], | ||
"nodes": { | ||
"mqi": "nodes/v1.js", | ||
"mqi-out": "nodes/v1-out.js", | ||
"mqi-config": "nodes/v1-config.js" | ||
"mqi-messaging": "nodes/mqrest-messaging.js", | ||
"mqi-channel": "nodes/mqrest-channel.js", | ||
"mqi-installation": "nodes/mqrest-installation.js", | ||
"mqi-usrconfig": "nodes/user-config.js", | ||
"mqi-login": "nodes/mqrest-login.js", | ||
"mqi-svrconfig": "nodes/server-config.js", | ||
"mqi-mftagent": "nodes/mft-agent.js", | ||
"mqi-transfer": "nodes/mft-transfer.js", | ||
"mqi-mft-monitor": "nodes/mft-monitor.js", | ||
"mqi-qmgr": "nodes/mqrest-qmgr.js", | ||
"mqi-mqsc": "nodes/qmgr-mqsc.js", | ||
"mqi-queue": "nodes/mqrest-queue.js", | ||
"mqi-sub": "nodes/mqrest-sub.js" | ||
} | ||
}, | ||
"engines": { | ||
"node": ">=8.0.0" | ||
"node": ">=14.0.0" | ||
} | ||
} |
@@ -10,11 +10,40 @@ # node-red-contrib-mqrest-client | ||
## Usage | ||
Two nodes are provided. The output node is used to post messages to a MQ queue. | ||
The function node is used to read with delete messages from a MQ queue. | ||
Fourteen nodes are provided. | ||
<dl> | ||
<dt>mqrest-channel</dt> | ||
<dd>retrieves channel information</dd> | ||
<dt>mqrest-installation</dt> | ||
<dd>retrieves installation information</dd> | ||
<dt>mqrest-login </dt> | ||
<dd> can be used to log in, log out and query a user</dd> | ||
<dt>mqrest-messaging</dt> | ||
<dd>provides messaging functionality (put, get, pub)</dd> | ||
<dt>mft-agent</dt> | ||
<dd>retrieves MFT agent details</dd> | ||
<dt>mft-monitor</dt> | ||
<dd>performs MFT monitor operations</dd> | ||
<dt>mft-transfer</dt> | ||
<dd>retrieves details of, and creates transfers</dd> | ||
<dt>mqrest-qmgr</dt> | ||
<dd>retrieves details of queue managers</dd> | ||
<dt>qmgr-mqsc</dt> | ||
<dd>runs an MQSC command</dd> | ||
<dt>mqrest-queue</dt> | ||
<dd>creates, deletes, modifies and retrieves details of a queue</dd> | ||
<dt>mqrest-sub</dt> | ||
<dd>retrieves details of subscriptions</dd> | ||
</dl> | ||
## Configuration | ||
Use the configuration to specify the full API URL. Which will look something like: | ||
Use the configuration to enter user and server details. Once created the user and server details can be reused with other mqrest nodes. | ||
https://<host>:<port>/ibmmq/rest/v1/messaging/qmgr/<queue manager>/queue/<queue>/message | ||
In user: | ||
<dl> | ||
<dt>username</dt> | ||
<dd>is the username of a user with authentication to use the REST API</dd> | ||
<dt>password</dt> | ||
<dd>the password for this user</dd> | ||
Where: | ||
In server: | ||
<dl> | ||
@@ -25,20 +54,9 @@ <dt>host</dt> | ||
<dd>is typically 9443</dd> | ||
<dt>queue manager</dt> | ||
<dd>may be something like `QM1`</dd> | ||
<dt>queue</dt> | ||
<dd>may be something like `DEV.QUEUE.1`</dd> | ||
</dl> | ||
resulting in | ||
https://localhost:9443/ibmmq/rest/v1/messaging/qmgr/QM1/queue/DEV.QUEUE.1/message | ||
### Input | ||
The output node expects the message to place on a queue to be in `msg.payload` and | ||
can be either a text string or a json object. | ||
Each node expects parameters via a `msg` object (e.g. the message to place on a queue to be in `msg.payload`). See the configuration panel of a node to see its expected parameters. | ||
### Output | ||
The function node performs a read with delete. If found the message is placed on | ||
`msg.payload`. If the message is a JSON object, then | ||
it is first converted into a JSON object before placing on `msg.payload` | ||
If a node can give an output, it will have a connector on the right. The output will almost always be the json string returned from MQ. | ||
@@ -51,2 +69,16 @@ ## Contributing | ||
Copyright 2018 IBM Corp. under the Apache 2.0 license. | ||
Copyright 2022 IBM Corp. under the Apache 2.0 license. | ||
## Example flows | ||
### Linking queue depth to a UI gauge | ||
` | ||
[{"id":"a341b09eb8c81942","type":"tab","label":"Flow 9","disabled":false,"info":"","env":[]},{"id":"7f7cae7a622b0f17","type":"ui_gauge","z":"a341b09eb8c81942","name":"","group":"68eb6cca3fbe9d5d","order":0,"width":0,"height":0,"gtype":"gage","title":"DEV.QUEUE.1 Queue Depth","label":"Messages","format":"{{msg.payload.currentDepth}}","min":0,"max":"5000","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","className":"","x":820,"y":640,"wires":[]},{"id":"1198a593d53e0ff9","type":"mqrest-queue","z":"a341b09eb8c81942","name":"","user":"8bb2a9c81bae9f00","server":"c813686f07868d8b","apiv":"v1","operation":"GET","x":390,"y":640,"wires":[["78cf75c68ef6505c"]]},{"id":"2ae88e3dd11cc21b","type":"inject","z":"a341b09eb8c81942","name":"","props":[{"p":"mqparams.qmgr","v":"QM1","vt":"str"},{"p":"mqparams.qname","v":"DEV.QUEUE.1","vt":"str"},{"p":"mqparams.status","v":"status.currentDepth","vt":"str"},{"p":"mqparams.attributes","v":"storage.maximumDepth","vt":"str"}],"repeat":"20","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":170,"y":640,"wires":[["1198a593d53e0ff9"]]},{"id":"78cf75c68ef6505c","type":"function","z":"a341b09eb8c81942","name":"","func":"msg.payload.currentDepth = msg.payload.queue[0].status.currentDepth;\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":640,"wires":[["7f7cae7a622b0f17"]]},{"id":"68eb6cca3fbe9d5d","type":"ui_group","name":"Default","tab":"440c82d8f94d11fb","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"8bb2a9c81bae9f00","type":"user-config","name":"ADMIN","username":"mqadmin","password":"mqadmin"},{"id":"c813686f07868d8b","type":"server-config","name":"","host":"localhost","port":"9443","allowSelfSigned":true},{"id":"440c82d8f94d11fb","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}] | ||
` | ||
### Sending QM status to twitter DM | ||
` | ||
[{"id":"c9634fa8db54069b","type":"tab","label":"Flow 11","disabled":false,"info":"","env":[]},{"id":"33966ca71ec197f6","type":"twitter out","z":"c9634fa8db54069b","twitter":"","name":"Tweet","x":690,"y":480,"wires":[]},{"id":"5fe8c2fa916dbbbb","type":"mqrest-qmgr","z":"c9634fa8db54069b","name":"","user":"8bb2a9c81bae9f00","server":"c813686f07868d8b","qmgr":null,"apiv":"v2","x":360,"y":480,"wires":[["9a30ad5ed87bef3c"]]},{"id":"d969950ceac03694","type":"inject","z":"c9634fa8db54069b","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":480,"wires":[["5fe8c2fa916dbbbb"]]},{"id":"9a30ad5ed87bef3c","type":"function","z":"c9634fa8db54069b","name":"","func":"console.log(msg.payload)\nmsg.payload = `D NodeREDTest10 Hello ${JSON.stringify(msg.payload)}`;\nnode.send(msg);","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":480,"wires":[["33966ca71ec197f6"]]},{"id":"8bb2a9c81bae9f00","type":"user-config","name":"ADMIN","username":"mqadmin","password":"mqadmin"},{"id":"c813686f07868d8b","type":"server-config","name":"","host":"localhost","port":"9443","allowSelfSigned":true}] | ||
` |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
100989
208.8%31
158.33%771
175.36%82
64%13
Infinity%+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed