Merge branch 'master' into 5463-fix-editablelist-overflow

pull/5467/head
Nick O'Leary 2026-01-26 10:32:28 +00:00 committed by GitHub
commit 1d5557b74d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 228 additions and 180 deletions

View File

@ -159,7 +159,8 @@ module.exports = function(RED) {
if (node.pauseType === "delay") {
node.on("input", function(msg, send, done) {
var id = ourTimeout(function() {
node.idList.splice(node.idList.indexOf(id),1);
var idx = node.idList.indexOf(id);
if (idx !== -1) { node.idList.splice(idx, 1); }
if (node.timeout > 1000) {
node.status({fill:"blue",shape:"dot",text:node.idList.length});
}
@ -184,7 +185,8 @@ module.exports = function(RED) {
}
if (delayvar < 0) { delayvar = 0; }
var id = ourTimeout(function() {
node.idList.splice(node.idList.indexOf(id),1);
var idx = node.idList.indexOf(id);
if (idx !== -1) { node.idList.splice(idx, 1); }
if (node.idList.length === 0) { node.status({}); }
send(msg);
if (delayvar >= 0) {
@ -207,7 +209,8 @@ module.exports = function(RED) {
node.on("input", function(msg, send, done) {
var wait = node.randomFirst + (node.diff * Math.random());
var id = ourTimeout(function() {
node.idList.splice(node.idList.indexOf(id),1);
var idx = node.idList.indexOf(id);
if (idx !== -1) { node.idList.splice(idx, 1); }
send(msg);
if (node.timeout >= 1000) {
node.status({fill:"blue",shape:"dot",text:node.idList.length});

View File

@ -105,18 +105,26 @@ module.exports = function(RED) {
}
node.activeProcesses[child.pid] = child;
child.stdout.on('data', function (data) {
if (node.activeProcesses.hasOwnProperty(child.pid) && node.activeProcesses[child.pid] !== null) {
// console.log('[exec] stdout: ' + data,child.pid);
if (isUtf8(data)) { msg.payload = data.toString(); }
else { msg.payload = data; }
nodeSend([RED.util.cloneMessage(msg),null,null]);
try {
if (node.activeProcesses.hasOwnProperty(child.pid) && node.activeProcesses[child.pid] !== null) {
// console.log('[exec] stdout: ' + data,child.pid);
if (isUtf8(data)) { msg.payload = data.toString(); }
else { msg.payload = data; }
nodeSend([RED.util.cloneMessage(msg),null,null]);
}
} catch (err) {
node.error(err.toString());
}
});
child.stderr.on('data', function (data) {
if (node.activeProcesses.hasOwnProperty(child.pid) && node.activeProcesses[child.pid] !== null) {
if (isUtf8(data)) { msg.payload = data.toString(); }
else { msg.payload = data; }
nodeSend([null,RED.util.cloneMessage(msg),null]);
try {
if (node.activeProcesses.hasOwnProperty(child.pid) && node.activeProcesses[child.pid] !== null) {
if (isUtf8(data)) { msg.payload = data.toString(); }
else { msg.payload = data; }
nodeSend([null,RED.util.cloneMessage(msg),null]);
}
} catch (err) {
node.error(err.toString());
}
});
child.on('close', function (code,signal) {

View File

@ -227,6 +227,7 @@ module.exports = function(RED) {
* Handle the payload / packet recieved in MQTT In and MQTT Sub nodes
*/
function subscriptionHandler(node, datatype ,topic, payload, packet) {
if (!packet) { packet = {}; }
const msg = {topic:topic, payload:null, qos:packet.qos, retain:packet.retain};
const v5 = (node && node.brokerConn)
? node.brokerConn.v5()
@ -1074,12 +1075,16 @@ module.exports = function(RED) {
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)
try {
const sops = subscription.options ? subscription.options.properties : {}
const pops = (mpacket && 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)
}
} catch (err) {
node.error("MQTT subscription handler error: " + err.toString());
}
}
}

View File

@ -297,7 +297,11 @@ module.exports = function(RED) {
}
msg._session = {type:"websocket",id:id};
for (var i = 0; i < this._inputNodes.length; i++) {
this._inputNodes[i].send(msg);
try {
this._inputNodes[i].send(msg);
} catch (err) {
this.error(RED._("websocket.errors.send-error") + " " + err.toString());
}
}
}

View File

@ -127,32 +127,36 @@ module.exports = function(RED) {
connectionPool[id] = client;
client.on('data', function (data) {
if (node.datatype != 'buffer') {
data = data.toString(node.datatype);
}
if (node.stream) {
var msg;
if ((node.datatype) === "utf8" && node.newline !== "") {
buffer = buffer+data;
var parts = buffer.split(node.newline);
for (var i = 0; i<parts.length-1; i+=1) {
msg = {topic:node.topic, payload:parts[i]};
if (node.trim == true) { msg.payload += node.newline; }
try {
if (node.datatype != 'buffer') {
data = data.toString(node.datatype);
}
if (node.stream) {
var msg;
if ((node.datatype) === "utf8" && node.newline !== "") {
buffer = buffer+data;
var parts = buffer.split(node.newline);
for (var i = 0; i<parts.length-1; i+=1) {
msg = {topic:node.topic, payload:parts[i]};
if (node.trim == true) { msg.payload += node.newline; }
msg._session = {type:"tcp",id:id};
node.send(msg);
}
buffer = parts[parts.length-1];
} else {
msg = {topic:node.topic, payload:data};
msg._session = {type:"tcp",id:id};
node.send(msg);
}
buffer = parts[parts.length-1];
} else {
msg = {topic:node.topic, payload:data};
msg._session = {type:"tcp",id:id};
node.send(msg);
}
} else {
if ((typeof data) === "string") {
buffer = buffer+data;
} else {
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
if ((typeof data) === "string") {
buffer = buffer+data;
} else {
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
}
}
} catch (err) {
node.error(RED._("tcpin.errors.error",{error:err.toString()}));
}
});
client.on('end', function() {
@ -222,35 +226,39 @@ module.exports = function(RED) {
var buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
socket.on('data', function (data) {
if (node.datatype != 'buffer') {
data = data.toString(node.datatype);
}
if (node.stream) {
var msg;
if ((typeof data) === "string" && node.newline !== "") {
buffer = buffer+data;
var parts = buffer.split(node.newline);
for (var i = 0; i<parts.length-1; i+=1) {
msg = {topic:node.topic, payload:parts[i], ip:socket.remoteAddress, port:socket.remotePort};
if (node.trim == true) { msg.payload += node.newline; }
try {
if (node.datatype != 'buffer') {
data = data.toString(node.datatype);
}
if (node.stream) {
var msg;
if ((typeof data) === "string" && node.newline !== "") {
buffer = buffer+data;
var parts = buffer.split(node.newline);
for (var i = 0; i<parts.length-1; i+=1) {
msg = {topic:node.topic, payload:parts[i], ip:socket.remoteAddress, port:socket.remotePort};
if (node.trim == true) { msg.payload += node.newline; }
msg._session = {type:"tcp",id:id};
node.send(msg);
}
buffer = parts[parts.length-1];
} else {
msg = {topic:node.topic, payload:data, ip:socket.remoteAddress, port:socket.remotePort};
msg._session = {type:"tcp",id:id};
node.send(msg);
}
buffer = parts[parts.length-1];
} else {
msg = {topic:node.topic, payload:data, ip:socket.remoteAddress, port:socket.remotePort};
msg._session = {type:"tcp",id:id};
node.send(msg);
}
}
else {
if ((typeof data) === "string") {
buffer = buffer+data;
} else {
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
else {
if ((typeof data) === "string") {
buffer = buffer+data;
} else {
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
}
fromi = socket.remoteAddress;
fromp = socket.remotePort;
}
fromi = socket.remoteAddress;
fromp = socket.remotePort;
} catch (err) {
node.error(RED._("tcpin.errors.error",{error:err.toString()}));
}
});
socket.on('end', function() {
@ -678,117 +686,121 @@ module.exports = function(RED) {
}
var chunk = "";
clients[connection_id].client.on('data', function(data) {
if (node.out === "sit") { // if we are staying connected just send the buffer
if (clients[connection_id]) {
const msg = clients[connection_id].lastMsg || {};
msg.payload = RED.util.cloneMessage(data);
if (node.ret === "string") {
try {
if (node.newline && node.newline !== "" ) {
chunk += msg.payload.toString();
let parts = chunk.split(node.newline);
for (var p=0; p<parts.length-1; p+=1) {
let m = RED.util.cloneMessage(msg);
m.payload = parts[p];
if (node.trim == true) { m.payload += node.newline; }
nodeSend(m);
}
chunk = parts[parts.length-1];
}
else {
msg.payload = msg.payload.toString();
nodeSend(msg);
}
}
catch(e) { node.error(RED._("tcpin.errors.bad-string"), msg); }
}
else { nodeSend(msg); }
}
}
// else if (node.splitc === 0) {
// clients[connection_id].msg.payload = data;
// node.send(clients[connection_id].msg);
// }
else {
for (var j = 0; j < data.length; j++ ) {
if (node.out === "time") {
if (clients[connection_id]) {
// do the timer thing
if (clients[connection_id].timeout) {
i += 1;
buf[i] = data[j];
}
else {
clients[connection_id].timeout = setTimeout(function () {
if (clients[connection_id]) {
clients[connection_id].timeout = null;
const msg = clients[connection_id].lastMsg || {};
msg.payload = Buffer.alloc(i+1);
buf.copy(msg.payload,0,0,i+1);
if (node.ret === "string") {
try { msg.payload = msg.payload.toString(); }
catch(e) { node.error("Failed to create string", msg); }
}
nodeSend(msg);
if (clients[connection_id].client) {
node.status({});
clients[connection_id].client.destroy();
delete clients[connection_id];
}
try {
if (node.out === "sit") { // if we are staying connected just send the buffer
if (clients[connection_id]) {
const msg = clients[connection_id].lastMsg || {};
msg.payload = RED.util.cloneMessage(data);
if (node.ret === "string") {
try {
if (node.newline && node.newline !== "" ) {
chunk += msg.payload.toString();
let parts = chunk.split(node.newline);
for (var p=0; p<parts.length-1; p+=1) {
let m = RED.util.cloneMessage(msg);
m.payload = parts[p];
if (node.trim == true) { m.payload += node.newline; }
nodeSend(m);
}
}, node.splitc);
i = 0;
buf[0] = data[j];
chunk = parts[parts.length-1];
}
else {
msg.payload = msg.payload.toString();
nodeSend(msg);
}
}
catch(e) { node.error(RED._("tcpin.errors.bad-string"), msg); }
}
else { nodeSend(msg); }
}
}
// else if (node.splitc === 0) {
// clients[connection_id].msg.payload = data;
// node.send(clients[connection_id].msg);
// }
else {
for (var j = 0; j < data.length; j++ ) {
if (node.out === "time") {
if (clients[connection_id]) {
// do the timer thing
if (clients[connection_id].timeout) {
i += 1;
buf[i] = data[j];
}
else {
clients[connection_id].timeout = setTimeout(function () {
if (clients[connection_id]) {
clients[connection_id].timeout = null;
const msg = clients[connection_id].lastMsg || {};
msg.payload = Buffer.alloc(i+1);
buf.copy(msg.payload,0,0,i+1);
if (node.ret === "string") {
try { msg.payload = msg.payload.toString(); }
catch(e) { node.error("Failed to create string", msg); }
}
nodeSend(msg);
if (clients[connection_id].client) {
node.status({});
clients[connection_id].client.destroy();
delete clients[connection_id];
}
}
}, node.splitc);
i = 0;
buf[0] = data[j];
}
}
}
}
// count bytes into a buffer...
else if (node.out == "count") {
buf[i] = data[j];
i += 1;
if ( i >= node.splitc) {
if (clients[connection_id]) {
const msg = clients[connection_id].lastMsg || {};
msg.payload = Buffer.alloc(i);
buf.copy(msg.payload,0,0,i);
if (node.ret === "string") {
try { msg.payload = msg.payload.toString(); }
catch(e) { node.error("Failed to create string", msg); }
// count bytes into a buffer...
else if (node.out == "count") {
buf[i] = data[j];
i += 1;
if ( i >= node.splitc) {
if (clients[connection_id]) {
const msg = clients[connection_id].lastMsg || {};
msg.payload = Buffer.alloc(i);
buf.copy(msg.payload,0,0,i);
if (node.ret === "string") {
try { msg.payload = msg.payload.toString(); }
catch(e) { node.error("Failed to create string", msg); }
}
nodeSend(msg);
if (clients[connection_id].client) {
node.status({});
clients[connection_id].client.destroy();
delete clients[connection_id];
}
i = 0;
}
nodeSend(msg);
if (clients[connection_id].client) {
node.status({});
clients[connection_id].client.destroy();
delete clients[connection_id];
}
i = 0;
}
}
}
// look for a char
else {
buf[i] = data[j];
i += 1;
if (data[j] == node.splitc) {
if (clients[connection_id]) {
const msg = clients[connection_id].lastMsg || {};
msg.payload = Buffer.alloc(i);
buf.copy(msg.payload,0,0,i);
if (node.ret === "string") {
try { msg.payload = msg.payload.toString(); }
catch(e) { node.error("Failed to create string", msg); }
// look for a char
else {
buf[i] = data[j];
i += 1;
if (data[j] == node.splitc) {
if (clients[connection_id]) {
const msg = clients[connection_id].lastMsg || {};
msg.payload = Buffer.alloc(i);
buf.copy(msg.payload,0,0,i);
if (node.ret === "string") {
try { msg.payload = msg.payload.toString(); }
catch(e) { node.error("Failed to create string", msg); }
}
nodeSend(msg);
if (clients[connection_id].client) {
node.status({});
clients[connection_id].client.destroy();
delete clients[connection_id];
}
i = 0;
}
nodeSend(msg);
if (clients[connection_id].client) {
node.status({});
clients[connection_id].client.destroy();
delete clients[connection_id];
}
i = 0;
}
}
}
}
} catch (err) {
node.error(RED._("tcpin.errors.error",{error:err.toString()}));
}
});

View File

@ -98,15 +98,19 @@ module.exports = function(RED) {
});
server.on('message', function (message, remote) {
var msg;
if (node.datatype =="base64") {
msg = { payload:message.toString('base64'), fromip:remote.address+':'+remote.port, ip:remote.address, port:remote.port };
} else if (node.datatype =="utf8") {
msg = { payload:message.toString('utf8'), fromip:remote.address+':'+remote.port, ip:remote.address, port:remote.port };
} else {
msg = { payload:message, fromip:remote.address+':'+remote.port, ip:remote.address, port:remote.port };
try {
var msg;
if (node.datatype =="base64") {
msg = { payload:message.toString('base64'), fromip:remote.address+':'+remote.port, ip:remote.address, port:remote.port };
} else if (node.datatype =="utf8") {
msg = { payload:message.toString('utf8'), fromip:remote.address+':'+remote.port, ip:remote.address, port:remote.port };
} else {
msg = { payload:message, fromip:remote.address+':'+remote.port, ip:remote.address, port:remote.port };
}
node.send(msg);
} catch (err) {
node.error(RED._("udp.errors.error",{error:err.toString()}));
}
node.send(msg);
});
server.on('listening', function () {

View File

@ -322,6 +322,7 @@ Node.prototype.close = function(removed) {
// The callback takes a 'done' callback and (maybe) the removed flag
promises.push(
new Promise((resolve) => {
var resolved = false;
try {
var args = [];
if (callback.length === 2) {
@ -329,13 +330,19 @@ Node.prototype.close = function(removed) {
args.push(!!removed);
}
args.push(() => {
resolve();
if (!resolved) {
resolved = true;
resolve();
}
});
callback.apply(node, args);
} catch(err) {
// TODO: error thrown in node async close callback
// We've never logged this properly.
resolve();
if (!resolved) {
resolved = true;
resolve();
}
}
})
);

View File

@ -155,6 +155,7 @@ function LocalFileSystem(config){
}
this.pendingWrites = {};
this.knownCircularRefs = {};
this.closing = false;
if (config.hasOwnProperty('flushInterval')) {
this.flushInterval = Math.max(0,config.flushInterval) * 1000;
@ -233,16 +234,19 @@ LocalFileSystem.prototype.open = function(){
LocalFileSystem.prototype.close = function(){
var self = this;
if (this.cache && this._pendingWriteTimeout) {
clearTimeout(this._pendingWriteTimeout);
delete this._pendingWriteTimeout;
this.closing = true;
if (this.cache) {
if (this._pendingWriteTimeout) {
clearTimeout(this._pendingWriteTimeout);
delete this._pendingWriteTimeout;
}
this.flushInterval = 0;
// Always flush pending writes on close, even if no timeout was pending
self.writePromise = self.writePromise.then(function(){
return self._flushPendingWrites.call(self).catch(function(err) {
log.error(log._("context.localfilesystem.error-write",{message:err.toString()}));
});
});
}
return this.writePromise;
}
@ -298,8 +302,9 @@ LocalFileSystem.prototype.set = function(scope, key, value, callback) {
if (this.cache) {
this.cache.set(scope,key,value,callback);
this.pendingWrites[scope] = true;
if (this._pendingWriteTimeout) {
// there's a pending write which will handle this
if (this._pendingWriteTimeout || this.closing) {
// there's a pending write which will handle this,
// or we're closing and the close() flush will handle it
return;
} else {
this._pendingWriteTimeout = setTimeout(function() {