Session, dashboard concurrent use

Found it, in your router function you had msg._socket = clientlist[msg.topic], it should be msg._socketId = clientlist[msg.topic] (_socketId not _socket).

Any the way, I changed your flow a bit.

First, I "simplified" the "client connection" function node:

let clientlist = flow.get("clientlist") || {};

if (msg.urlParams.device) {

    if (msg.uibuilderCtrl === "client connect") {
        clientlist[msg.urlParams.device] = msg._socketId
        node.send(null, {
            payload: '<p>Waiting for data</p>',
            _socketId: msg._socketId,
        })
    }
    
    if (msg.uibuilderCtrl === "client disconnect") {
        delete clientlist[msg.urlParams.device]
    }

    flow.set("clientlist", clientlist)

} else {
    node.send(null, {
            payload: '<p>Missing device parameter in the payload</p>',
            _socketId: msg._socketId,
    })
}

return [msg, null]

So now it passes all control data onwards out of port #1 and passes an explicit new msg out of port #2 only on client connect.

Here is the full thing:

[{"id":"ddf27e1052787ad5","type":"debug","z":"30fdd9a9702231b0","name":"debug 72","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":740,"y":4180,"wires":[]},{"id":"e181aa0641a3733f","type":"debug","z":"30fdd9a9702231b0","name":"debug 73","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":760,"y":4220,"wires":[]},{"id":"c545de0744ed3c75","type":"function","z":"30fdd9a9702231b0","name":"Test 1","func":"let number = Math.floor(Math.random()*100);\nmsg.topic = \"test1\";\nmsg.payload = number;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":570,"y":4500,"wires":[["9e9cbe1ba459dfc1"]]},{"id":"bb23d9df851b734e","type":"inject","z":"30fdd9a9702231b0","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"_uib","v":"{\"clientId\": \"6aX6-fbCXY7i9uFO3ZaI6\" }","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"test","payload":"OK","payloadType":"str","x":210,"y":4140,"wires":[["958d1f8c4fc837f6"]]},{"id":"01512afde4d3dcf2","type":"inject","z":"30fdd9a9702231b0","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"_uib","v":"{\"clientId\": \"xxxxx\" }","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"test","payload":"Not OK","payloadType":"str","x":230,"y":4180,"wires":[["958d1f8c4fc837f6"]]},{"id":"958d1f8c4fc837f6","type":"uibuilder","z":"30fdd9a9702231b0","name":"","topic":"","url":"nygma2004","okToGo":true,"fwdInMessages":false,"allowScripts":false,"allowStyles":false,"copyIndex":true,"templateFolder":"blank","extTemplate":"","showfolder":false,"reload":false,"sourceFolder":"src","deployedVersion":"6.8.2","showMsgUib":false,"title":"","descr":"","x":540,"y":4220,"wires":[["ddf27e1052787ad5"],["e181aa0641a3733f","3bb6fe2cc8712d87"]]},{"id":"08a6f1d386d371a7","type":"inject","z":"30fdd9a9702231b0","name":"Toggle Visible Msgs","props":[{"p":"_uib","v":"{\"command\":\"showMsg\"}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":250,"y":4220,"wires":[["958d1f8c4fc837f6"]]},{"id":"3bb6fe2cc8712d87","type":"function","z":"30fdd9a9702231b0","name":"Client collection","func":"let clientlist = flow.get(\"clientlist\") || {};\n\nif (msg.urlParams.device) {\n\n    if (msg.uibuilderCtrl === \"client connect\") {\n        clientlist[msg.urlParams.device] = msg._socketId\n        node.send(null, {\n            payload: '<p>Waiting for data</p>',\n            _socketId: msg._socketId,\n        })\n    }\n    \n    if (msg.uibuilderCtrl === \"client disconnect\") {\n        delete clientlist[msg.urlParams.device]\n    }\n\n    flow.set(\"clientlist\", clientlist)\n\n} else {\n    node.send(null, {\n            payload: '<p>Missing device parameter in the payload</p>',\n            _socketId: msg._socketId,\n    })\n}\n\nreturn [msg, null]\n","outputs":2,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":760,"y":4260,"wires":[[],["6ec3e076bd9eded6"]]},{"id":"f9de99c97f05389e","type":"inject","z":"30fdd9a9702231b0","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":410,"y":4540,"wires":[["c545de0744ed3c75","b3f3614223dfa819","56f95f8d4a95376e"]]},{"id":"b3f3614223dfa819","type":"function","z":"30fdd9a9702231b0","name":"Test 2","func":"let number = Math.floor(Math.random()*100+100);\nmsg.topic = \"test2\";\nmsg.payload = number;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":570,"y":4540,"wires":[["9e9cbe1ba459dfc1"]]},{"id":"9e9cbe1ba459dfc1","type":"function","z":"30fdd9a9702231b0","name":"Router","func":"let clientlist = flow.get(\"clientlist\")\n\nif (!clientlist) return\n\nif (clientlist[msg.topic]) {\n    msg._socketId = clientlist[msg.topic]\n    return msg\n}\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":710,"y":4540,"wires":[["f7d081247d597aab"]]},{"id":"30674faded2349bf","type":"uib-element","z":"30fdd9a9702231b0","name":"","topic":"","elementtype":"html","parent":"#more","parentSource":"","parentSourceType":"str","elementid":"more","elementId":"","elementIdSourceType":"str","heading":"","headingSourceType":"str","headingLevel":"h2","data":"payload","dataSourceType":"msg","position":"last","positionSourceType":"str","passthrough":false,"confData":{},"x":530,"y":4400,"wires":[["f1923e4c384ac61a","c667d9ef7138a52b"]]},{"id":"f1923e4c384ac61a","type":"debug","z":"30fdd9a9702231b0","name":"debug 81","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":840,"y":4420,"wires":[]},{"id":"13c0f273a3aa58e6","type":"link in","z":"30fdd9a9702231b0","name":"link in 15","links":["6ec3e076bd9eded6","f7d081247d597aab"],"x":395,"y":4400,"wires":[["30674faded2349bf"]]},{"id":"6ec3e076bd9eded6","type":"link out","z":"30fdd9a9702231b0","name":"link out 81","mode":"link","links":["13c0f273a3aa58e6"],"x":875,"y":4280,"wires":[]},{"id":"1053593e5ce0452b","type":"link in","z":"30fdd9a9702231b0","name":"link in 16","links":["c667d9ef7138a52b","f7d081247d597aab"],"x":395,"y":4260,"wires":[["958d1f8c4fc837f6"]]},{"id":"c667d9ef7138a52b","type":"link out","z":"30fdd9a9702231b0","name":"link out 82","mode":"link","links":["1053593e5ce0452b"],"x":875,"y":4380,"wires":[]},{"id":"849ac0cc42a2a236","type":"inject","z":"30fdd9a9702231b0","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":240,"y":4260,"wires":[["958d1f8c4fc837f6"]]},{"id":"56f95f8d4a95376e","type":"function","z":"30fdd9a9702231b0","name":"Test x","func":"msg.topic = \"testx\"\nmsg.payload = -1\nreturn msg","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":570,"y":4580,"wires":[["9e9cbe1ba459dfc1"]]},{"id":"f7d081247d597aab","type":"link out","z":"30fdd9a9702231b0","name":"link out 83","mode":"link","links":["1053593e5ce0452b","13c0f273a3aa58e6"],"x":815,"y":4540,"wires":[]}]

Amazing, exactly what I wanted!!!

Thanks for fixing my code:
I did not know that you can initialize to an empty object like this: let clientlist = flow.get("clientlist") || {};. I thought this is only possible with simple types like boolean, and numbers.

I did not know that you can also do this: if (msg.urlParams.device) { I guess anything other than null or undefined evalutes to true in javascript. The wonders of javascript :slight_smile:

Interesting to see your use of node.send. For some reason I never remember to use it, I always just return but I have to make sure to do housekeeping (like update the context variables) before return.

No problem. Just do some more UIBUILDER videos! :grinning:

Actually I should have used ?? rather than || - it is a good habit to get into at least in node.js (not all browsers yet support that. That's because if the initial part of your data is "falsy", || doesn't do what you expect whereas ?? does. But yes, it is a really nice shortcut that generally (in my view) looks easier to read than the alternative.

I used to get that one wrong as well until relatively recently. Again, not so useful if your property value needs to differentiate between null, undefined, false, and "" since all of those will evaluate to false in the if statement. But it saves tons of time and pointless typing when you really DO mean that you don't want it to be any of those things.

I know what you mean, hard to remember. Also note that I created a new msg object rather than relying on deleting a property from the old one. Deleting properties can be a bit fraught with JS in general but in Node-RED specifically because of JS's insistence on passing objects by reference and doing things asynchronously. That's not to say don't do it, your original code would have worked in that sense, I just prefer to avoid if possible having been caught out a few times.

1 Like

Also beware that if that property is 0 then that also evaluates to false... so be extra careful if it is numeric.

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.