basic-ftp
Advanced tools
Comparing version 2.12.3 to 2.13.0
# Changelog | ||
## 2.13.0 | ||
- Added: Use client.rename() to rename or move a file. | ||
- Changed: Default timeout set to 30 seconds. | ||
- Changed: Timeouts are tracked exlusively by data connection during transfer. | ||
- Fixed: Node's socket.removeAllListeners() doesn't work, see https://github.com/nodejs/node/issues/20923 | ||
- Fixed: Node 8 is required, correct documentation and CI. | ||
## 2.12.3 | ||
@@ -4,0 +12,0 @@ |
@@ -40,5 +40,5 @@ "use strict"; | ||
* | ||
* @param {number} [timeout=0] Timeout in milliseconds, use 0 for no timeout. | ||
* @param {number} [timeout=30000] Timeout in milliseconds, use 0 for no timeout. | ||
*/ | ||
constructor(timeout = 0) { | ||
constructor(timeout = 30000) { | ||
this.ftp = new FTPContext(timeout); | ||
@@ -239,2 +239,17 @@ this.prepareTransfer = prepareTransferAutoDetect; | ||
/** | ||
* Rename a file. | ||
* | ||
* Depending on the FTP server this might also be used to move a file from one | ||
* directory to another by providing full paths. | ||
* | ||
* @param {string} path | ||
* @param {string} newPath | ||
* @returns {Promise<PositiveResponse>} response of second command (RNTO) | ||
*/ | ||
async rename(path, newPath) { | ||
await this.send("RNFR " + path); | ||
return await this.send("RNTO " + newPath); | ||
} | ||
/** | ||
* Remove a file from the current working directory. | ||
@@ -520,4 +535,4 @@ * | ||
else { | ||
// Remove any listeners we set up here, e.g. error listener below. | ||
tlsSocket.removeAllListeners(); | ||
// Remove error listener below. | ||
tlsSocket.removeAllListeners("error"); | ||
resolve(tlsSocket); | ||
@@ -690,3 +705,3 @@ } | ||
*/ | ||
function upload(ftp, progress, readableStream, remoteFilename) { | ||
function upload(ftp, progress, readableStream, remoteFilename) { | ||
const resolver = new TransferResolver(ftp); | ||
@@ -701,5 +716,7 @@ const command = "STOR " + remoteFilename; | ||
ftp.log(`Uploading (${describeTLS(ftp.dataSocket)})`); | ||
ftp.suspendControlTimeout(true); | ||
progress.start(ftp.dataSocket, remoteFilename, "upload"); | ||
readableStream.pipe(ftp.dataSocket).once("finish", () => { | ||
ftp.dataSocket.destroy(); // Explicitly close/destroy the socket to signal the end. | ||
ftp.suspendControlTimeout(false); | ||
progress.updateAndStop(); | ||
@@ -714,2 +731,3 @@ resolver.confirm(task); | ||
else if (res.code >= 400 || res.error) { | ||
ftp.suspendControlTimeout(false); | ||
progress.updateAndStop(); | ||
@@ -739,2 +757,3 @@ resolver.reject(task, res); | ||
ftp.log(`Downloading (${describeTLS(ftp.dataSocket)})`); | ||
ftp.suspendControlTimeout(true); | ||
progress.start(ftp.dataSocket, remoteFilename, "download"); | ||
@@ -746,2 +765,3 @@ // Confirm the transfer as soon as the data socket transmission ended. | ||
conditionOrEvent(ftp.dataSocket.destroyed, ftp.dataSocket, "end", () => { | ||
ftp.suspendControlTimeout(false); | ||
progress.updateAndStop(); | ||
@@ -758,2 +778,3 @@ resolver.confirm(task); | ||
else if (res.code >= 400 || res.error) { | ||
ftp.suspendControlTimeout(false); | ||
progress.updateAndStop(); | ||
@@ -760,0 +781,0 @@ resolver.reject(task, res); |
@@ -59,3 +59,6 @@ "use strict"; | ||
if (this._socket) { | ||
this._socket.removeAllListeners(); | ||
// socket.removeAllListeners() without name doesn't work: https://github.com/nodejs/node/issues/20923 | ||
this._socket.removeAllListeners("timeout"); | ||
this._socket.removeAllListeners("data"); | ||
this._socket.removeAllListeners("error"); | ||
} | ||
@@ -66,10 +69,4 @@ if (socket) { | ||
socket.on("data", data => this._onControlSocketData(data)); | ||
socket.once("error", error => { | ||
this._passToHandler({ error }); | ||
this.socket = undefined; | ||
}); | ||
socket.once("timeout", () => { | ||
this._passToHandler({ error: "Timeout control socket" }); | ||
this.socket = undefined; | ||
}); | ||
socket.once("error", error => this._closeWithError(error)); | ||
socket.once("timeout", () => this._closeWithError("Timeout control connection")); | ||
} | ||
@@ -96,10 +93,4 @@ else { | ||
socket.setTimeout(this._timeout); | ||
socket.once("error", error => { | ||
this._passToHandler({ error }); | ||
this.dataSocket = undefined; | ||
}); | ||
socket.once("timeout", () => { | ||
this._passToHandler({ error: "Timeout data socket" }); | ||
this.dataSocket = undefined; | ||
}); | ||
socket.once("error", error => this._closeWithError(error)); | ||
socket.once("timeout", () => this._closeWithError("Timeout data connection")); | ||
} | ||
@@ -172,2 +163,13 @@ this._dataSocket = socket; | ||
/** | ||
* Suspend timeout on the control socket connection. This can be useful if | ||
* a timeout should be caught by the current data connection instead of the | ||
* control connection that sits idle during transfers anyway. | ||
* | ||
* @param {boolean} suspended | ||
*/ | ||
suspendControlTimeout(suspended) { | ||
this.socket.setTimeout(suspended ? 0 : this._timeout); | ||
} | ||
/** | ||
* Handle incoming data on the control socket. | ||
@@ -207,2 +209,12 @@ * | ||
/** | ||
* Send an error to the current handler and close all connections. | ||
* | ||
* @param {*} error | ||
*/ | ||
_closeWithError(error) { | ||
this._passToHandler({ error }); | ||
this.close(); | ||
} | ||
/** | ||
* Close a socket. | ||
@@ -216,5 +228,8 @@ * | ||
socket.destroy(); | ||
socket.removeAllListeners(); | ||
// socket.removeAllListeners() without name doesn't work: https://github.com/nodejs/node/issues/20923 | ||
socket.removeAllListeners("timeout"); | ||
socket.removeAllListeners("data"); | ||
socket.removeAllListeners("error"); | ||
} | ||
} | ||
}; |
{ | ||
"name": "basic-ftp", | ||
"version": "2.12.3", | ||
"version": "2.13.0", | ||
"description": "FTP client for Node.js with support for explicit FTPS over TLS.", | ||
@@ -27,3 +27,3 @@ "main": "./lib/ftp", | ||
"engines": { | ||
"node": ">=7.6.0" | ||
"node": ">=8.0.0" | ||
}, | ||
@@ -30,0 +30,0 @@ "devDependencies": { |
@@ -9,3 +9,3 @@ # Basic FTP | ||
Node 7.6 or later is the only dependency. | ||
Node 8.0 or later is the only dependency. | ||
@@ -57,5 +57,5 @@ ## Introduction | ||
`new Client(timeout = 0)` | ||
`new Client(timeout = 30000)` | ||
Create a client instance using an optional timeout in milliseconds that will be used for control and data connections. Use 0 to disable timeouts. | ||
Create a client instance using an optional timeout in milliseconds that will be used for control and data connections. Use 0 to disable timeouts, default is 30 seconds. | ||
@@ -125,2 +125,6 @@ `close()` | ||
`rename(path, newPath): Promise<Response>` | ||
Rename a file. Depending on the server you may also use this to move a file to another directory by providing full paths. | ||
`remove(filename, ignoreErrorCodes = false): Promise<Response>` | ||
@@ -127,0 +131,0 @@ |
@@ -36,3 +36,3 @@ const assert = require("assert"); | ||
ftp.handle(undefined, (res, task) => { | ||
assert.deepEqual(res, { error: "Timeout control socket" }); | ||
assert.deepEqual(res, { error: "Timeout control connection" }); | ||
done(); | ||
@@ -53,3 +53,3 @@ }); | ||
ftp.handle(undefined, (res, task) => { | ||
assert.deepEqual(res, { error: "Timeout data socket" }); | ||
assert.deepEqual(res, { error: "Timeout data connection" }); | ||
done(); | ||
@@ -56,0 +56,0 @@ }); |
107568
2331
305