@node-red/nodes 2.1.4 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/LICENSE +1 -1
  2. package/core/common/20-inject.html +4 -4
  3. package/core/common/20-inject.js +2 -8
  4. package/core/function/10-function.html +6 -4
  5. package/core/function/10-function.js +5 -2
  6. package/core/function/89-delay.html +2 -1
  7. package/core/function/90-exec.js +3 -3
  8. package/core/function/rbe.js +1 -1
  9. package/core/network/10-mqtt.js +11 -5
  10. package/core/network/21-httprequest.js +6 -4
  11. package/core/network/22-websocket.html +6 -2
  12. package/core/network/22-websocket.js +22 -14
  13. package/core/network/31-tcpin.html +126 -20
  14. package/core/network/31-tcpin.js +162 -29
  15. package/core/parsers/70-JSON.js +5 -1
  16. package/core/storage/10-file.js +1 -3
  17. package/examples/common/link/03 - Link call.json +156 -0
  18. package/examples/storage/{file/01 - Write string to a file.json → read file/01 - Read string from a file.json } +22 -22
  19. package/examples/storage/{file-in → read file}/02 - Read data in specified encoding.json +23 -22
  20. package/examples/storage/{file-in → read file}/03 - Read data breaking lines into messages.json +25 -25
  21. package/examples/storage/{file-in → read file}/04 - Create a message stream.json +37 -37
  22. package/examples/storage/{file-in/01 - Read string from a file.json → write file/01 - Write string to a file.json } +15 -15
  23. package/examples/storage/{file → write file}/02 - Write string to a file specified by property.json +22 -22
  24. package/examples/storage/{file → write file}/03 - Delete a file.json +16 -16
  25. package/examples/storage/{file → write file}/04 - Specify encoding of written data.json +23 -23
  26. package/locales/de/messages.json +2 -1
  27. package/locales/en-US/function/80-template.html +1 -1
  28. package/locales/en-US/function/89-delay.html +1 -1
  29. package/locales/en-US/function/rbe.html +2 -2
  30. package/locales/en-US/messages.json +10 -6
  31. package/locales/en-US/network/10-mqtt.html +1 -1
  32. package/locales/en-US/network/21-httprequest.html +1 -1
  33. package/locales/en-US/sequence/17-split.html +1 -1
  34. package/locales/ja/function/80-template.html +2 -0
  35. package/locales/ja/function/89-delay.html +5 -2
  36. package/locales/ja/function/rbe.html +1 -1
  37. package/locales/ja/messages.json +9 -4
  38. package/locales/ja/network/10-mqtt.html +65 -4
  39. package/locales/ja/parsers/70-CSV.html +1 -1
  40. package/locales/ja/sequence/17-split.html +5 -2
  41. package/locales/ko/messages.json +2 -1
  42. package/locales/ru/messages.json +2 -1
  43. package/locales/zh-CN/messages.json +2 -1
  44. package/locales/zh-TW/messages.json +2 -1
  45. package/package.json +7 -7
@@ -16,13 +16,46 @@
16
16
 
17
17
  module.exports = function(RED) {
18
18
  "use strict";
19
- var reconnectTime = RED.settings.socketReconnectTime||10000;
20
- var socketTimeout = RED.settings.socketTimeout||null;
19
+ let reconnectTime = RED.settings.socketReconnectTime || 10000;
20
+ let socketTimeout = RED.settings.socketTimeout || null;
21
21
  const msgQueueSize = RED.settings.tcpMsgQueueSize || 1000;
22
22
  const Denque = require('denque');
23
- var net = require('net');
23
+ const net = require('net');
24
+ const tls = require('tls');
25
+
26
+ let connectionPool = {};
27
+
28
+ function normalizeConnectArgs(listArgs) {
29
+ const args = net._normalizeArgs(listArgs);
30
+ const options = args[0];
31
+ const cb = args[1];
32
+
33
+ // If args[0] was options, then normalize dealt with it.
34
+ // If args[0] is port, or args[0], args[1] is host, port, we need to
35
+ // find the options and merge them in, normalize's options has only
36
+ // the host/port/path args that it knows about, not the tls options.
37
+ // This means that options.host overrides a host arg.
38
+ if (listArgs[1] !== null && typeof listArgs[1] === 'object') {
39
+ ObjectAssign(options, listArgs[1]);
40
+ } else if (listArgs[2] !== null && typeof listArgs[2] === 'object') {
41
+ ObjectAssign(options, listArgs[2]);
42
+ }
43
+
44
+ return cb ? [options, cb] : [options];
45
+ }
24
46
 
25
- var connectionPool = {};
47
+ function getAllowUnauthorized() {
48
+ const allowUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0';
49
+
50
+ if (allowUnauthorized) {
51
+ process.emitWarning(
52
+ 'Setting the NODE_TLS_REJECT_UNAUTHORIZED ' +
53
+ 'environment variable to \'0\' makes TLS connections ' +
54
+ 'and HTTPS requests insecure by disabling ' +
55
+ 'certificate verification.');
56
+ }
57
+ return allowUnauthorized;
58
+ }
26
59
 
27
60
  /**
28
61
  * Enqueue `item` in `queue`
@@ -53,13 +86,14 @@ module.exports = function(RED) {
53
86
  this.topic = n.topic;
54
87
  this.stream = (!n.datamode||n.datamode=='stream'); /* stream,single*/
55
88
  this.datatype = n.datatype||'buffer'; /* buffer,utf8,base64 */
56
- this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r");
89
+ this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r").replace("\\t","\t");
57
90
  this.base64 = n.base64;
58
91
  this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");
59
92
  this.closing = false;
60
93
  this.connected = false;
61
94
  var node = this;
62
95
  var count = 0;
96
+ if (n.tls) { var tlsNode = RED.nodes.getNode(n.tls); }
63
97
 
64
98
  if (!node.server) {
65
99
  var buffer = null;
@@ -70,13 +104,25 @@ module.exports = function(RED) {
70
104
  node.log(RED._("tcpin.status.connecting",{host:node.host,port:node.port}));
71
105
  node.status({fill:"grey",shape:"dot",text:"common.status.connecting"});
72
106
  var id = RED.util.generateId();
73
- client = net.connect(node.port, node.host, function() {
74
- buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
75
- node.connected = true;
76
- node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
77
- node.status({fill:"green",shape:"dot",text:"common.status.connected",_session:{type:"tcp",id:id}});
78
- });
79
- client.setKeepAlive(true,120000);
107
+ var connOpts = {host: node.host};
108
+ if (n.tls) {
109
+ var connOpts = tlsNode.addTLSOptions({host: node.host});
110
+ client = tls.connect(node.port, connOpts, function() {
111
+ buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
112
+ node.connected = true;
113
+ node.log(RED._("status.connected", {host: node.host, port: node.port}));
114
+ node.status({fill:"green",shape:"dot",text:"common.status.connected",_session:{type:"tcp",id:id}});
115
+ });
116
+ }
117
+ else {
118
+ client = net.connect(node.port, node.host, function() {
119
+ buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
120
+ node.connected = true;
121
+ node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
122
+ node.status({fill:"green",shape:"dot",text:"common.status.connected",_session:{type:"tcp",id:id}});
123
+ });
124
+ }
125
+ client.setKeepAlive(true, 120000);
80
126
  connectionPool[id] = client;
81
127
 
82
128
  client.on('data', function (data) {
@@ -89,7 +135,7 @@ module.exports = function(RED) {
89
135
  buffer = buffer+data;
90
136
  var parts = buffer.split(node.newline);
91
137
  for (var i = 0; i<parts.length-1; i+=1) {
92
- msg = {topic:node.topic, payload:parts[i]};
138
+ msg = {topic:node.topic, payload:parts[i] + node.newline.trimEnd()};
93
139
  msg._session = {type:"tcp",id:id};
94
140
  node.send(msg);
95
141
  }
@@ -150,7 +196,13 @@ module.exports = function(RED) {
150
196
  });
151
197
  }
152
198
  else {
153
- var server = net.createServer(function (socket) {
199
+ let srv = net;
200
+ let connOpts;
201
+ if (n.tls) {
202
+ srv = tls;
203
+ connOpts = tlsNode.addTLSOptions({});
204
+ }
205
+ var server = srv.createServer(connOpts, function (socket) {
154
206
  socket.setKeepAlive(true,120000);
155
207
  if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
156
208
  var id = RED.util.generateId();
@@ -177,7 +229,7 @@ module.exports = function(RED) {
177
229
  buffer = buffer+data;
178
230
  var parts = buffer.split(node.newline);
179
231
  for (var i = 0; i<parts.length-1; i+=1) {
180
- msg = {topic:node.topic, payload:parts[i], ip:socket.remoteAddress, port:socket.remotePort};
232
+ msg = {topic:node.topic, payload:parts[i] + node.newline.trimEnd(), ip:socket.remoteAddress, port:socket.remotePort};
181
233
  msg._session = {type:"tcp",id:id};
182
234
  node.send(msg);
183
235
  }
@@ -269,8 +321,9 @@ module.exports = function(RED) {
269
321
  this.closing = false;
270
322
  this.connected = false;
271
323
  var node = this;
324
+ if (n.tls) { var tlsNode = RED.nodes.getNode(n.tls); }
272
325
 
273
- if (!node.beserver||node.beserver=="client") {
326
+ if (!node.beserver || node.beserver == "client") {
274
327
  var reconnectTimeout;
275
328
  var client = null;
276
329
  var end = false;
@@ -278,11 +331,24 @@ module.exports = function(RED) {
278
331
  var setupTcpClient = function() {
279
332
  node.log(RED._("tcpin.status.connecting",{host:node.host,port:node.port}));
280
333
  node.status({fill:"grey",shape:"dot",text:"common.status.connecting"});
281
- client = net.connect(node.port, node.host, function() {
282
- node.connected = true;
283
- node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
284
- node.status({fill:"green",shape:"dot",text:"common.status.connected"});
285
- });
334
+ if (n.tls) {
335
+ // connOpts = tlsNode.addTLSOptions(connOpts);
336
+ // client = tls.connect(connOpts, function() {
337
+ var connOpts = tlsNode.addTLSOptions({host: node.host});
338
+ client = tls.connect(node.port, connOpts, function() {
339
+ // buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
340
+ node.connected = true;
341
+ node.log(RED._("status.connected", {host: node.host, port: node.port}));
342
+ node.status({fill:"green",shape:"dot",text:"common.status.connected"});
343
+ });
344
+ }
345
+ else {
346
+ client = net.connect(node.port, node.host, function() {
347
+ node.connected = true;
348
+ node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
349
+ node.status({fill:"green",shape:"dot",text:"common.status.connected"});
350
+ });
351
+ }
286
352
  client.setKeepAlive(true,120000);
287
353
  client.on('error', function (err) {
288
354
  node.log(RED._("tcpin.errors.error",{error:err.toString()}));
@@ -368,7 +434,13 @@ module.exports = function(RED) {
368
434
  else {
369
435
  var connectedSockets = [];
370
436
  node.status({text:RED._("tcpin.status.connections",{count:0})});
371
- var server = net.createServer(function (socket) {
437
+ let srv = net;
438
+ let connOpts;
439
+ if (n.tls) {
440
+ srv = tls;
441
+ connOpts = tlsNode.addTLSOptions({});
442
+ }
443
+ var server = srv.createServer(connOpts, function (socket) {
372
444
  socket.setKeepAlive(true,120000);
373
445
  if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
374
446
  node.log(RED._("tcpin.status.connection-from",{host:socket.remoteAddress, port:socket.remotePort}));
@@ -445,7 +517,11 @@ module.exports = function(RED) {
445
517
  this.port = Number(n.port);
446
518
  this.out = n.out;
447
519
  this.ret = n.ret || "buffer";
520
+ this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r").replace("\\t","\t");
448
521
  this.splitc = n.splitc;
522
+ if (n.tls) {
523
+ var tlsNode = RED.nodes.getNode(n.tls);
524
+ }
449
525
 
450
526
  if (this.out === "immed") { this.splitc = -1; this.out = "time"; }
451
527
  if (this.out !== "char") { this.splitc = Number(this.splitc); }
@@ -500,12 +576,48 @@ module.exports = function(RED) {
500
576
  }
501
577
  else { buf = Buffer.alloc(65536); } // set it to 64k... hopefully big enough for most TCP packets.... but only hopefully
502
578
 
503
- clients[connection_id].client = net.Socket();
579
+ var connOpts = {host:host, port:port};
580
+ if (n.tls) {
581
+ connOpts = tlsNode.addTLSOptions(connOpts);
582
+ const allowUnauthorized = getAllowUnauthorized();
583
+
584
+ let options = {
585
+ rejectUnauthorized: !allowUnauthorized,
586
+ ciphers: tls.DEFAULT_CIPHERS,
587
+ checkServerIdentity: tls.checkServerIdentity,
588
+ minDHSize: 1024,
589
+ ...connOpts
590
+ };
591
+
592
+ if (!options.keepAlive) { options.singleUse = true; }
593
+
594
+ const context = options.secureContext || tls.createSecureContext(options);
595
+
596
+ clients[connection_id].client = new tls.TLSSocket(options.socket, {
597
+ allowHalfOpen: options.allowHalfOpen,
598
+ pipe: !!options.path,
599
+ secureContext: context,
600
+ isServer: false,
601
+ requestCert: false, // true,
602
+ rejectUnauthorized: false, // options.rejectUnauthorized !== false,
603
+ session: options.session,
604
+ ALPNProtocols: options.ALPNProtocols,
605
+ requestOCSP: options.requestOCSP,
606
+ enableTrace: options.enableTrace,
607
+ pskCallback: options.pskCallback,
608
+ highWaterMark: options.highWaterMark,
609
+ onread: options.onread,
610
+ signal: options.signal,
611
+ });
612
+ }
613
+ else {
614
+ clients[connection_id].client = net.Socket();
615
+ }
504
616
  if (socketTimeout !== null) { clients[connection_id].client.setTimeout(socketTimeout);}
505
617
 
506
618
  if (host && port) {
507
619
  clients[connection_id].connecting = true;
508
- clients[connection_id].client.connect(port, host, function() {
620
+ clients[connection_id].client.connect(connOpts, function() {
509
621
  //node.log(RED._("tcpin.errors.client-connected"));
510
622
  node.status({fill:"green",shape:"dot",text:"common.status.connected"});
511
623
  if (clients[connection_id] && clients[connection_id].client) {
@@ -528,17 +640,32 @@ module.exports = function(RED) {
528
640
  else {
529
641
  node.warn(RED._("tcpin.errors.no-host"));
530
642
  }
531
-
643
+ var chunk = "";
532
644
  clients[connection_id].client.on('data', function(data) {
533
645
  if (node.out === "sit") { // if we are staying connected just send the buffer
534
646
  if (clients[connection_id]) {
535
647
  const msg = clients[connection_id].lastMsg || {};
536
648
  msg.payload = RED.util.cloneMessage(data);
537
649
  if (node.ret === "string") {
538
- try { msg.payload = msg.payload.toString(); }
539
- catch(e) { node.error("Failed to create string", msg); }
650
+ try {
651
+ if (node.newline && node.newline !== "" ) {
652
+ chunk += msg.payload.toString();
653
+ let parts = chunk.split(node.newline);
654
+ for (var p=0; p<parts.length-1; p+=1) {
655
+ let m = RED.util.cloneMessage(msg);
656
+ m.payload = parts[p] + node.newline.trimEnd();
657
+ nodeSend(m);
658
+ }
659
+ chunk = parts[parts.length-1];
660
+ }
661
+ else {
662
+ msg.payload = msg.payload.toString();
663
+ nodeSend(msg);
664
+ }
665
+ }
666
+ catch(e) { node.error(RED._("tcpin.errors.bad-string"), msg); }
540
667
  }
541
- nodeSend(msg);
668
+ else { nodeSend(msg); }
542
669
  }
543
670
  }
544
671
  // else if (node.splitc === 0) {
@@ -675,7 +802,13 @@ module.exports = function(RED) {
675
802
  //node.warn(RED._("tcpin.errors.connect-timeout"));
676
803
  if (clients[connection_id].client) {
677
804
  clients[connection_id].connecting = true;
678
- clients[connection_id].client.connect(port, host, function() {
805
+
806
+ var connOpts = {host:host, port:port};
807
+ if (n.tls) {
808
+ connOpts = tlsNode.addTLSOptions(connOpts);
809
+ }
810
+
811
+ clients[connection_id].client.connect(connOpts, function() {
679
812
  clients[connection_id].connected = true;
680
813
  clients[connection_id].connecting = false;
681
814
  node.status({fill:"green",shape:"dot",text:"common.status.connected"});
@@ -49,7 +49,11 @@ module.exports = function(RED) {
49
49
  }
50
50
  var value = RED.util.getMessageProperty(msg,node.property);
51
51
  if (value !== undefined) {
52
- if (typeof value === "string") {
52
+ if (typeof value === "string" || Buffer.isBuffer(value)) {
53
+ // if (Buffer.isBuffer(value) && node.action !== "obj") {
54
+ // node.warn(RED._("json.errors.dropped")); done();
55
+ // }
56
+ // else
53
57
  if (node.action === "" || node.action === "obj") {
54
58
  try {
55
59
  RED.util.setMessageProperty(msg,node.property,JSON.parse(value));
@@ -71,9 +71,7 @@ module.exports = function(RED) {
71
71
  node.error(RED._("file.errors.deletefail",{error:err.toString()}),msg);
72
72
  }
73
73
  else {
74
- if (RED.settings.verbose) {
75
- node.log(RED._("file.status.deletedfile",{file:filename}));
76
- }
74
+ node.debug(RED._("file.status.deletedfile",{file:filename}));
77
75
  nodeSend(msg);
78
76
  }
79
77
  done();
@@ -0,0 +1,156 @@
1
+ [
2
+ {
3
+ "id": "62ea32aa.d73aac",
4
+ "type": "comment",
5
+ "z": "6312c0588348b2d4",
6
+ "name": "Example: Link Call Node",
7
+ "info": "Link call node can call link in node then get result from link out node.",
8
+ "x": 230,
9
+ "y": 180,
10
+ "wires": []
11
+ },
12
+ {
13
+ "id": "c588bc36.87fec",
14
+ "type": "comment",
15
+ "z": "6312c0588348b2d4",
16
+ "name": "↓ call link in node",
17
+ "info": "",
18
+ "x": 440,
19
+ "y": 220,
20
+ "wires": []
21
+ },
22
+ {
23
+ "id": "cd31efb4d2c6967e",
24
+ "type": "link call",
25
+ "z": "6312c0588348b2d4",
26
+ "name": "",
27
+ "links": [
28
+ "dbc46892c8d14c37"
29
+ ],
30
+ "timeout": "30",
31
+ "x": 420,
32
+ "y": 260,
33
+ "wires": [
34
+ [
35
+ "c3db64d1d2260340"
36
+ ]
37
+ ]
38
+ },
39
+ {
40
+ "id": "dbc46892c8d14c37",
41
+ "type": "link in",
42
+ "z": "6312c0588348b2d4",
43
+ "name": "",
44
+ "links": [],
45
+ "x": 315,
46
+ "y": 340,
47
+ "wires": [
48
+ [
49
+ "e10575d73f2e5352"
50
+ ]
51
+ ]
52
+ },
53
+ {
54
+ "id": "6b61792143b3b0a3",
55
+ "type": "inject",
56
+ "z": "6312c0588348b2d4",
57
+ "name": "",
58
+ "props": [
59
+ {
60
+ "p": "payload"
61
+ },
62
+ {
63
+ "p": "topic",
64
+ "vt": "str"
65
+ }
66
+ ],
67
+ "repeat": "",
68
+ "crontab": "",
69
+ "once": false,
70
+ "onceDelay": 0.1,
71
+ "topic": "",
72
+ "payload": "",
73
+ "payloadType": "date",
74
+ "x": 240,
75
+ "y": 260,
76
+ "wires": [
77
+ [
78
+ "cd31efb4d2c6967e"
79
+ ]
80
+ ]
81
+ },
82
+ {
83
+ "id": "e10575d73f2e5352",
84
+ "type": "change",
85
+ "z": "6312c0588348b2d4",
86
+ "name": "",
87
+ "rules": [
88
+ {
89
+ "t": "set",
90
+ "p": "payload",
91
+ "pt": "msg",
92
+ "to": "Hello, World!",
93
+ "tot": "str"
94
+ }
95
+ ],
96
+ "action": "",
97
+ "property": "",
98
+ "from": "",
99
+ "to": "",
100
+ "reg": false,
101
+ "x": 450,
102
+ "y": 340,
103
+ "wires": [
104
+ [
105
+ "cf8438e7137bc0f0"
106
+ ]
107
+ ]
108
+ },
109
+ {
110
+ "id": "cf8438e7137bc0f0",
111
+ "type": "link out",
112
+ "z": "6312c0588348b2d4",
113
+ "name": "",
114
+ "mode": "return",
115
+ "links": [],
116
+ "x": 595,
117
+ "y": 340,
118
+ "wires": []
119
+ },
120
+ {
121
+ "id": "c3db64d1d2260340",
122
+ "type": "debug",
123
+ "z": "6312c0588348b2d4",
124
+ "name": "",
125
+ "active": true,
126
+ "tosidebar": true,
127
+ "console": false,
128
+ "tostatus": false,
129
+ "complete": "false",
130
+ "statusVal": "",
131
+ "statusType": "auto",
132
+ "x": 600,
133
+ "y": 260,
134
+ "wires": []
135
+ },
136
+ {
137
+ "id": "6d077dfa0987febb",
138
+ "type": "comment",
139
+ "z": "6312c0588348b2d4",
140
+ "name": "↑called from link call node",
141
+ "info": "",
142
+ "x": 410,
143
+ "y": 380,
144
+ "wires": []
145
+ },
146
+ {
147
+ "id": "53b9a0adfd8c4217",
148
+ "type": "comment",
149
+ "z": "6312c0588348b2d4",
150
+ "name": "↑return to link call node",
151
+ "info": "",
152
+ "x": 680,
153
+ "y": 380,
154
+ "wires": []
155
+ }
156
+ ]
@@ -2,7 +2,7 @@
2
2
  {
3
3
  "id": "84222b92.d65d18",
4
4
  "type": "inject",
5
- "z": "4b63452d.672afc",
5
+ "z": "6312c0588348b2d4",
6
6
  "name": "",
7
7
  "props": [
8
8
  {
@@ -20,8 +20,8 @@
20
20
  "topic": "",
21
21
  "payload": "Hello, World!",
22
22
  "payloadType": "str",
23
- "x": 230,
24
- "y": 200,
23
+ "x": 190,
24
+ "y": 180,
25
25
  "wires": [
26
26
  [
27
27
  "b4b9f603.739598"
@@ -31,25 +31,25 @@
31
31
  {
32
32
  "id": "7b014430.dfd94c",
33
33
  "type": "comment",
34
- "z": "4b63452d.672afc",
34
+ "z": "6312c0588348b2d4",
35
35
  "name": "Write string to a file, then read from the file",
36
- "info": "File node can write string to a file.",
37
- "x": 260,
38
- "y": 120,
36
+ "info": "Read file node can read string from a file.",
37
+ "x": 220,
38
+ "y": 100,
39
39
  "wires": []
40
40
  },
41
41
  {
42
42
  "id": "b4b9f603.739598",
43
43
  "type": "file",
44
- "z": "4b63452d.672afc",
44
+ "z": "6312c0588348b2d4",
45
45
  "name": "",
46
46
  "filename": "/tmp/hello.txt",
47
47
  "appendNewline": true,
48
48
  "createDir": false,
49
49
  "overwriteFile": "true",
50
50
  "encoding": "none",
51
- "x": 420,
52
- "y": 200,
51
+ "x": 380,
52
+ "y": 180,
53
53
  "wires": [
54
54
  [
55
55
  "6dc01cac.5c4bf4"
@@ -59,7 +59,7 @@
59
59
  {
60
60
  "id": "2587adb9.7e60f2",
61
61
  "type": "debug",
62
- "z": "4b63452d.672afc",
62
+ "z": "6312c0588348b2d4",
63
63
  "name": "",
64
64
  "active": true,
65
65
  "tosidebar": true,
@@ -68,22 +68,22 @@
68
68
  "complete": "false",
69
69
  "statusVal": "",
70
70
  "statusType": "auto",
71
- "x": 810,
72
- "y": 200,
71
+ "x": 770,
72
+ "y": 180,
73
73
  "wires": []
74
74
  },
75
75
  {
76
76
  "id": "6dc01cac.5c4bf4",
77
77
  "type": "file in",
78
- "z": "4b63452d.672afc",
78
+ "z": "6312c0588348b2d4",
79
79
  "name": "",
80
80
  "filename": "/tmp/hello.txt",
81
81
  "format": "utf8",
82
82
  "chunk": false,
83
83
  "sendError": false,
84
84
  "encoding": "none",
85
- "x": 620,
86
- "y": 200,
85
+ "x": 580,
86
+ "y": 180,
87
87
  "wires": [
88
88
  [
89
89
  "2587adb9.7e60f2"
@@ -93,21 +93,21 @@
93
93
  {
94
94
  "id": "f4b4309a.3b78a",
95
95
  "type": "comment",
96
- "z": "4b63452d.672afc",
96
+ "z": "6312c0588348b2d4",
97
97
  "name": "↑read result from file",
98
98
  "info": "",
99
- "x": 630,
100
- "y": 240,
99
+ "x": 590,
100
+ "y": 220,
101
101
  "wires": []
102
102
  },
103
103
  {
104
104
  "id": "672d3693.3cabd8",
105
105
  "type": "comment",
106
- "z": "4b63452d.672afc",
106
+ "z": "6312c0588348b2d4",
107
107
  "name": "↓write to /tmp/hello.txt",
108
108
  "info": "",
109
- "x": 440,
110
- "y": 160,
109
+ "x": 400,
110
+ "y": 140,
111
111
  "wires": []
112
112
  }
113
113
  ]