mirror of https://github.com/node-red/node-red.git
Merge branch 'master' into fix/file-node-error-handler
commit
5a799efa57
10
CHANGELOG.md
10
CHANGELOG.md
|
|
@ -1,3 +1,13 @@
|
|||
#### 4.1.4: Maintenance Releas
|
||||
|
||||
- Update tar dependency @knolleary
|
||||
- Revert overflow fix in editableList (#5467) @knolleary
|
||||
- registry: fix importModule base dir for exports subpaths (#5465) @yuan-cloud
|
||||
- fix: prevent race condition in localfilesystem context store during shutdown (#5462) @Dennis-SEG
|
||||
- fix: prevent double resolve in node close callback (#5461) @Dennis-SEG
|
||||
- fix: prevent incorrect array modification in delay node (#5457) @Dennis-SEG
|
||||
- fix: prevent uncaught exceptions in core node event handlers (#5438) @Dennis-SEG
|
||||
|
||||
#### 4.1.3: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "node-red",
|
||||
"version": "4.1.3",
|
||||
"version": "4.1.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "node-red",
|
||||
"version": "4.1.3",
|
||||
"version": "4.1.4",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"acorn": "8.15.0",
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
"raw-body": "3.0.0",
|
||||
"rfdc": "^1.3.1",
|
||||
"semver": "7.7.1",
|
||||
"tar": "7.4.3",
|
||||
"tar": "7.5.6",
|
||||
"tough-cookie": "5.1.2",
|
||||
"uglify-js": "3.19.3",
|
||||
"uuid": "9.0.1",
|
||||
|
|
@ -10996,16 +10996,15 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "7.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
|
||||
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
|
||||
"license": "ISC",
|
||||
"version": "7.5.6",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.6.tgz",
|
||||
"integrity": "sha512-xqUeu2JAIJpXyvskvU3uvQW8PAmHrtXp2KDuMJwQqW8Sqq0CaZBAQ+dKS3RBXVhU4wC5NjAdKrmh84241gO9cA==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"@isaacs/fs-minipass": "^4.0.0",
|
||||
"chownr": "^3.0.0",
|
||||
"minipass": "^7.1.2",
|
||||
"minizlib": "^3.0.1",
|
||||
"mkdirp": "^3.0.1",
|
||||
"minizlib": "^3.1.0",
|
||||
"yallist": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
|
|
@ -11066,21 +11065,6 @@
|
|||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/tar/node_modules/mkdirp": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
|
||||
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mkdirp": "dist/cjs/src/bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/tar/node_modules/yallist": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "node-red",
|
||||
"version": "4.1.3",
|
||||
"version": "4.1.4",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "https://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
|
|
@ -76,7 +76,7 @@
|
|||
"raw-body": "3.0.0",
|
||||
"rfdc": "^1.3.1",
|
||||
"semver": "7.7.1",
|
||||
"tar": "7.4.3",
|
||||
"tar": "7.5.6",
|
||||
"tough-cookie": "5.1.2",
|
||||
"uglify-js": "3.19.3",
|
||||
"uuid": "9.0.1",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "4.1.3",
|
||||
"version": "4.1.4",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
|
|
@ -16,8 +16,8 @@
|
|||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "4.1.3",
|
||||
"@node-red/editor-client": "4.1.3",
|
||||
"@node-red/util": "4.1.4",
|
||||
"@node-red/editor-client": "4.1.4",
|
||||
"bcryptjs": "3.0.2",
|
||||
"body-parser": "1.20.4",
|
||||
"clone": "2.1.2",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "4.1.3",
|
||||
"version": "4.1.4",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
padding: 2px 16px 2px 4px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.red-ui-editableList-container {
|
||||
padding: 5px;
|
||||
|
|
|
|||
|
|
@ -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});
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()}));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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 () {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@node-red/nodes",
|
||||
"version": "4.1.3",
|
||||
"version": "4.1.4",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ function importModule(module) {
|
|||
throw e;
|
||||
}
|
||||
const externalModuleDir = getInstallDir();
|
||||
const moduleDir = path.join(externalModuleDir,"node_modules",module);
|
||||
const moduleDir = path.join(externalModuleDir,"node_modules",parsedModule.module);
|
||||
// To handle both CJS and ESM we need to resolve the module to the
|
||||
// specific file that is loaded when the module is required/imported
|
||||
// As this won't be on the natural module search path, we use createRequire
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@node-red/registry",
|
||||
"version": "4.1.3",
|
||||
"version": "4.1.4",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
|
|
@ -16,11 +16,11 @@
|
|||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "4.1.3",
|
||||
"@node-red/util": "4.1.4",
|
||||
"clone": "2.1.2",
|
||||
"fs-extra": "11.3.0",
|
||||
"semver": "7.7.1",
|
||||
"tar": "7.4.3",
|
||||
"tar": "7.5.6",
|
||||
"uglify-js": "3.19.3"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@node-red/runtime",
|
||||
"version": "4.1.3",
|
||||
"version": "4.1.4",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
|
|
@ -16,8 +16,8 @@
|
|||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/registry": "4.1.3",
|
||||
"@node-red/util": "4.1.3",
|
||||
"@node-red/registry": "4.1.4",
|
||||
"@node-red/util": "4.1.4",
|
||||
"async-mutex": "0.5.0",
|
||||
"clone": "2.1.2",
|
||||
"cronosjs": "1.7.1",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@node-red/util",
|
||||
"version": "4.1.3",
|
||||
"version": "4.1.4",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "node-red",
|
||||
"version": "4.1.3",
|
||||
"version": "4.1.4",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "https://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
|
|
@ -31,10 +31,10 @@
|
|||
"flow"
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/editor-api": "4.1.3",
|
||||
"@node-red/runtime": "4.1.3",
|
||||
"@node-red/util": "4.1.3",
|
||||
"@node-red/nodes": "4.1.3",
|
||||
"@node-red/editor-api": "4.1.4",
|
||||
"@node-red/runtime": "4.1.4",
|
||||
"@node-red/util": "4.1.4",
|
||||
"@node-red/nodes": "4.1.4",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "3.0.2",
|
||||
"cors": "2.8.5",
|
||||
|
|
|
|||
|
|
@ -344,6 +344,36 @@ describe("externalModules api", function() {
|
|||
should.exist(result);
|
||||
should.exist(result.existsSync);
|
||||
})
|
||||
it("imports external modules using export aliasing", async function() {
|
||||
const externalModulesDir = path.join(homeDir,"externalModules");
|
||||
await fs.ensureDir(externalModulesDir);
|
||||
externalModules.init({userDir: externalModulesDir, get:()=>{}, set:()=>{}});
|
||||
|
||||
await fs.writeFile(path.join(externalModulesDir,"package.json"),`{
|
||||
"name": "Node-RED-External-Modules",
|
||||
"description": "These modules are automatically installed by Node-RED to use in Function nodes.",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"dependencies": {"fake-pkg":"1.0.0"}
|
||||
}`)
|
||||
|
||||
const packageDir = path.join(externalModulesDir,"node_modules","fake-pkg");
|
||||
await fs.ensureDir(path.join(packageDir,"dist"));
|
||||
await fs.writeFile(path.join(packageDir,"package.json"),`{
|
||||
"name": "fake-pkg",
|
||||
"version": "1.0.0",
|
||||
"exports": {
|
||||
"./M.js": "./dist/M.js"
|
||||
}
|
||||
}`)
|
||||
await fs.writeFile(path.join(packageDir,"dist","M.js"),"module.exports = 42;\n");
|
||||
|
||||
await externalModules.checkFlowDependencies([]);
|
||||
|
||||
const importedValue = await externalModules.import("fake-pkg/M.js")
|
||||
const normalizedValue = importedValue && importedValue.default !== undefined ? importedValue.default : importedValue;
|
||||
normalizedValue.should.equal(42);
|
||||
})
|
||||
it("rejects unknown modules", async function() {
|
||||
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
|
||||
try {
|
||||
|
|
|
|||
Loading…
Reference in New Issue