diff --git a/.checksums b/.checksums index 0a60959..45c4007 100644 --- a/.checksums +++ b/.checksums @@ -1,5 +1,5 @@ { - "src\\editor\\event-out\\main.html": "6bad9c420154d8b311906a169602d29d19d9ef81", + "src\\editor\\event-out\\main.html": "ddd0b0d8312e59fcc8e0b156815ef2d1124acfc9", "src\\editor\\event-in\\main.html": "5775c74f0586c430d691c3f8ffc5145c744eb1dc", "src\\editor\\event-return\\main.html": "bcd175ed92a1d8f460a138d2eab2fc94597f43c3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a064040..705d1a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## 1.1.3 - Bug Fix (2021-09-27) + +### Changed + +* Change return node so that topic setting doesn't override the msg.topic. The topic setting in the node will now only be used if the inbound msg has no topic. + +### Fixed + +* [A nested loops issue](https://discourse.nodered.org/t/new-node-node-red-contrib-events-alternative-to-link-nodes/51028/35). + + `msg._eventOriginator` and `msg._eventReturner` are now both arrays with the latest entries at the top. This enables multi-level out and return. + + Infinite loops should no longer be possible unless you deliberately mess with these properties (hint: don't!). + ## 1.1.2 - Improvements & new event-return node (2021-09-26) ### New diff --git a/README.md b/README.md index 76adab8..6ff86b8 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ This allows you to create sub-flows (sub-routines) and loops very easily. * A separate event handler is needed because the Node-RED core devs want to make sure that Node-RED's own event handlers are not used by contributed nodes. These nodes use a separate event handler module that is shared with other nodes from me including node-red-contrib-uibuilder. That means that these nodes will (in the future) interact with uibuilder where needed but are not dependent. + Other nodes could also use the same library. Whichever nodes use the library, they will all get the same event handler. * The `/` char in the topic is used as a level (namespace) separator in the same way as with MQTT. * Can use either glob-style (`*`, `**`) or MQTT-style (`+`, `#`) wildcards. * The package contains some example flows. Access using the Import examples library in Node-RED. @@ -49,7 +50,8 @@ However, if you wish, you can: * Allow the received msg to be passed through to the output. * Allow the use of an `event-return` node so that sub-subflows (sub-routines) or loops can be created. -The node adds a `msg._eventOriginator` property that records the `event-out` node ID that is originating the msg. This helps with debugging and tracing of data flows. +The node adds a `msg._eventOriginator` array property that records the `event-out` node ID that is originating the msg. This helps with debugging and tracing of data flows. +If a series of `event.out` nodes are used, each will add an ID to top of the array so that you can see the full path taken and so that the `event-return` nodes can navigate back up the tree. The input topic is sanity checked: it must be a string and no more than 255 chars. It should not contain `*`, `#` or `+` @@ -74,6 +76,7 @@ Then create a flow starting with an `event-in` node, do some processing and end The `event-return` node does not need any configuration, it uses the `msg._eventOriginator` property from the input msg to route data back to the originating `event-out` using an internal event sender/listener based on the node ID of the `event-out` node. +In the process, it adds to top of an array `msg._eventReturner` with the ID of the return node so that you can trace backwards if needed. You can, however, allow the node to pass messages through to an output if you want to. @@ -92,4 +95,8 @@ You can also override the msg.topic for the output if you wish. ## Change Log -See the [CHANGELOG](./CHANGELOG.md) file for details. \ No newline at end of file +See the [CHANGELOG](./CHANGELOG.md) file for details. + +## To Do + +* Allow though AND return \ No newline at end of file diff --git a/examples/double-depth-test-return.json b/examples/double-depth-test-return.json new file mode 100644 index 0000000..e46d103 --- /dev/null +++ b/examples/double-depth-test-return.json @@ -0,0 +1,377 @@ +[ + { + "id": "27d4fad308fd9bd9", + "type": "group", + "z": "8e3f56d019f55677", + "name": "Double-depth event-out and return \\n ", + "style": { + "fill": "#ffffbf", + "fill-opacity": "0.26", + "label": true, + "color": "#6f2fa0" + }, + "nodes": [ + "445f49b44309142d", + "aa103474b84d5a58", + "2cbb3cd788dff965", + "7dc71f19ca5fcdd7", + "3c32a6b94faee583", + "acf119f388e431ec", + "3a96f909199808d6", + "93dbe802654942a4", + "09fafe2e65457d0a", + "7fed6d4ded4432e6", + "74f80e84b2cb1a4d", + "fa0fcadc9a7342fa", + "b573d1dcece1fdd3", + "aa5329c75fc8c224", + "d16d39fab75667fd", + "0459fe8d982d0280", + "3051aac86938589c" + ], + "x": 24, + "y": 23, + "w": 1082, + "h": 478 + }, + { + "id": "445f49b44309142d", + "type": "event-in", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "", + "topic": "red/test", + "x": 130, + "y": 240, + "wires": [ + [ + "09fafe2e65457d0a" + ] + ] + }, + { + "id": "aa103474b84d5a58", + "type": "event-out", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "", + "topic": "", + "passthrough": "return", + "outputs": 1, + "x": 380, + "y": 140, + "wires": [ + [ + "3c32a6b94faee583" + ] + ] + }, + { + "id": "2cbb3cd788dff965", + "type": "event-return", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "", + "topic": "", + "passthrough": true, + "outputs": 1, + "x": 850, + "y": 240, + "wires": [ + [ + "0459fe8d982d0280" + ] + ] + }, + { + "id": "7dc71f19ca5fcdd7", + "type": "inject", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "red/test", + "payloadType": "date", + "x": 160, + "y": 140, + "wires": [ + [ + "aa103474b84d5a58" + ] + ] + }, + { + "id": "3c32a6b94faee583", + "type": "debug", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "msg1", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 580, + "y": 140, + "wires": [] + }, + { + "id": "acf119f388e431ec", + "type": "event-in", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "", + "topic": "blue/test", + "x": 360, + "y": 400, + "wires": [ + [ + "93dbe802654942a4", + "fa0fcadc9a7342fa" + ] + ] + }, + { + "id": "3a96f909199808d6", + "type": "event-return", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "", + "topic": "", + "passthrough": true, + "outputs": 1, + "x": 770, + "y": 400, + "wires": [ + [ + "b573d1dcece1fdd3" + ] + ] + }, + { + "id": "93dbe802654942a4", + "type": "change", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "(\t $minimum := 1;\t $maximum := 10;\t $round(($random() * ($maximum-$minimum)) + $minimum, 0)\t)", + "tot": "jsonata" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 540, + "y": 400, + "wires": [ + [ + "3a96f909199808d6" + ] + ] + }, + { + "id": "09fafe2e65457d0a", + "type": "change", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "", + "rules": [ + { + "t": "set", + "p": "topicOrig", + "pt": "msg", + "to": "topic", + "tot": "msg" + }, + { + "t": "set", + "p": "topic", + "pt": "msg", + "to": "", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 300, + "y": 240, + "wires": [ + [ + "74f80e84b2cb1a4d", + "d16d39fab75667fd" + ] + ] + }, + { + "id": "7fed6d4ded4432e6", + "type": "change", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "", + "rules": [ + { + "t": "set", + "p": "topic", + "pt": "msg", + "to": "topicOrig", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 670, + "y": 240, + "wires": [ + [ + "2cbb3cd788dff965" + ] + ] + }, + { + "id": "74f80e84b2cb1a4d", + "type": "debug", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "msg2", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 470, + "y": 300, + "wires": [] + }, + { + "id": "fa0fcadc9a7342fa", + "type": "debug", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "msg4", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 510, + "y": 460, + "wires": [] + }, + { + "id": "b573d1dcece1fdd3", + "type": "debug", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "msg5", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 950, + "y": 400, + "wires": [] + }, + { + "id": "aa5329c75fc8c224", + "type": "debug", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "msg3", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 650, + "y": 300, + "wires": [] + }, + { + "id": "d16d39fab75667fd", + "type": "event-out", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "", + "topic": "blue/test", + "passthrough": "return", + "outputs": 1, + "x": 480, + "y": 240, + "wires": [ + [ + "aa5329c75fc8c224", + "7fed6d4ded4432e6" + ] + ] + }, + { + "id": "0459fe8d982d0280", + "type": "debug", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "msg6", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 1010, + "y": 240, + "wires": [] + }, + { + "id": "3051aac86938589c", + "type": "comment", + "z": "8e3f56d019f55677", + "g": "27d4fad308fd9bd9", + "name": "Expect 6 outputs, 1 from each debug node", + "info": "Output order:\n\n* 2\n* 4\n* 5\n* 3\n* 6\n* 1", + "x": 240, + "y": 80, + "wires": [] + } +] \ No newline at end of file diff --git a/examples/simple-test.json b/examples/simple-test.json index e851007..6da4ec9 100644 --- a/examples/simple-test.json +++ b/examples/simple-test.json @@ -2,10 +2,10 @@ { "id": "b8d40388d72e6e0e", "type": "event-in", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "name": "", "topic": "examples/**", - "x": 810, + "x": 790, "y": 320, "wires": [ [ @@ -16,7 +16,7 @@ { "id": "9bba81f838846069", "type": "debug", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "name": "", "active": true, "tosidebar": true, @@ -26,14 +26,14 @@ "targetType": "full", "statusVal": "payload", "statusType": "msg", - "x": 1010, + "x": 990, "y": 320, "wires": [] }, { "id": "0d0a35162e82055a", "type": "debug", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "name": "", "active": true, "tosidebar": true, @@ -43,14 +43,14 @@ "targetType": "full", "statusVal": "payload", "statusType": "msg", - "x": 1010, + "x": 990, "y": 380, "wires": [] }, { "id": "67928932778fceff", "type": "group", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "name": "Valid Input Messages \\n ", "style": { "stroke": "#92d04f", @@ -69,7 +69,7 @@ "76d3d6e0b6559112", "18205a9c2c4b3b4a" ], - "x": 54, + "x": 34, "y": 23, "w": 572, "h": 318 @@ -77,7 +77,7 @@ { "id": "cd7e74689f80d6d8", "type": "inject", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "67928932778fceff", "name": "Expect 6 outputs", "props": [ @@ -101,7 +101,7 @@ "topic": "examples/example1", "payload": "I am example 1", "payloadType": "str", - "x": 180, + "x": 160, "y": 80, "wires": [ [ @@ -112,7 +112,7 @@ { "id": "b6e339b8d119ffd2", "type": "inject", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "67928932778fceff", "name": "Expect 5 outputs", "props": [ @@ -136,7 +136,7 @@ "topic": "examples/example2", "payload": "I am example 2", "payloadType": "str", - "x": 180, + "x": 160, "y": 120, "wires": [ [ @@ -147,7 +147,7 @@ { "id": "fc38ec1067519f20", "type": "inject", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "67928932778fceff", "name": "Multi-level: Expect 2 outputs", "props": [ @@ -171,7 +171,7 @@ "topic": "examples/example3/another/level", "payload": "I am example 3", "payloadType": "str", - "x": 220, + "x": 200, "y": 160, "wires": [ [ @@ -182,19 +182,20 @@ { "id": "80372eb0451d3972", "type": "event-out", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "67928932778fceff", "name": "", "topic": "defaultTopic", + "passthrough": "none", "outputs": 0, - "x": 530, + "x": 510, "y": 80, "wires": [] }, { "id": "dc2785b950617d59", "type": "inject", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "67928932778fceff", "name": "No topic (default enabled): Expect 1 output", "props": [ @@ -214,7 +215,7 @@ "topic": "", "payload": "No topic example", "payloadType": "str", - "x": 260, + "x": 240, "y": 200, "wires": [ [ @@ -225,7 +226,7 @@ { "id": "80f0d09ccb354a9d", "type": "inject", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "67928932778fceff", "name": "Passthrough", "props": [ @@ -249,7 +250,7 @@ "topic": "examples/example2", "payload": "I am example 2", "payloadType": "str", - "x": 170, + "x": 150, "y": 300, "wires": [ [ @@ -260,13 +261,13 @@ { "id": "76d3d6e0b6559112", "type": "event-out", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "67928932778fceff", "name": "", "topic": "", - "passthrough": true, + "passthrough": "input", "outputs": 1, - "x": 340, + "x": 320, "y": 300, "wires": [ [ @@ -277,7 +278,7 @@ { "id": "18205a9c2c4b3b4a", "type": "debug", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "67928932778fceff", "name": "", "active": true, @@ -288,14 +289,14 @@ "targetType": "full", "statusVal": "", "statusType": "auto", - "x": 510, + "x": 490, "y": 300, "wires": [] }, { "id": "883e090d8eb4b74f", "type": "group", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "name": "Outputs - See the debug panel for valid and error outputs \\n ", "style": { "stroke": "#0070c0", @@ -319,7 +320,7 @@ "1f588e99bd69a8f9", "559741411257c600" ], - "x": 714, + "x": 694, "y": 23, "w": 392, "h": 518 @@ -327,7 +328,7 @@ { "id": "8db94251f4bfc582", "type": "debug", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "883e090d8eb4b74f", "name": "", "active": true, @@ -338,14 +339,14 @@ "targetType": "full", "statusVal": "payload", "statusType": "msg", - "x": 1010, + "x": 990, "y": 80, "wires": [] }, { "id": "99ae35911f9beb07", "type": "debug", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "883e090d8eb4b74f", "name": "", "active": true, @@ -356,14 +357,14 @@ "targetType": "full", "statusVal": "payload", "statusType": "msg", - "x": 1010, + "x": 990, "y": 140, "wires": [] }, { "id": "357d18d1dc7409ba", "type": "debug", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "883e090d8eb4b74f", "name": "", "active": true, @@ -374,18 +375,18 @@ "targetType": "full", "statusVal": "payload", "statusType": "msg", - "x": 1010, + "x": 990, "y": 200, "wires": [] }, { "id": "bcbb58dc68b2cdd2", "type": "event-in", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "883e090d8eb4b74f", "name": "Example 1a", "topic": "examples/example1", - "x": 810, + "x": 790, "y": 80, "wires": [ [ @@ -396,11 +397,11 @@ { "id": "5d32ccc5f6501aa8", "type": "event-in", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "883e090d8eb4b74f", "name": "Example 1b ", "topic": "examples/example1", - "x": 810, + "x": 790, "y": 140, "wires": [ [ @@ -411,11 +412,11 @@ { "id": "93371ee03ba7cd9a", "type": "event-in", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "883e090d8eb4b74f", "name": "", "topic": "examples/example2", - "x": 830, + "x": 810, "y": 200, "wires": [ [ @@ -426,7 +427,7 @@ { "id": "e67d203a6f91357e", "type": "debug", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "883e090d8eb4b74f", "name": "", "active": true, @@ -437,18 +438,18 @@ "targetType": "full", "statusVal": "payload", "statusType": "msg", - "x": 1010, + "x": 990, "y": 260, "wires": [] }, { "id": "4dedcf6a355b32bf", "type": "event-in", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "883e090d8eb4b74f", "name": "", "topic": "examples/*", - "x": 800, + "x": 780, "y": 260, "wires": [ [ @@ -459,7 +460,7 @@ { "id": "2bd5446ca5b41eda", "type": "debug", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "883e090d8eb4b74f", "name": "", "active": true, @@ -470,18 +471,18 @@ "targetType": "full", "statusVal": "payload", "statusType": "msg", - "x": 1010, + "x": 990, "y": 500, "wires": [] }, { "id": "2406573246c81ef6", "type": "event-in", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "883e090d8eb4b74f", "name": "", "topic": "defaultTopic", - "x": 810, + "x": 790, "y": 500, "wires": [ [ @@ -492,11 +493,11 @@ { "id": "2140cf56b552fe1b", "type": "event-in", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "883e090d8eb4b74f", "name": "", "topic": "examples/+", - "x": 810, + "x": 790, "y": 380, "wires": [ [ @@ -507,11 +508,11 @@ { "id": "1f588e99bd69a8f9", "type": "event-in", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "883e090d8eb4b74f", "name": "", "topic": "examples/#", - "x": 810, + "x": 790, "y": 440, "wires": [ [ @@ -522,7 +523,7 @@ { "id": "559741411257c600", "type": "debug", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "883e090d8eb4b74f", "name": "", "active": true, @@ -533,14 +534,14 @@ "targetType": "full", "statusVal": "payload", "statusType": "msg", - "x": 1010, + "x": 990, "y": 440, "wires": [] }, { "id": "f1d57f2323376d4f", "type": "group", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "name": "Error Tests \\n ", "style": { "stroke": "#ff0000", @@ -561,7 +562,7 @@ "88f335a6657f3025", "cbd27c0740d2df2c" ], - "x": 54, + "x": 34, "y": 363, "w": 572, "h": 358 @@ -569,7 +570,7 @@ { "id": "48cff9ebf7f43376", "type": "inject", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "f1d57f2323376d4f", "name": "Topic >255 characters (error)", "props": [ @@ -588,7 +589,7 @@ "topic": "123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/123/456/789/0/", "payload": "This topic is >255 chars - should generate an error", "payloadType": "str", - "x": 220, + "x": 200, "y": 420, "wires": [ [ @@ -599,19 +600,19 @@ { "id": "8962a5fe0b8d6288", "type": "event-out", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "f1d57f2323376d4f", "name": "Error Tests", "topic": "", "outputs": 0, - "x": 530, + "x": 510, "y": 420, "wires": [] }, { "id": "88fae359279f773c", "type": "inject", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "f1d57f2323376d4f", "name": "No topic and no default (error)", "props": [ @@ -626,7 +627,7 @@ "topic": "", "payload": "No topic example & no default (should error)", "payloadType": "str", - "x": 220, + "x": 200, "y": 460, "wires": [ [ @@ -637,7 +638,7 @@ { "id": "0972a2d7180549c3", "type": "inject", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "f1d57f2323376d4f", "name": "Topic contains `#` (error)", "props": [ @@ -656,7 +657,7 @@ "topic": "some/text#/blurb", "payload": "Topic contains # (should error)", "payloadType": "str", - "x": 230, + "x": 210, "y": 500, "wires": [ [ @@ -667,7 +668,7 @@ { "id": "27976301ca819020", "type": "inject", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "f1d57f2323376d4f", "name": "Topic contains `*` (error)", "props": [ @@ -686,7 +687,7 @@ "topic": "some/text*/blurb", "payload": "Topic contains * (should error)", "payloadType": "str", - "x": 240, + "x": 220, "y": 540, "wires": [ [ @@ -697,7 +698,7 @@ { "id": "2936bcef3b54a656", "type": "inject", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "f1d57f2323376d4f", "name": "Topic contains `+` (error)", "props": [ @@ -716,7 +717,7 @@ "topic": "some/text+/blurb", "payload": "Topic contains + (should error)", "payloadType": "str", - "x": 230, + "x": 210, "y": 580, "wires": [ [ @@ -727,7 +728,7 @@ { "id": "f432f577fc0b19f2", "type": "inject", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "f1d57f2323376d4f", "name": "Several errors (error)", "props": [ @@ -746,7 +747,7 @@ "topic": "some/+text#/blurb/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/", "payload": "Topic contains # (should error)", "payloadType": "str", - "x": 240, + "x": 220, "y": 620, "wires": [ [ @@ -757,7 +758,7 @@ { "id": "6ec3e8743317f01e", "type": "inject", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "f1d57f2323376d4f", "name": "Passthrough", "props": [ @@ -781,7 +782,7 @@ "topic": "examples/example+2", "payload": "I am example 2", "payloadType": "str", - "x": 170, + "x": 150, "y": 680, "wires": [ [ @@ -792,13 +793,13 @@ { "id": "88f335a6657f3025", "type": "event-out", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "f1d57f2323376d4f", "name": "Expect only error", "topic": "", - "passthrough": true, + "passthrough": "input", "outputs": 1, - "x": 350, + "x": 330, "y": 680, "wires": [ [ @@ -809,7 +810,7 @@ { "id": "cbd27c0740d2df2c", "type": "debug", - "z": "3b8f2a4f11876937", + "z": "f8f450e5112b3528", "g": "f1d57f2323376d4f", "name": "", "active": true, @@ -820,7 +821,7 @@ "targetType": "full", "statusVal": "", "statusType": "auto", - "x": 510, + "x": 490, "y": 680, "wires": [] } diff --git a/examples/test-event-return-node.json b/examples/test-event-return-node.json index a8cb39b..06996dc 100644 --- a/examples/test-event-return-node.json +++ b/examples/test-event-return-node.json @@ -247,7 +247,7 @@ "x": 234, "y": 283, "w": 532, - "h": 138 + "h": 158 }, { "id": "f010dbf8a8087a75", @@ -317,7 +317,7 @@ "statusVal": "", "statusType": "auto", "x": 650, - "y": 380, + "y": 400, "wires": [] } ] \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index e1870d5..9220afb 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -46,7 +46,7 @@ const fs = require('fs') //#region >>>> Vars - change as needed <<<< // // What release/version do we want to end up with? -const release = '1.1.2' +const release = '1.1.3' // Locations const nodeDest = 'nodes' diff --git a/nodes/event-out.html b/nodes/event-out.html index 6ce1d4c..a5b07df 100644 --- a/nodes/event-out.html +++ b/nodes/event-out.html @@ -148,10 +148,21 @@

Node Settings

Topic string
A topic name to use if the incoming msg does not contain one.
-
passthrough boolean
+
passthrough string, hidden
- If selected, an output port will appear and any input msg will be also delivered to the output. - This allows you to use the node in-line with a flow but still benefit from listeners elsewhere in your flows and tabs. + Set by the 3 radio buttons to one of 'none', 'input', or 'return'. +
diff --git a/nodes/event-out.js b/nodes/event-out.js index f6d4c49..eaa7472 100644 --- a/nodes/event-out.js +++ b/nodes/event-out.js @@ -37,6 +37,8 @@ const mod = { RED: undefined, /** @type {string} Custom Node Name - has to match with html file and package.json `red` section */ nodeName: 'event-out', + /** @type {boolean} Turn on/off node debugging */ + debug: false, } //#endregion ----- Module level variables ---- // @@ -56,9 +58,9 @@ function inputMsgHandler(msg, send, done) { // eslint-disable-line no-unused-var // If you need it - or just use mod.RED if you prefer: //const RED = mod.RED - let topic = msg.topic - // Default topic from the settings if the msg doesn't define one + // Use the default topic from the settings if the msg doesn't define one + let topic = msg.topic if ( (! topic) && this.topic ) topic = this.topic if ( ! topic ) topic = '' @@ -74,15 +76,20 @@ function inputMsgHandler(msg, send, done) { // eslint-disable-line no-unused-var return } + // If passthrough set to 'input', send the original msg to the output port + if ( this.passthrough === 'input' ) send(msg) + // Ensure that the event name is unique for these nodes (since the event handler may be reused in other nodes) const eventName = `node-red-contrib-events/${topic}` - // Add the originating node id to make tracing easier - msg._eventOriginator = this.id - // Emit the event - tiEvents.emit(eventName, msg) - if ( this.passthrough === 'input' ) send(msg) // If passthrough set to 'input', send the msg to the output port + // Add this.id to new level of _eventOriginator. Done in a way so we don't impact the through msg + let _eo = [] + if ( msg._eventOriginator ) _eo = Array.from(msg._eventOriginator) + _eo.unshift(this.id) + // Emit the event + tiEvents.emit(eventName, { ...msg, ...{_eventOriginator: _eo} }) + // We are done done() @@ -105,6 +112,13 @@ function nodeInstance(config) { this.topic = config.topic || '' this.passthrough = config.passthrough || 'none' + let s = [] + if ( this.passthrough === 'input' ) s = ['green', 'dot'] + else if ( this.passthrough === 'return' ) s = ['blue', 'ring'] + + if ( mod.debug ) this.status({fill:s[0],shape:s[1],text:this.id}) + else if ( this.passthrough !== 'none' ) this.status({fill:s[0],shape:s[1],text:this.passthrough}) + // Handle v1.0 legacy if ( this.passthrough === false ) this.passthrough = 'none' else if ( this.passthrough === true ) this.passthrough = 'input' @@ -117,11 +131,15 @@ function nodeInstance(config) { if ( this.passthrough === 'return' ) { // if set to 'return', set up a return listener tiEvents.on(`node-red-contrib-events/return/${this.id}`, (msg) => { - this.send(msg) + // Drop the top entry + let _eo = [] + if ( msg._eventOriginator ) _eo = Array.from(msg._eventOriginator) + _eo.shift() + + this.send({ ...msg, ...{_eventOriginator: _eo} }) }) } - /** Put things here if you need to do anything when a node instance is removed * Or if Node-RED is shutting down. * Note the use of an arrow function, ensures that the function keeps the diff --git a/nodes/event-return.js b/nodes/event-return.js index a5e1793..97e2bad 100644 --- a/nodes/event-return.js +++ b/nodes/event-return.js @@ -37,6 +37,8 @@ const mod = { RED: undefined, /** @type {string} Custom Node Name - has to match with html file and package.json `red` section */ nodeName: 'event-return', + /** @type {boolean} Turn on/off node debugging */ + debug: false, } //#endregion ----- Module level variables ---- // @@ -56,8 +58,9 @@ function inputMsgHandler(msg, send, done) { // eslint-disable-line no-unused-var // If you need it - or just use mod.RED if you prefer: //const RED = mod.RED - // Override the msg.topic if one is set in the node - if ( this.topic ) msg.topic = this.topic + // Use the default topic from the settings if the msg doesn't define one + if ( (! msg.topic) && this.topic ) msg.topic = this.topic + // Does the input msg contain a msg._eventOriginator property? If not, error if ( ! msg._eventOriginator ) { @@ -66,17 +69,19 @@ function inputMsgHandler(msg, send, done) { // eslint-disable-line no-unused-var return } + // If passthrough is enabled, send the original msg + if ( this.passthrough === true ) send(msg) + // Where to return the msg to? Uses the originating node id - const eventName = `node-red-contrib-events/return/${msg._eventOriginator}` + const eventName = `node-red-contrib-events/return/${msg._eventOriginator[0]}` - // Change the originating node id to this node to make tracing easier - msg._eventReturner = this.id + // Add this node id to make tracing easier + let _er = [] + if ( msg._eventReturner ) _er = Array.from(msg._eventReturner) + _er.unshift(this.id) - // Emit the event - tiEvents.emit(eventName, msg) - - // If passthrough is enabled, send the msg - if ( this.passthrough === true ) send(msg) + // Emit the event but with the _eventReturner replaced with this node id so we don't impact the through msg + tiEvents.emit(eventName, { ...msg, ...{_eventReturner: _er} } ) // We are done done() @@ -100,6 +105,8 @@ function nodeInstance(config) { this.topic = config.topic || '' this.passthrough = config.passthrough + if ( mod.debug ) this.status({fill:'green',shape:'dot',text:this.id}) + /** Handle incoming msg's - note that the handler fn inherits `this` * The inputMsgHandler function is executed every time this instance * of the node receives a msg in a flow. diff --git a/package-lock.json b/package-lock.json index 08b6cc5..3d620b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@totallyinformation/node-red-contrib-events", - "version": "1.1.2", + "version": "1.1.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3041aef..6e152e1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@totallyinformation/node-red-contrib-events", - "version": "1.1.2", + "version": "1.1.3", "description": "Event broadcast and receive nodes for Node-RED.", "keywords": [ "events", diff --git a/src/editor/event-out/help.html b/src/editor/event-out/help.html index c98dcc9..9ce3be5 100644 --- a/src/editor/event-out/help.html +++ b/src/editor/event-out/help.html @@ -25,9 +25,20 @@

Node Settings

Topic string
A topic name to use if the incoming msg does not contain one.
-
passthrough boolean
+
passthrough string, hidden
- If selected, an output port will appear and any input msg will be also delivered to the output. - This allows you to use the node in-line with a flow but still benefit from listeners elsewhere in your flows and tabs. + Set by the 3 radio buttons to one of 'none', 'input', or 'return'. +