mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Merge branch 'dev' into adding-timeout-to-functio-node
This commit is contained in:
		
							
								
								
									
										35
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,3 +1,38 @@ | ||||
| #### 3.1.0-beta.3: Beta Release | ||||
|  | ||||
| Editor | ||||
|  | ||||
|  - Select the item that is specified in a deep link URL (#4113) @Steve-Mcl | ||||
|  - Update to Monaco 0.38.0 (#4189) @Steve-Mcl | ||||
|  - Place subflow outputs/inputs relative to current view (#4183) @knolleary | ||||
|  - Enable RED.view.select to select group by id (#4184) @knolleary | ||||
|  - Combine existing env vars when merging groups (#4182) @knolleary | ||||
|  - Avoid creating empty global-config node if not needed (#4153) @knolleary | ||||
|  - Fix group selection when using lasso (#4108) @knolleary | ||||
|  - Use editor path in generating localStorage keys (#4151) @mw75 | ||||
|  - Ensure no node credentials are included when exporting to clipboard (#4112) @knolleary | ||||
|  - Fix jsonata expression test ui (#4097) @knolleary | ||||
|  - Fix search button in palette popover (#4096) @knolleary | ||||
|  | ||||
| Runtime | ||||
|  | ||||
|  - Allow options object on each httpStatic configuration (#4109) @kevinGodell | ||||
|  - Ensure non-zero exit codes for errors (#4181) @knolleary | ||||
|  - Ensure external modules are installed synchronously (#4180) @knolleary | ||||
|  - Update dependecies include got (#4155) @knolleary | ||||
|  - Add Japanese translations for v3.1 beta.2 (#4158) @kazuhitoyokoi | ||||
|  - Ensure express server options are applied consistently (#4178) @knolleary | ||||
|  - Remove version info from theme endpoint (#4179) @knolleary | ||||
|  - Add Japanese translations for welcome tour of 3.1.0 beta.2 (#4145) @kazuhitoyokoi | ||||
|  - Added SHA-256 and SHA-512-256 digest authentication (#4100) @sroebert | ||||
|  - Add "timers" types to known types (#4103) @Steve-Mcl | ||||
|  | ||||
| Nodes | ||||
|  | ||||
|  - Allow Catch/Status nodes to be scoped to their group (#4185) @NetHans | ||||
|  - MQTT: Option to disable MQTT topic unsubscribe on disconnect (#4078) @flying7eleven | ||||
|  | ||||
|  | ||||
| #### 3.1.0-beta.2: Beta Release | ||||
|  | ||||
| Editor | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "node-red", | ||||
|     "version": "3.1.0-beta.2", | ||||
|     "version": "3.1.0-beta.3", | ||||
|     "description": "Low-code programming for event-driven applications", | ||||
|     "homepage": "http://nodered.org", | ||||
|     "license": "Apache-2.0", | ||||
| @@ -79,7 +79,7 @@ | ||||
|         "uglify-js": "3.17.4", | ||||
|         "uuid": "9.0.0", | ||||
|         "ws": "7.5.6", | ||||
|         "xml2js": "0.5.0" | ||||
|         "xml2js": "0.6.0" | ||||
|     }, | ||||
|     "optionalDependencies": { | ||||
|         "bcrypt": "5.1.0" | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/editor-api", | ||||
|     "version": "3.1.0-beta.2", | ||||
|     "version": "3.1.0-beta.3", | ||||
|     "license": "Apache-2.0", | ||||
|     "main": "./lib/index.js", | ||||
|     "repository": { | ||||
| @@ -16,8 +16,8 @@ | ||||
|         } | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "@node-red/util": "3.1.0-beta.2", | ||||
|         "@node-red/editor-client": "3.1.0-beta.2", | ||||
|         "@node-red/util": "3.1.0-beta.3", | ||||
|         "@node-red/editor-client": "3.1.0-beta.3", | ||||
|         "bcryptjs": "2.4.3", | ||||
|         "body-parser": "1.20.2", | ||||
|         "clone": "2.1.2", | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/editor-client", | ||||
|     "version": "3.1.0-beta.2", | ||||
|     "version": "3.1.0-beta.3", | ||||
|     "license": "Apache-2.0", | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|   | ||||
| @@ -1168,19 +1168,19 @@ RED.editor.codeEditor.monaco = (function() { | ||||
|         // Warning: 4 | ||||
|         // Error: 8 | ||||
|         ed.getAnnotations = function getAnnotations() { | ||||
|             var aceCompatibleMarkers = []; | ||||
|             let aceCompatibleMarkers; | ||||
|             try { | ||||
|                 var _model = ed.getModel(); | ||||
|                 const _model = ed.getModel(); | ||||
|                 if (_model !== null) { | ||||
|                     var id = _model._languageId; // e.g. javascript | ||||
|                     var ra = _model._associatedResource.authority;  //e.g.  model | ||||
|                     var rp = _model._associatedResource.path;   //e.g.      /18 | ||||
|                     var rs = _model._associatedResource.scheme; //e.g.      inmemory | ||||
|                     var modelMarkers = monaco.editor.getModelMarkers(_model) || []; | ||||
|                     var thisEditorsMarkers = modelMarkers.filter(function (marker) { | ||||
|                         var _ra = marker.resource.authority;  //e.g.  model | ||||
|                         var _rp = marker.resource.path;   //e.g.      /18 | ||||
|                         var _rs = marker.resource.scheme; //e.g.      inmemory | ||||
|                     const id = _model.getLanguageId(); // e.g.  javascript | ||||
|                     const ra = _model.uri.authority; //   e.g.  model | ||||
|                     const rp = _model.uri.path; //        e.g.  /18 | ||||
|                     const rs = _model.uri.scheme; //      e.g.  inmemory | ||||
|                     const modelMarkers = monaco.editor.getModelMarkers(_model) || []; | ||||
|                     const thisEditorsMarkers = modelMarkers.filter(function (marker) { | ||||
|                         const _ra = marker.resource.authority; // e.g.  model | ||||
|                         const _rp = marker.resource.path; //      e.g.  /18 | ||||
|                         const _rs = marker.resource.scheme; //    e.g.  inmemory | ||||
|                         return marker.owner == id && _ra === ra && _rp === rp && _rs === rs; | ||||
|                     }) | ||||
|                     aceCompatibleMarkers = thisEditorsMarkers.map(function (marker) { | ||||
|   | ||||
| @@ -1,15 +1,15 @@ | ||||
| export default { | ||||
|     version: "3.1.0-beta.2", | ||||
|     version: "3.1.0-beta.3", | ||||
|     steps: [ | ||||
|         { | ||||
|             titleIcon: "fa fa-map-o", | ||||
|             title: { | ||||
|                 "en-US": "Welcome to Node-RED 3.1 Beta 2!", | ||||
|                 "ja": "Node-RED 3.1 ベータ2へようこそ!" | ||||
|                 "en-US": "Welcome to Node-RED 3.1 Beta 3!", | ||||
|                 "ja": "Node-RED 3.1 ベータ3へようこそ!" | ||||
|             }, | ||||
|             description: { | ||||
|                 "en-US": "<p>This is the second beta release for 3.1.0 and we have a few new features to tell you about.</p>", | ||||
|                 "ja": "<p>これは3.1.0の2回目のベータリリースです。いくつかの新機能について説明します。</p>" | ||||
|                 "en-US": "<p>This is the third beta release for 3.1.0. This is mostly a bug fix release, so you can skip this tour if you've tried the other betas.</p><p>If not, stick around to see what's new in Node-RED 3.1.</p>", | ||||
|                 "ja": "<p>これは3.1.0の3回目のベータリリースです。不具合修正のリリースのため、もし他のベータ版を試したことがある場合は、このツアーを読み飛ばしてもかまいません。</p><p>そうでない場合は、Node-RED 3.1の新機能を確認してください。</p>" | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|   | ||||
| @@ -219,8 +219,10 @@ module.exports = function(RED) { | ||||
|      * Handle the payload / packet recieved in MQTT In and MQTT Sub nodes | ||||
|      */ | ||||
|     function subscriptionHandler(node, datatype ,topic, payload, packet) { | ||||
|         const v5 = node.brokerConn.options && node.brokerConn.options.protocolVersion == 5; | ||||
|         var msg = {topic:topic, payload:null, qos:packet.qos, retain:packet.retain}; | ||||
|         const msg = {topic:topic, payload:null, qos:packet.qos, retain:packet.retain}; | ||||
|         const v5 = (node && node.brokerConn)  | ||||
|             ? node.brokerConn.v5()  | ||||
|             : Object.prototype.hasOwnProperty.call(packet, "properties"); | ||||
|         if(v5 && packet.properties) { | ||||
|             setStrProp(packet.properties, msg, "responseTopic"); | ||||
|             setBufferProp(packet.properties, msg, "correlationData"); | ||||
| @@ -300,7 +302,7 @@ module.exports = function(RED) { | ||||
|             //} | ||||
|         } | ||||
|         msg.payload = payload; | ||||
|         if ((node.brokerConn.broker === "localhost")||(node.brokerConn.broker === "127.0.0.1")) { | ||||
|         if (node.brokerConn && (node.brokerConn.broker === "localhost" || node.brokerConn.broker === "127.0.0.1")) { | ||||
|             msg._topic = topic; | ||||
|         } | ||||
|         node.send(msg); | ||||
| @@ -412,6 +414,12 @@ module.exports = function(RED) { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Perform the connect action | ||||
|      * @param {MQTTInNode|MQTTOutNode} node | ||||
|      * @param {Object} msg | ||||
|      * @param {Function} done | ||||
|      */ | ||||
|     function handleConnectAction(node, msg, done) { | ||||
|         let actionData = typeof msg.broker === 'object' ? msg.broker : null; | ||||
|         if (node.brokerConn.canConnect()) { | ||||
| @@ -442,12 +450,17 @@ module.exports = function(RED) { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Perform the disconnect action | ||||
|      * @param {MQTTInNode|MQTTOutNode} node  | ||||
|      * @param {Function} done | ||||
|      */ | ||||
|     function handleDisconnectAction(node, done) { | ||||
|         node.brokerConn.disconnect(function () { | ||||
|             done(); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     const unsubscribeCandidates = {} | ||||
|     //#endregion  "Supporting functions" | ||||
|  | ||||
|     //#region  "Broker node" | ||||
| @@ -591,10 +604,9 @@ module.exports = function(RED) { | ||||
|             if (typeof node.cleansession === 'undefined') { | ||||
|                 node.cleansession = true; | ||||
|             } | ||||
|             if (typeof node.autoUnsubscribe === 'undefined') { | ||||
|             if (typeof node.autoUnsubscribe !== 'boolean') { | ||||
|                 node.autoUnsubscribe = true; | ||||
|             } | ||||
|  | ||||
|             //use url or build a url from usetls://broker:port | ||||
|             if (node.url && node.brokerurl !== node.url) { | ||||
|                 node.brokerurl = node.url; | ||||
| @@ -664,7 +676,6 @@ module.exports = function(RED) { | ||||
|             node.options.password = node.password; | ||||
|             node.options.keepalive = node.keepalive; | ||||
|             node.options.clean = node.cleansession; | ||||
|             node.options.autoUnsubscribe = node.autoUnsubscribe; | ||||
|             node.options.clientId = node.clientid || 'nodered_' + RED.util.generateId(); | ||||
|             node.options.reconnectPeriod = RED.settings.mqttReconnectTime||5000; | ||||
|             delete node.options.protocolId; //V4+ default | ||||
| @@ -785,18 +796,11 @@ module.exports = function(RED) { | ||||
|                         // Re-subscribe to stored topics | ||||
|                         for (var s in node.subscriptions) { | ||||
|                             if (node.subscriptions.hasOwnProperty(s)) { | ||||
|                                 let topic = s; | ||||
|                                 let qos = 0; | ||||
|                                 let _options = {}; | ||||
|                                 for (var r in node.subscriptions[s]) { | ||||
|                                     if (node.subscriptions[s].hasOwnProperty(r)) { | ||||
|                                         qos = Math.max(qos,node.subscriptions[s][r].qos); | ||||
|                                         _options = node.subscriptions[s][r].options; | ||||
|                                         node._clientOn('message',node.subscriptions[s][r].handler); | ||||
|                                         node.subscribe(node.subscriptions[s][r]) | ||||
|                                     } | ||||
|                                 } | ||||
|                                 _options.qos = _options.qos || qos; | ||||
|                                 node.client.subscribe(topic, _options); | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
| @@ -858,22 +862,28 @@ module.exports = function(RED) { | ||||
|             if(!node.client) { return _callback(); } | ||||
|             if(node.closing) { return _callback(); } | ||||
|  | ||||
|             /** | ||||
|              * Call end and wait for the client to end (or timeout) | ||||
|              * @param {mqtt.MqttClient} client The broker client | ||||
|              * @param {number} ms The time to wait for the client to end | ||||
|              * @returns  | ||||
|              */ | ||||
|             let waitEnd = (client, ms) => { | ||||
|                 return new Promise( (resolve, reject) => { | ||||
|                     node.closing = true; | ||||
|                     if(!client) { | ||||
|                     if (!client) { | ||||
|                         resolve(); | ||||
|                      } else { | ||||
|                     } else { | ||||
|                         const t = setTimeout(() => { | ||||
|                             //clean end() has exceeded WAIT_END, lets force end! | ||||
|                             client && client.end(true); | ||||
|                             reject(); | ||||
|                             resolve(); | ||||
|                         }, ms); | ||||
|                         client.end(() => { | ||||
|                              clearTimeout(t); | ||||
|                              resolve() | ||||
|                          }); | ||||
|                      } | ||||
|                             clearTimeout(t); | ||||
|                             resolve() | ||||
|                         }); | ||||
|                     } | ||||
|                 }); | ||||
|             }; | ||||
|             if(node.connected && node.closeMessage) { | ||||
| @@ -894,69 +904,222 @@ module.exports = function(RED) { | ||||
|         } | ||||
|         node.subscriptionIds = {}; | ||||
|         node.subid = 1; | ||||
|         node.subscribe = function (topic,options,callback,ref) { | ||||
|             ref = ref||0; | ||||
|             var qos; | ||||
|             if(typeof options == "object") { | ||||
|                 qos = options.qos; | ||||
|             } else { | ||||
|                 qos = options; | ||||
|                 options = {}; | ||||
|  | ||||
|         //typedef for subscription object: | ||||
|         /**  | ||||
|          * @typedef {Object} Subscription | ||||
|          * @property {String} topic - topic to subscribe to | ||||
|          * @property {Object} [options] - options object | ||||
|          * @property {Number} [options.qos] - quality of service | ||||
|          * @property {Number} [options.nl] - no local | ||||
|          * @property {Number} [options.rap] - retain as published | ||||
|          * @property {Number} [options.rh] - retain handling | ||||
|          * @property {Number} [options.properties] - MQTT 5.0 properties | ||||
|          * @property {Number} [options.properties.subscriptionIdentifier] - MQTT 5.0 subscription identifier | ||||
|          * @property {Number} [options.properties.userProperties] - MQTT 5.0 user properties | ||||
|          * @property {Function} callback | ||||
|          * @property {String} ref - reference to the node that created the subscription | ||||
|          */ | ||||
|  | ||||
|         /** | ||||
|          * Create a subscription object | ||||
|          * @param {String} _topic - topic to subscribe to | ||||
|          * @param {Object} _options - options object | ||||
|          * @param {String} _ref - reference to the node that created the subscription | ||||
|          * @returns {Subscription} | ||||
|          */ | ||||
|         function createSubscriptionObject(_topic, _options, _ref, _brokerId) { | ||||
|             /** @type {Subscription} */ | ||||
|             const subscription = {}; | ||||
|             const ref = _ref || 0; | ||||
|             let options | ||||
|             let qos = 1 // default to QoS 1 (AWS and several other brokers don't support QoS 2) | ||||
|              | ||||
|             // if options is an object, then clone it | ||||
|             if (typeof _options == "object") { | ||||
|                 options = RED.util.cloneMessage(_options || {}) | ||||
|                 qos = _options.qos; | ||||
|             } else if (typeof _options == "number") { | ||||
|                 qos = _options; | ||||
|             } | ||||
|             options.qos = qos; | ||||
|             options = options || {}; | ||||
|  | ||||
|             // sanitise qos | ||||
|             if (typeof qos === "number" && qos >= 0 && qos <= 2) { | ||||
|                 options.qos = qos; | ||||
|             } | ||||
|              | ||||
|             subscription.topic = _topic; | ||||
|             subscription.qos = qos; | ||||
|             subscription.options = RED.util.cloneMessage(options); | ||||
|             subscription.ref = ref; | ||||
|             subscription.brokerId = _brokerId; | ||||
|             return subscription; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * If topic is a subscription object, then use that, otherwise look up the topic in  | ||||
|          * the  subscriptions object.  If the topic is not found, then create a new subscription | ||||
|          * object and add it to the subscriptions object. | ||||
|          * @param {Subscription|String} topic  | ||||
|          * @param {*} options  | ||||
|          * @param {*} callback  | ||||
|          * @param {*} ref  | ||||
|          */ | ||||
|         node.subscribe = function (topic, options, callback, ref) { | ||||
|             /** @type {Subscription} */  | ||||
|             let subscription | ||||
|             let doCompare = false | ||||
|             let changesFound = false | ||||
|  | ||||
|             // function signature 1: subscribe(subscription: Subscription) | ||||
|             if (typeof topic === "object" && topic !== null) { | ||||
|                 subscription = topic | ||||
|                 topic = subscription.topic | ||||
|                 options = subscription.options | ||||
|                 ref = subscription.ref | ||||
|                 callback = subscription.callback | ||||
|             } | ||||
|  | ||||
|             // function signature 2: subscribe(topic: String, options: Object, callback: Function, ref: String) | ||||
|             else if (typeof topic === "string") { | ||||
|                 // since this is a call where all params are provided, it might be | ||||
|                 // a node change (modification) so we need to check for changes | ||||
|                 doCompare = true | ||||
|                 subscription = node.subscriptions[topic] && node.subscriptions[topic][ref] | ||||
|             } | ||||
|  | ||||
|             // bad function call | ||||
|             else { | ||||
|                 console.warn('Invalid call to node.subscribe') | ||||
|                 return | ||||
|             } | ||||
|             const thisBrokerId = node.type === 'mqtt-broker' ? node.id : node.broker | ||||
|  | ||||
|             // unsubscribe topics where the broker has changed | ||||
|             const oldBrokerSubs = (unsubscribeCandidates[ref] || []).filter(sub => sub.brokerId !== thisBrokerId) | ||||
|             oldBrokerSubs.forEach(sub => { | ||||
|                 /** @type {MQTTBrokerNode} */ | ||||
|                 const _brokerConn = RED.nodes.getNode(sub.brokerId) | ||||
|                 if (_brokerConn) { | ||||
|                     _brokerConn.unsubscribe(sub.topic, sub.ref, true) | ||||
|                 } | ||||
|             }) | ||||
|              | ||||
|             // if subscription is found (or sent in as a parameter), then check for changes. | ||||
|             // if there are any changes requested, tidy up the old subscription | ||||
|             if (subscription) { | ||||
|                 if (doCompare) { | ||||
|                     // compare the current sub to the passed in parameters. Use RED.util.compareObjects against | ||||
|                     // only the minimal set of properties to identify if the subscription has changed | ||||
|                     const currentSubscription = createSubscriptionObject(subscription.topic, subscription.options, subscription.ref) | ||||
|                     const newSubscription = createSubscriptionObject(topic, options, ref) | ||||
|                     changesFound = RED.util.compareObjects(currentSubscription, newSubscription) === false | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (changesFound) { | ||||
|                 if (subscription.handler) { | ||||
|                     node._clientRemoveListeners('message', subscription.handler) | ||||
|                     subscription.handler = null | ||||
|                 } | ||||
|                 const _brokerConn = RED.nodes.getNode(subscription.brokerId) | ||||
|                 if (_brokerConn) { | ||||
|                     _brokerConn.unsubscribe(subscription.topic, subscription.ref, true) | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // clean up the unsubscribe candidate list | ||||
|             delete unsubscribeCandidates[ref] | ||||
|  | ||||
|             // determine if this is an existing subscription | ||||
|             const existingSubscription = typeof subscription === "object" && subscription !== null | ||||
|  | ||||
|             // if existing subscription is not found or has changed, create a new subscription object | ||||
|             if (existingSubscription === false || changesFound) { | ||||
|                 subscription = createSubscriptionObject(topic, options, ref, node.id) | ||||
|             } | ||||
|  | ||||
|             // setup remainder of subscription properties and event handling | ||||
|             node.subscriptions[topic] = node.subscriptions[topic] || {}; | ||||
|             node.subscriptions[topic][ref] = subscription | ||||
|             if (!node.subscriptionIds[topic]) { | ||||
|                 node.subscriptionIds[topic] = node.subid++; | ||||
|             } | ||||
|             options.properties = options.properties || {}; | ||||
|             options.properties.subscriptionIdentifier = node.subscriptionIds[topic]; | ||||
|             subscription.options = subscription.options || {}; | ||||
|             subscription.options.properties = options.properties || {}; | ||||
|             subscription.options.properties.subscriptionIdentifier = node.subscriptionIds[topic]; | ||||
|             subscription.callback = callback; | ||||
|  | ||||
|             node.subscriptions[topic] = node.subscriptions[topic]||{}; | ||||
|             var sub = { | ||||
|                 topic:topic, | ||||
|                 qos:qos, | ||||
|                 options:options, | ||||
|                 handler:function(mtopic,mpayload, mpacket) { | ||||
|                     if(mpacket.properties && options.properties && mpacket.properties.subscriptionIdentifier && options.properties.subscriptionIdentifier && (mpacket.properties.subscriptionIdentifier !== options.properties.subscriptionIdentifier) ) { | ||||
|                         //do nothing as subscriptionIdentifier does not match | ||||
|                     } else if (matchTopic(topic,mtopic)) { | ||||
|                         callback(mtopic,mpayload, mpacket); | ||||
|                     } | ||||
|                 }, | ||||
|                 ref: ref | ||||
|             }; | ||||
|             node.subscriptions[topic][ref] = sub; | ||||
|             // if the client is connected, then setup the handler and subscribe | ||||
|             if (node.connected) { | ||||
|                 const subIdsAvailable = node.subscriptionIdentifiersAvailable() | ||||
|                 node._clientOn('message',sub.handler); | ||||
|                 // if the broker doesn't support subscription identifiers (e.g. AWS core), then don't send them | ||||
|                 if (options.properties && options.properties.subscriptionIdentifier && subIdsAvailable !== true) { | ||||
|                     delete options.properties.subscriptionIdentifier | ||||
|                 } | ||||
|                 node.client.subscribe(topic, options); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         node.unsubscribe = function (topic, ref, removed) { | ||||
|             ref = ref||0; | ||||
|             var sub = node.subscriptions[topic]; | ||||
|             if (sub) { | ||||
|                 if (sub[ref]) { | ||||
|                     if(node.client) { | ||||
|                         node._clientRemoveListeners('message',sub[ref].handler); | ||||
|                     } | ||||
|                     delete sub[ref]; | ||||
|                 } | ||||
|                 //TODO: Review. The `if(removed)` was commented out to always delete and remove subscriptions. | ||||
|                 // if we dont then property changes dont get applied and old subs still trigger | ||||
|                 //if (removed) { | ||||
|                     if (Object.keys(sub).length === 0) { | ||||
|                         delete node.subscriptions[topic]; | ||||
|                         delete node.subscriptionIds[topic]; | ||||
|                         if (node.connected) { | ||||
|                             node.client.unsubscribe(topic); | ||||
|                 if (!subscription.handler) { | ||||
|                     subscription.handler = function (mtopic, mpayload, mpacket) { | ||||
|                         const sops = subscription.options ? subscription.options.properties : {} | ||||
|                         const pops = mpacket.properties || {} | ||||
|                         if (subIdsAvailable && pops.subscriptionIdentifier && sops.subscriptionIdentifier && (pops.subscriptionIdentifier !== sops.subscriptionIdentifier)) { | ||||
|                             //do nothing as subscriptionIdentifier does not match | ||||
|                         } else if (matchTopic(topic, mtopic)) { | ||||
|                             subscription.callback && subscription.callback(mtopic, mpayload, mpacket) | ||||
|                         } | ||||
|                     } | ||||
|                 //} | ||||
|                 } | ||||
|                 node._clientOn('message', subscription.handler) | ||||
|                 // if the broker doesn't support subscription identifiers, then don't send them (AWS support) | ||||
|                 if (subscription.options.properties && subscription.options.properties.subscriptionIdentifier && subIdsAvailable !== true) { | ||||
|                     delete subscription.options.properties.subscriptionIdentifier | ||||
|                 } | ||||
|                 node.client.subscribe(topic, subscription.options) | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|         node.unsubscribe = function (topic, ref, removeClientSubscription) { | ||||
|             ref = ref||0; | ||||
|             const unsub = removeClientSubscription || node.autoUnsubscribe !== false | ||||
|             const sub = node.subscriptions[topic]; | ||||
|             let brokerId = node.id | ||||
|             if (sub) { | ||||
|                 if (sub[ref]) { | ||||
|                     brokerId = sub[ref].brokerId || brokerId | ||||
|                     if(node.client && sub[ref].handler) { | ||||
|                         node._clientRemoveListeners('message', sub[ref].handler); | ||||
|                         sub[ref].handler = null | ||||
|                     } | ||||
|                     if (unsub) { | ||||
|                         delete sub[ref] | ||||
|                     } | ||||
|                 } | ||||
|                 // if instructed to remove the actual MQTT client subscription  | ||||
|                 if (unsub) { | ||||
|                     // if there are no more subscriptions for the topic, then remove the topic | ||||
|                     if (Object.keys(sub).length === 0) { | ||||
|                         try { | ||||
|                             node.client.unsubscribe(topic) | ||||
|                         } catch (_err) { | ||||
|                             // do nothing | ||||
|                         } finally { | ||||
|                             // remove unsubscribe candidate as it is now REALLY unsubscribed | ||||
|                             delete node.subscriptions[topic]; | ||||
|                             delete node.subscriptionIds[topic]; | ||||
|                             if (unsubscribeCandidates[ref]) { | ||||
|                                 unsubscribeCandidates[ref] = unsubscribeCandidates[ref].filter(sub => sub.topic !== topic) | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|                     // if instructed to not remove the client subscription, then add it to the candidate list | ||||
|                     // of subscriptions to be removed when the the same ref is used in a subsequent subscribe | ||||
|                     // and the topic has changed | ||||
|                     unsubscribeCandidates[ref] = unsubscribeCandidates[ref] || []; | ||||
|                     unsubscribeCandidates[ref].push({ | ||||
|                         topic: topic, | ||||
|                         ref: ref, | ||||
|                         brokerId: brokerId | ||||
|                     }) | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
|         node.topicAliases = {}; | ||||
| @@ -994,7 +1157,7 @@ module.exports = function(RED) { | ||||
|                     setStrProp(msg, options.properties, "contentType"); | ||||
|                     setIntProp(msg, options.properties, "messageExpiryInterval", 0); | ||||
|                     setUserProperties(msg.userProperties, options.properties); | ||||
|                     setIntProp(msg, options.properties, "topicAlias", 1, node.serverProperties.topicAliasMaximum || 0); | ||||
|                     setIntProp(msg, options.properties, "topicAlias", 1, bsp.topicAliasMaximum || 0); | ||||
|                     setBoolProp(msg, options.properties, "payloadFormatIndicator"); | ||||
|                     //FUTURE setIntProp(msg, options.properties, "subscriptionIdentifier", 1, 268435455); | ||||
|  | ||||
| @@ -1130,7 +1293,7 @@ module.exports = function(RED) { | ||||
|                         if(node.rap === "true" || node.rap === true) options.rap = true; | ||||
|                         else if(node.rap === "false" || node.rap === false) options.rap = false; | ||||
|                     } | ||||
|  | ||||
|                     node._topic = node.topic; // store the original topic incase node is later changed | ||||
|                     node.brokerConn.subscribe(node.topic,options,function(topic, payload, packet) { | ||||
|                         subscriptionHandler(node, node.datatype, topic, payload, packet); | ||||
|                     },node.id); | ||||
| @@ -1183,7 +1346,7 @@ module.exports = function(RED) { | ||||
|                     } | ||||
|                     if (action === Actions.UNSUBSCRIBE) { | ||||
|                         subscriptions.forEach(function (sub) { | ||||
|                             node.brokerConn.unsubscribe(sub.topic, node.id); | ||||
|                             node.brokerConn.unsubscribe(sub.topic, node.id, true); | ||||
|                             delete node.dynamicSubs[sub.topic]; | ||||
|                         }) | ||||
|                         //user can access current subscriptions through the complete node is so desired | ||||
| @@ -1193,7 +1356,7 @@ module.exports = function(RED) { | ||||
|                         subscriptions.forEach(function (sub) { | ||||
|                             //always unsubscribe before subscribe to prevent multiple subs to same topic | ||||
|                             if (node.dynamicSubs[sub.topic]) { | ||||
|                                 node.brokerConn.unsubscribe(sub.topic, node.id); | ||||
|                                 node.brokerConn.unsubscribe(sub.topic, node.id, true); | ||||
|                                 delete node.dynamicSubs[sub.topic]; | ||||
|                             } | ||||
|  | ||||
| @@ -1239,16 +1402,12 @@ module.exports = function(RED) { | ||||
|             node.on('close', function(removed, done) { | ||||
|                 if (node.brokerConn) { | ||||
|                     if(node.isDynamic) { | ||||
|                         if (node.brokerConn.options.autoUnsubscribe) { | ||||
|                             Object.keys(node.dynamicSubs).forEach(function (topic) { | ||||
|                                 node.brokerConn.unsubscribe(topic, node.id, removed); | ||||
|                             }); | ||||
|                             node.dynamicSubs = {}; | ||||
|                         } | ||||
|                         Object.keys(node.dynamicSubs).forEach(function (topic) { | ||||
|                             node.brokerConn.unsubscribe(topic, node.id, removed); | ||||
|                         }); | ||||
|                         node.dynamicSubs = {}; | ||||
|                     } else { | ||||
|                         if (node.brokerConn.options.autoUnsubscribe) { | ||||
|                             node.brokerConn.unsubscribe(node.topic, node.id, removed); | ||||
|                         } | ||||
|                         node.brokerConn.unsubscribe(node.topic, node.id, removed); | ||||
|                     } | ||||
|                     node.brokerConn.deregister(node, done, removed); | ||||
|                     node.brokerConn = null; | ||||
|   | ||||
| @@ -33,14 +33,7 @@ module.exports = function(RED) { | ||||
|                     parseString(value, options, function (err, result) { | ||||
|                         if (err) { done(err); } | ||||
|                         else { | ||||
|                             // TODO: With xml2js@0.5.0, they return an object with | ||||
|                             //       a null prototype. This could cause unexpected | ||||
|                             //       issues. So for now, we have to reconstruct | ||||
|                             //       the object with a proper prototype. | ||||
|                             // Once https://github.com/Leonidas-from-XIV/node-xml2js/pull/674 | ||||
|                             // is merged, we can revisit and hopefully remove this hack | ||||
|                             value = fixObj(result) | ||||
|                             RED.util.setMessageProperty(msg,node.property,value); | ||||
|                             RED.util.setMessageProperty(msg,node.property,result); | ||||
|                             send(msg); | ||||
|                             done(); | ||||
|                         } | ||||
| @@ -52,18 +45,4 @@ module.exports = function(RED) { | ||||
|         }); | ||||
|     } | ||||
|     RED.nodes.registerType("xml",XMLNode); | ||||
|  | ||||
|  | ||||
|     function fixObj(obj) { | ||||
|         const res = {} | ||||
|         const keys = Object.keys(obj) | ||||
|         keys.forEach(k => { | ||||
|             if (typeof obj[k] === 'object' && obj[k]) { | ||||
|                 res[k] = fixObj(obj[k]) | ||||
|             } else { | ||||
|                 res[k] = obj[k] | ||||
|             } | ||||
|         }) | ||||
|         return res | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/nodes", | ||||
|     "version": "3.1.0-beta.2", | ||||
|     "version": "3.1.0-beta.3", | ||||
|     "license": "Apache-2.0", | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
| @@ -44,7 +44,7 @@ | ||||
|         "tough-cookie": "4.1.2", | ||||
|         "uuid": "9.0.0", | ||||
|         "ws": "7.5.6", | ||||
|         "xml2js": "0.5.0", | ||||
|         "xml2js": "0.6.0", | ||||
|         "iconv-lite": "0.6.3" | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/registry", | ||||
|     "version": "3.1.0-beta.2", | ||||
|     "version": "3.1.0-beta.3", | ||||
|     "license": "Apache-2.0", | ||||
|     "main": "./lib/index.js", | ||||
|     "repository": { | ||||
| @@ -16,7 +16,7 @@ | ||||
|         } | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "@node-red/util": "3.1.0-beta.2", | ||||
|         "@node-red/util": "3.1.0-beta.3", | ||||
|         "clone": "2.1.2", | ||||
|         "fs-extra": "11.1.1", | ||||
|         "semver": "7.5.0", | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/runtime", | ||||
|     "version": "3.1.0-beta.2", | ||||
|     "version": "3.1.0-beta.3", | ||||
|     "license": "Apache-2.0", | ||||
|     "main": "./lib/index.js", | ||||
|     "repository": { | ||||
| @@ -16,8 +16,8 @@ | ||||
|         } | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "@node-red/registry": "3.1.0-beta.2", | ||||
|         "@node-red/util": "3.1.0-beta.2", | ||||
|         "@node-red/registry": "3.1.0-beta.3", | ||||
|         "@node-red/util": "3.1.0-beta.3", | ||||
|         "async-mutex": "0.4.0", | ||||
|         "clone": "2.1.2", | ||||
|         "express": "4.18.2", | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/util", | ||||
|     "version": "3.1.0-beta.2", | ||||
|     "version": "3.1.0-beta.3", | ||||
|     "license": "Apache-2.0", | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|   | ||||
							
								
								
									
										10
									
								
								packages/node_modules/node-red/package.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								packages/node_modules/node-red/package.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "node-red", | ||||
|     "version": "3.1.0-beta.2", | ||||
|     "version": "3.1.0-beta.3", | ||||
|     "description": "Low-code programming for event-driven applications", | ||||
|     "homepage": "http://nodered.org", | ||||
|     "license": "Apache-2.0", | ||||
| @@ -31,10 +31,10 @@ | ||||
|         "flow" | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "@node-red/editor-api": "3.1.0-beta.2", | ||||
|         "@node-red/runtime": "3.1.0-beta.2", | ||||
|         "@node-red/util": "3.1.0-beta.2", | ||||
|         "@node-red/nodes": "3.1.0-beta.2", | ||||
|         "@node-red/editor-api": "3.1.0-beta.3", | ||||
|         "@node-red/runtime": "3.1.0-beta.3", | ||||
|         "@node-red/util": "3.1.0-beta.3", | ||||
|         "@node-red/nodes": "3.1.0-beta.3", | ||||
|         "basic-auth": "2.0.1", | ||||
|         "bcryptjs": "2.4.3", | ||||
|         "express": "4.18.2", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user