diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js b/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js index 7319b6aac..cbe7f5c3a 100644 --- a/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js +++ b/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js @@ -20,38 +20,42 @@ var typeRegistry = require("@node-red/registry"); var Log; var redUtil = require("@node-red/util").util; var flowUtil = require("./util"); -var Node; var nodeCloseTimeout = 15000; -function Flow(global,flow) { - if (typeof flow === 'undefined') { - flow = global; +class Flow { + constructor(global,flow) { + this.global = global; + if (typeof flow === 'undefined') { + this.flow = global; + } else { + this.flow = flow; + } + this.activeNodes = {}; + this.subflowInstanceNodes = {}; + this.catchNodeMap = {}; + this.statusNodeMap = {}; } - var activeNodes = {}; - var subflowInstanceNodes = {}; - var catchNodeMap = {}; - var statusNodeMap = {}; - this.start = function(diff) { + start(diff) { var node; var newNode; var id; - catchNodeMap = {}; - statusNodeMap = {}; + this.catchNodeMap = {}; + this.statusNodeMap = {}; - var configNodes = Object.keys(flow.configs); + var configNodes = Object.keys(this.flow.configs); var configNodeAttempts = {}; while (configNodes.length > 0) { id = configNodes.shift(); - node = flow.configs[id]; - if (!activeNodes[id]) { + node = this.flow.configs[id]; + if (!this.activeNodes[id]) { var readyToCreate = true; // This node doesn't exist. // Check it doesn't reference another non-existent config node for (var prop in node) { - if (node.hasOwnProperty(prop) && prop !== 'id' && prop !== 'wires' && prop !== '_users' && flow.configs[node[prop]]) { - if (!activeNodes[node[prop]]) { + if (node.hasOwnProperty(prop) && prop !== 'id' && prop !== 'wires' && prop !== '_users' && this.flow.configs[node[prop]]) { + if (!this.activeNodes[node[prop]]) { // References a non-existent config node // Add it to the back of the list to try again later configNodes.push(id); @@ -67,7 +71,7 @@ function Flow(global,flow) { if (readyToCreate) { newNode = createNode(node.type,node); if (newNode) { - activeNodes[id] = newNode; + this.activeNodes[id] = newNode; } } } @@ -75,31 +79,32 @@ function Flow(global,flow) { if (diff && diff.rewired) { for (var j=0;j { var i; if (stopList) { for (i=0;i { + // Once stopped, allow context to remove anything no longer needed + return context.clean(activeFlowConfig) + }).then(() => { + // Start the active flows + start(type,diff,muteLog).then(() => { + events.emit("runtime-event",{id:"runtime-deploy",payload:{revision:flowRevision},retain: true}); }); - }).catch(function(err) { - }) + // Return the new revision asynchronously to the actual start + return flowRevision; + }).catch(function(err) { }) } else { events.emit("runtime-event",{id:"runtime-deploy",payload:{revision:flowRevision},retain: true}); } @@ -273,10 +287,10 @@ function handleStatus(node,statusMessage) { function start(type,diff,muteLog) { - //dumpActiveNodes(); type = type||"full"; started = true; var i; + // If there are missing types, report them, emit the necessary runtime event and return if (activeFlowConfig.missingTypes.length > 0) { log.info(log._("nodes.flows.missing-types")); var knownUnknowns = 0; @@ -297,8 +311,10 @@ function start(type,diff,muteLog) { log.info(" "+settings.userDir); } events.emit("runtime-event",{id:"runtime-state",payload:{error:"missing-types", type:"warning",text:"notification.warnings.missing-types",types:activeFlowConfig.missingTypes},retain:true}); - return when.resolve(); + return Promise.resolve(); } + + // In safe mode, don't actually start anything, emit the necessary runtime event and return if (settings.safeMode) { log.info("*****************************************************************") log.info(log._("nodes.flows.safe-mode")); @@ -306,6 +322,7 @@ function start(type,diff,muteLog) { events.emit("runtime-event",{id:"runtime-state",payload:{error:"safe-mode", type:"warning",text:"notification.warnings.safe-mode"},retain:true}); return Promise.resolve(); } + if (!muteLog) { if (type !== "full") { log.info(log._("nodes.flows.starting-modified-"+type)); @@ -313,15 +330,22 @@ function start(type,diff,muteLog) { log.info(log._("nodes.flows.starting-flows")); } } + var id; if (type === "full") { + // A full start means everything should + + // Check the 'global' flow is running if (!activeFlows['global']) { log.debug("red/nodes/flows.start : starting flow : global"); activeFlows['global'] = Flow.create(activeFlowConfig); } + + // Check each flow in the active configuration for (id in activeFlowConfig.flows) { if (activeFlowConfig.flows.hasOwnProperty(id)) { if (!activeFlowConfig.flows[id].disabled && !activeFlows[id]) { + // This flow is not disabled, nor is it currently active, so create it activeFlows[id] = Flow.create(activeFlowConfig,activeFlowConfig.flows[id]); log.debug("red/nodes/flows.start : starting flow : "+id); } else { @@ -330,13 +354,18 @@ function start(type,diff,muteLog) { } } } else { + // A modified-type deploy means restarting things that have changed + + // Update the global flow activeFlows['global'].update(activeFlowConfig,activeFlowConfig); for (id in activeFlowConfig.flows) { if (activeFlowConfig.flows.hasOwnProperty(id)) { if (!activeFlowConfig.flows[id].disabled) { if (activeFlows[id]) { + // This flow exists and is not disabled, so update it activeFlows[id].update(activeFlowConfig,activeFlowConfig.flows[id]); } else { + // This flow didn't previously exist, so create it activeFlows[id] = Flow.create(activeFlowConfig,activeFlowConfig.flows[id]); log.debug("red/nodes/flows.start : starting flow : "+id); } @@ -347,9 +376,12 @@ function start(type,diff,muteLog) { } } + // Having created or updated all flows, now start them. for (id in activeFlows) { if (activeFlows.hasOwnProperty(id)) { activeFlows[id].start(diff); + + // Create a map of node id to flow id and also a subflowInstance lookup map var activeNodes = activeFlows[id].getActiveNodes(); Object.keys(activeNodes).forEach(function(nid) { activeNodesToFlow[nid] = id; @@ -376,7 +408,7 @@ function start(type,diff,muteLog) { log.info(log._("nodes.flows.started-flows")); } } - return when.resolve(); + return Promise.resolve(); } function stop(type,diff,muteLog) {