From 0a0d2632743de448b92d21f3f7d3bb904fce577f Mon Sep 17 00:00:00 2001 From: Sergi Mansilla Date: Mon, 5 May 2014 11:25:15 +0200 Subject: [PATCH] Add debug mode and some style changes. Fixes #87. --- README.md | 48 ++++++++++++++++++++++++++++++++++ lib/jsftp.js | 64 ++++++++++++++++++++++++++++++---------------- test/jsftp_test.js | 17 ++++++++++++ 3 files changed, 107 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 1583180..9968d63 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,54 @@ Refreshes the interval thats keep the server connection active. `wait` is an opt You can find more usage examples in the [unit tests](https://github.com/sergi/jsftp/blob/master/test/jsftp_test.js). This documentation will grow as jsftp evolves. + +Debugging +--------- + +In order to enable debug mode in a FTP connection, a `debugMode` parameter can +be used in the constructors's config object: + +```javascript +var Ftp = new JSFtp({ + host: "myserver.com", + port: 3331, + user: "user", + pass: "1234", + debugMode: true +}); +``` + +It can also be activated or deactivated by calling the `setDebugMode` method: + +```javascript +Ftp.setDebugMode(true); // Debug Mode on +Ftp.setDebugMode(false; // Debug mode off +``` + +If the debug mode is on, the jsftp instance will emit `jsftp_debug` events with +two parameters: the first is the type of the event and the second and object +including data related to the event. There are 3 possible types of events: + +- `response` events: These are response from the FTP server to the user's FTP + commands + +- `user_command` events: These are commands that the user issuendss to the + FTP server. + +- `event:{event name}` events: These are other events mostly related to the server + connection, such as `timeout`, `connect` or `disconnect`. For example, + a timeout event will have the name `event:timeout`. + +In order to react to print all debug events (for example), we would listen to the +debug messages like this: + +```javascript +Ftp.on('jsftp_debug', function(eventType, data) { + console.log('DEBUG: ', eventType); + console.log(JSON.stringify(data, null, 2)); +}); +``` + Installation ------------ diff --git a/lib/jsftp.js b/lib/jsftp.js index ea90478..a429ab1 100644 --- a/lib/jsftp.js +++ b/lib/jsftp.js @@ -17,7 +17,6 @@ var fs = require("fs"); var once = require("once"); var FTP_PORT = 21; -var DEBUG_MODE = false; var TIMEOUT = 10 * 60 * 1000; var IDLE_TIME = 30000; var NOOP = function() {}; @@ -31,14 +30,17 @@ var COMMANDS = [ "chmod", "size" ]; -function getPasvPort(text) { +function getPasvPort(text, cb) { var RE_PASV = /([-\d]+,[-\d]+,[-\d]+,[-\d]+),([-\d]+),([-\d]+)/; var match = RE_PASV.exec(text); - if (!match) return false; + if (!match) { + return cb(new Error("Bad passive host/port combination")); + } - // Array containing the passive host and the port number - return [match[1].replace(/,/g, "."), - (parseInt(match[2], 10) & 255) * 256 + (parseInt(match[3], 10) & 255)]; + cb(null, { + host: match[1].replace(/,/g, "."), + port: (parseInt(match[2], 10) & 255) * 256 + (parseInt(match[3], 10) & 255) + }); } function runCmd(cmd) { @@ -75,21 +77,37 @@ var Ftp = module.exports = function(cfg) { // Generate generic methods from parameter names. they can easily be // overriden if we need special behavior. they accept any parameters given, // it is the responsability of the user to validate the parameters. - this.raw = function () { + this.raw = function() { return runCmd.apply(this, arguments); }.bind(this); COMMANDS.forEach(function(cmd) { this.raw[cmd] = runCmd.bind(this, cmd); }, this); + var self = this; + this.on('data', function(data) { + if (self.debugMode) { + self.emit('jsftp_debug', 'response', data || {}); + } + }); + this.socket = this._createSocket(this.port, this.host); }; util.inherits(Ftp, EventEmitter); +Ftp.prototype.setDebugMode = function(debugOn) { + this.debugMode = (debugOn !== false); +}; + Ftp.prototype.reemit = function(event) { var self = this; - return function(data) { self.emit(event, data); } + return function(data) { + self.emit(event, data); + if (self.debugMode) { + self.emit('jsftp_debug', 'event:' + event, data || {}); + } + } }; Ftp.prototype._createSocket = function(port, host, firstAction) { @@ -155,6 +173,10 @@ Ftp.prototype.send = function(command) { this.emit("cmdSend", command); this.pipeline.write(command + "\r\n"); + + if (this.debugMode) { + this.emit('jsftp_debug', 'user_command', command || {}); + } }; Ftp.prototype.nextCmd = function() { @@ -489,11 +511,11 @@ Ftp.prototype.put = function(from, to, callback) { return callback(new Error("Local file doesn't exist.")); fs.stat(from, function(err, stats) { - var totalSize = err ? 0 : stats.size; - var read = fs.createReadStream(from, { - bufferSize: 4 * 1024 - }); - putReadable(read, to, totalSize, callback); + var totalSize = err ? 0 : stats.size; + var read = fs.createReadStream(from, { + bufferSize: 4 * 1024 + }); + putReadable(read, to, totalSize, callback); }); }); } else { @@ -546,7 +568,7 @@ Ftp.prototype.pasvTimeout = function(socket, cb) { socket.destroy(); cb(new Error("Passive socket timeout")); }); -} +}; Ftp.prototype.getPasvSocket = function(callback) { var timeout = this.timeout; @@ -554,15 +576,13 @@ Ftp.prototype.getPasvSocket = function(callback) { this.execute("pasv", function(err, res) { if (err) return callback(err); - var pasvRes = getPasvPort(res.text); - if (pasvRes === false) - return callback(new Error("PASV: Bad host/port combination")); + getPasvPort(res.text, function(err, res) { + if (err) return callback(err); - var host = pasvRes[0]; - var port = pasvRes[1]; - var socket = Net.createConnection(port, host); - socket.setTimeout(timeout || TIMEOUT); - callback(null, socket); + var socket = Net.createConnection(res.port, res.host); + socket.setTimeout(timeout || TIMEOUT); + callback(null, socket); + }); }); }; diff --git a/test/jsftp_test.js b/test/jsftp_test.js index dab01af..b98b56b 100755 --- a/test/jsftp_test.js +++ b/test/jsftp_test.js @@ -743,4 +743,21 @@ describe("jsftp test suite", function() { next(); }, 5000); }); + + it("Test debug mode", function(next) { + var debugCredentials = JSON.parse(JSON.stringify(FTPCredentials)); + debugCredentials.debugMode = true; + + var ftp2 = new Ftp(debugCredentials); + ftp2.once('jsftp_debug', function(type, data) { + next(); + }); + }); + + it("Test debug mode `setDebugMode`", function(next) { + ftp.setDebugMode(true); + ftp.once('jsftp_debug', function(type, data) { + next(); + }); + }); });