joeartsea / node-red-contrib-ftp Goto Github PK
View Code? Open in Web Editor NEWA Node-RED node to FTP Client
License: Apache License 2.0
A Node-RED node to FTP Client
License: Apache License 2.0
By setting msg.localFilename to a Buffer, this node can upload data without using a local file on the file system. This is a huge benefit, but it's not mentioned anywhere in the documentation. (This is ultimately a feature of the underlying ftp object.)
It would be even better for put operations only if the incoming payload were found to be a buffer, and localFilename were not set (evaluates to false), then the node internally sets localFilename to payload. This would make the property naming make more sense.
The GET option, like the PUT option should be exposing the Local Filename (msg.localFilename). This can be accomplished by editing ftp.html and change lines 133 from:
} else if (id == 'put') {
to:
} else if (id == 'put' || id == 'get') {
This will allow a user to specify the name of the file in the node itself.
Hello, I was in need of listing subdirectories within FTP and I ended up editing your ftp.js and ftp.html code, and implemented this option. If you are interested in using it to update your library, I think it would be interesting :)
Follows the code:
ftp.js:
module.exports = function (RED) {
'use strict';
var ftp = require('ftp');
var fs = require('fs');
function FtpNode(n) {
RED.nodes.createNode(this, n);
var node = this;
var credentials = RED.nodes.getCredentials(n.id);
this.options = {
'host': n.host || 'localhost',
'port': n.port || 21,
'secure': n.secure || false,
'secureOptions': n.secureOptions,
'user': n.user || 'anonymous',
'password': credentials.password || 'anonymous@',
'connTimeout': n.connTimeout || 10000,
'pasvTimeout': n.pasvTimeout || 10000,
'keepalive': n.keepalive || 10000
};
}
RED.nodes.registerType('ftp', FtpNode, {
credentials: {
password: { type: 'password' }
}
});
function FtpInNode(n) {
RED.nodes.createNode(this, n);
this.ftp = n.ftp;
this.operation = n.operation;
this.filename = n.filename;
this.localFilename = n.localFilename;
this.ftpConfig = RED.nodes.getNode(this.ftp);
if (this.ftpConfig) {
var node = this;
node.on('input', function (msg) {
var conn = new ftp();
var filename = node.filename || msg.filename || '';
var localFilename = node.localFilename || msg.localFilename || '';
this.sendMsg = function (err, result) {
if (err) {
node.error(err, msg);
node.status({ fill: 'red', shape: 'ring', text: 'failed' });
node.send(err);
return;
}
node.status({});
if (node.operation == 'get') {
result.once('close', function() { conn.end(); });
result.pipe(fs.createWriteStream(localFilename));
msg.payload = 'Get operation successful. ' + localFilename;
} else if (node.operation == 'put') {
conn.end();
msg.payload = 'Put operation successful.';
} else {
conn.end();
msg.message = 'Operation successful.';
msg.payload = result;
}
msg.filename = filename;
msg.localFilename = localFilename;
node.send(msg);
};
conn.on('ready', function () {
switch (node.operation) {
case 'list':
conn.list(filename, node.sendMsg);
break;
case 'get':
conn.get(filename, node.sendMsg);
break;
case 'put':
conn.put(localFilename, filename, node.sendMsg);
break;
case 'delete':
conn.delete(filename, node.sendMsg);
break;
}
});
conn.on('error', function(err) {
node.error(err, msg);
node.status({ fill: 'red', shape: 'ring', text: err.message });
node.send(err);
return;
});
conn.connect(node.ftpConfig.options);
});
} else {
this.error('missing ftp configuration');
}
}
RED.nodes.registerType('ftp in', FtpInNode);
}
ftp.html:
<script type="text/x-red" data-template-name="ftp">
<div class="form-row">
<label for="node-config-input-host"><i class="fa fa-bookmark"></i> Host</label>
<input type="text" id="node-config-input-host" placeholder="localhost" style="width: 40%;" />
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> Port</label>
<input type="text" id="node-config-input-port" placeholder="21" style="width:45px">
</div>
<div class="form-row">
<label for="node-config-input-user"><i class="fa fa-user"></i> User</label>
<input type="text" id="node-config-input-user" placeholder="anonymous" />
</div>
<div class="form-row">
<label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
<input type="password" id="node-config-input-password">
</div>
<div class="form-row">
<label for="node-config-input-connTimeout"><i class="fa fa-clock-o"></i> Connection Timeout</label>
<input type="text" id="node-config-input-connTimeout" placeholder="10000">
</div>
<div class="form-row">
<label for="node-config-input-pasvTimeout"><i class="fa fa-clock-o"></i> PASV Timeout</label>
<input type="text" id="node-config-input-pasvTimeout" placeholder="10000">
</div>
<div class="form-row">
<label for="node-config-input-keepalive"><i class="fa fa-clock-o"></i> Keepalive</label>
<input type="text" id="node-config-input-keepalive" placeholder="10000">
</div>
<div class="form-row">
<label for="node-input-secure"><i class="fa fa-key"></i> Data connection encryption</label>
<input type="checkbox" id="node-input-secure" placeholder="once" style="width: 10%; vertical-align: top;">
<label for="node-config-input-secureOptions" style="width: 20%; vertical-align: top;"> Secure Options</label>
<input type="text" id="node-config-input-secureOptions" style="width: 35%; vertical-align: top;">
</div>
</script>
<script type="text/x-red" data-help-name="ftp in">
<p>Allows LIST, GET, PUT and DELETE of files on a remote FTP server.</p>
<p><code>msg.filename</code> is the path/name of the file on the remote FTP server</p>
<p><code>msg.localFilename</code> is the path/name of the file on the local machine</p>
<p>NOTE: the local machine is where NR is running - this might not be the machine where your browser connects to Node Red.</p>
<p></p>
<p>GET uses <code>msg.filename</code> and <code>msg.localFilename</code></p>
<p>PUT uses <code>msg.filename</code> and <code>msg.localFilename</code></p>
<p>DELETE uses only <code>msg.filename</code></p>
<p>LIST uses only <code>msg.filename</code> and returns an array of the file/folders, containing type, name, sticky, rights(an object), acl, owner, group, size and date.</p>
<p></p>
<p>You can pass <code>msg.filename</code> and <code>msg.localFilename</code> to this node, however values entered in the node will take precedence.</p>
<p></p>
<p>If an error occurs, the error message will come out as <code>msg</code>.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('ftp', {
category: 'config',
color:"BurlyWood",
defaults: {
host: { value: '' },
port: { value: '' },
secure: { value: false },
secureOptions: { value: '' },
user: { value: '' },
connTimeout: { value: '' },
pasvTimeout: { value: '' },
keepalive: { value: '' }
},
credentials: {
password: { type: 'password', required: true },
},
label: function() {
return this.host
}
});
</script>
<script type="text/x-red" data-template-name="ftp in">
<div class="form-row">
<label for="node-input-ftp"><i class="fa fa-user"></i> Add new FTP Server</label>
<input type="text" id="node-input-ftp">
</div>
<div class="form-row">
<label for="node-input-operation"><i class="fa fa-wrench"></i> Operation</label>
<select type="text" id="node-input-operation">
<option value="list">list</option>
<option value="get">get</option>
<option value="put">put</option>
<option value="delete">delete</option>
</select>
</div>
<div class="form-row input-filename-row hidden">
<label for="node-input-filename"><i class="fa fa-file"></i> Filename</label>
<input type="text" id="node-input-filename" placeholder="Filename">
</div>
<div class="form-row input-localFilename-row hidden">
<label for="node-input-localFilename"><i class="fa fa-file"></i> Local Filename</label>
<input type="text" id="node-input-localFilename" placeholder="Local Filename">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('ftp in', {
category: 'storage-input',
color:"BurlyWood",
defaults: {
ftp: { type: 'ftp', required: true },
operation: { value: 'list', required: true },
filename: { value: '' },
localFilename: { value: '' },
name: { value: '' }
},
inputs: 1,
outputs: 1,
icon: "file.png",
label: function () {
var ftpNode = RED.nodes.node(this.ftp);
return this.name || 'ftp';
},
labelStyle: function () {
return this.name ? 'node_label_italic' : '';
},
oneditprepare: function () {
var filename = $(".input-filename-row");
var localFilename = $(".input-localFilename-row");
$("#node-input-operation").change(function () {
var id = $("#node-input-operation option:selected").val();
console.log(id);
if (id == 'list') {
filename.show();
localFilename.hide();
} else if (id == 'put' || id == 'get') {
filename.show();
localFilename.show();
} else {
filename.show();
localFilename.hide();
}
});
}
});
</script>
Thanks!
Hello, i have been working with this wonderful node but nothing seems to be working.
I configured the node to use the put function, but all it does is to create an empty file (0.0kb) with the "filename" on the ftp server.
Kindly advice on what to do to resolve this issue
error: TypeError: cannot read property ´Password´ of undefined.
Hi. I am currently working on a error logging flow. I collect all error and send a FTP via this node. However, when i trigger the node for the first time, it sends normally. But if i trigger second time, node puts twice, 3rd trigger puts thrice, on and on... This shouldn't be happen, because every time i send the data to FTP, i delete current log file. So, if ftp node puts consecutively, it cannot find a file.
What should i do?
The following could be used to add data help for the node. Edit ftp.html and after line 101 add the following:
<script type="text/x-red" data-help-name="ftp in">Allows LIST, GET, PUT and DELETE of files on a remote FTP server.
msg.filename
is the path/name of the file on the remote FTP server
msg.localFilename
is the path/name of the file on the local machine
NOTE: the local machine is where NR is running - this might not be the machine where your browser connects to Node Red.
GET uses msg.filename
and msg.localFilename
PUT uses msg.filename
and msg.localFilename
DELETE uses only msg.filename
LIST has no options and returns an array of the file/folders in the user's default ftp folder, containing type, name, sticky, rights(an object), acl, owner, group, size and date.
You can pass msg.filename
and msg.localFilename
to this node, however values entered in the node will take precedence.
The following would be helpful if added to the README.md
This node will allow you to LIST, GET, PUT and DELETE files on a remote FTP server. The GET and PUT options use msg.filename (the path/name of the file on the remote machine) and msg.localFilename (the path/name of the file on the local machine - i.e. the one running NR).
The DELETE option only specifies msg.filename (the path/name of the file on the remote machine)
The LIST option returns an array of the file/folders in the user's default ftp folder, containing
type, name, sticky, rights(an object), acl, owner, group, size and date.
Hi,
Just wondering if you have any plans to add SFTP support?
Thanks
Hello, I am trying to control the sequence in which files are put to an ftp server. Out of an array from which I get sorted filenames the files must arrive in the same sequence like the order inside of the array.
The node that is placed before the ftp node contains this:
Using this, the files seem to be sent almost in parallel and the sequence in which they arrive at the destination is unpredictable.
Is there a way how I can make sure, the files arrive in the same sequence as they are send?
Thanks..
Matthias
How can I do a list
on a sub-folder please, ideally with a filter. e.g.
dir anon/www/test/*.gif
Hi there!
I was wondering whether you could maybe add or supply a guide on exactly how to use the node and what to insert where, like a usage file or description? I have been trying to use the node to upload a file to a ftp server but it is either not doing anything or disconnecting me from my own server. I am really struggling with this and really hope you can assist me. I am not entirely sure how to use it.
It will be much appreciated
If you try to GET a nonexistent file, Node Red will crash with the following:
20 Jul 05:13:29 - [info] Node-RED version: v0.17.4
20 Jul 05:13:29 - [info] Node.js version: v6.11.0
20 Jul 05:13:29 - [info] Darwin 15.6.0 x64 LE
<...snip...>
20 Jul 05:14:02 - [red] Uncaught Exception:
20 Jul 05:14:02 - TypeError: Cannot read property 'once' of undefined
at sendMsg (/Users/Paul/.node-red/node_modules/node-red-contrib-ftp/ftp.js:66:19)
at Object.cb (/Users/Paul/.node-red/node_modules/ftp/lib/connection.js:606:15)
at Parser. (/Users/Paul/.node-red/node_modules/ftp/lib/connection.js:113:22)
at emitTwo (events.js:106:13)
at Parser.emit (events.js:191:7)
at Parser._write (/Users/Paul/.node-red/node_modules/ftp/lib/parser.js:59:10)
at doWrite (_stream_writable.js:331:12)
at writeOrBuffer (_stream_writable.js:317:5)
at Parser.Writable.write (_stream_writable.js:243:11)
at Socket.ondata (/Users/Paul/.node-red/node_modules/ftp/lib/connection.js:273:20)
Pauls-mini:.node-red Paul$
note: NR running on a Mac
i am planning to setup a flow that every min get one file which names yyyymmddhhmmss.dat
like 201907102301.dat 201907102302.dat
i use inject every min and funtion to make the filenames
how can i pass the filename to ftp get the files
thank you
I am using ftp node to send a different file to a remote server every 10 mins. Each time i inject a true, it sends the present file along with the previous sent files. This issue gets cleared after clicking the Deploy button but again ftp sends two files at the second inject and three files at the third inject.
At the input end of the ftp only 1 message goes into the ftp node with filename and local filename. But I get multiple outputs. I attached my code in the mail. Can anyone please help
I have an application where I need to send files to a folder using ftp. If the folder does not exit, the file is not being sent . When i create a folder manually in my database server, the file is getting saved in it. (Put operation).
Can i make the ftp node to create the folder in the database server if the folder does not exit?
If I use an FTP In node to Get a file that does not exist, the connection is never closed.
Looking at the callback code for handling errors:
this.sendMsg = function (err, result) {
if (err) {
node.error(err, msg);
node.status({ fill: 'red', shape: 'ring', text: 'failed' });
return;
}
the node returns when there is an error without calling conn.end()
to close the connection.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.