fix: explicitly promisify fs methods
`promisifyAll` will throw if a method with the suffix `Async` already exists. Fixes: https://github.com/trs/ftp-srv/pull/159
This commit is contained in:
37
src/fs.js
37
src/fs.js
@@ -2,13 +2,14 @@ const _ = require('lodash');
|
|||||||
const nodePath = require('path');
|
const nodePath = require('path');
|
||||||
const uuid = require('uuid');
|
const uuid = require('uuid');
|
||||||
const Promise = require('bluebird');
|
const Promise = require('bluebird');
|
||||||
const fs = Promise.promisifyAll(require('fs'));
|
const {createReadStream, createWriteStream, constants} = require('fs');
|
||||||
|
const fsAsync = require('./helpers/fs-async');
|
||||||
const errors = require('./errors');
|
const errors = require('./errors');
|
||||||
|
|
||||||
class FileSystem {
|
class FileSystem {
|
||||||
constructor(connection, {root, cwd} = {}) {
|
constructor(connection, {root, cwd} = {}) {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.cwd = cwd ? nodePath.join(nodePath.sep, cwd) : nodePath.sep;
|
this.cwd = nodePath.normalize(cwd ? nodePath.join(nodePath.sep, cwd) : nodePath.sep);
|
||||||
this._root = nodePath.resolve(root || process.cwd());
|
this._root = nodePath.resolve(root || process.cwd());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ class FileSystem {
|
|||||||
|
|
||||||
const fsPath = (() => {
|
const fsPath = (() => {
|
||||||
const resolvedPath = nodePath.join(this.root, clientPath);
|
const resolvedPath = nodePath.join(this.root, clientPath);
|
||||||
return nodePath.resolve(nodePath.join(resolvedPath));
|
return nodePath.resolve(nodePath.normalize(nodePath.join(resolvedPath)));
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -43,19 +44,19 @@ class FileSystem {
|
|||||||
|
|
||||||
get(fileName) {
|
get(fileName) {
|
||||||
const {fsPath} = this._resolvePath(fileName);
|
const {fsPath} = this._resolvePath(fileName);
|
||||||
return fs.statAsync(fsPath)
|
return fsAsync.stat(fsPath)
|
||||||
.then((stat) => _.set(stat, 'name', fileName));
|
.then((stat) => _.set(stat, 'name', fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
list(path = '.') {
|
list(path = '.') {
|
||||||
const {fsPath} = this._resolvePath(path);
|
const {fsPath} = this._resolvePath(path);
|
||||||
return fs.readdirAsync(fsPath)
|
return fsAsync.readdir(fsPath)
|
||||||
.then((fileNames) => {
|
.then((fileNames) => {
|
||||||
return Promise.map(fileNames, (fileName) => {
|
return Promise.map(fileNames, (fileName) => {
|
||||||
const filePath = nodePath.join(fsPath, fileName);
|
const filePath = nodePath.join(fsPath, fileName);
|
||||||
return fs.accessAsync(filePath, fs.constants.F_OK)
|
return fsAsync.access(filePath, constants.F_OK)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return fs.statAsync(filePath)
|
return fsAsync.stat(filePath)
|
||||||
.then((stat) => _.set(stat, 'name', fileName));
|
.then((stat) => _.set(stat, 'name', fileName));
|
||||||
})
|
})
|
||||||
.catch(() => null);
|
.catch(() => null);
|
||||||
@@ -66,7 +67,7 @@ class FileSystem {
|
|||||||
|
|
||||||
chdir(path = '.') {
|
chdir(path = '.') {
|
||||||
const {fsPath, clientPath} = this._resolvePath(path);
|
const {fsPath, clientPath} = this._resolvePath(path);
|
||||||
return fs.statAsync(fsPath)
|
return fsAsync.stat(fsPath)
|
||||||
.tap((stat) => {
|
.tap((stat) => {
|
||||||
if (!stat.isDirectory()) throw new errors.FileSystemError('Not a valid directory');
|
if (!stat.isDirectory()) throw new errors.FileSystemError('Not a valid directory');
|
||||||
})
|
})
|
||||||
@@ -78,8 +79,8 @@ class FileSystem {
|
|||||||
|
|
||||||
write(fileName, {append = false, start = undefined} = {}) {
|
write(fileName, {append = false, start = undefined} = {}) {
|
||||||
const {fsPath, clientPath} = this._resolvePath(fileName);
|
const {fsPath, clientPath} = this._resolvePath(fileName);
|
||||||
const stream = fs.createWriteStream(fsPath, {flags: !append ? 'w+' : 'a+', start});
|
const stream = createWriteStream(fsPath, {flags: !append ? 'w+' : 'a+', start});
|
||||||
stream.once('error', () => fs.unlinkAsync(fsPath));
|
stream.once('error', () => fsAsync.unlink(fsPath));
|
||||||
stream.once('close', () => stream.end());
|
stream.once('close', () => stream.end());
|
||||||
return {
|
return {
|
||||||
stream,
|
stream,
|
||||||
@@ -89,12 +90,12 @@ class FileSystem {
|
|||||||
|
|
||||||
read(fileName, {start = undefined} = {}) {
|
read(fileName, {start = undefined} = {}) {
|
||||||
const {fsPath, clientPath} = this._resolvePath(fileName);
|
const {fsPath, clientPath} = this._resolvePath(fileName);
|
||||||
return fs.statAsync(fsPath)
|
return fsAsync.stat(fsPath)
|
||||||
.tap((stat) => {
|
.tap((stat) => {
|
||||||
if (stat.isDirectory()) throw new errors.FileSystemError('Cannot read a directory');
|
if (stat.isDirectory()) throw new errors.FileSystemError('Cannot read a directory');
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const stream = fs.createReadStream(fsPath, {flags: 'r', start});
|
const stream = createReadStream(fsPath, {flags: 'r', start});
|
||||||
return {
|
return {
|
||||||
stream,
|
stream,
|
||||||
clientPath
|
clientPath
|
||||||
@@ -104,28 +105,28 @@ class FileSystem {
|
|||||||
|
|
||||||
delete(path) {
|
delete(path) {
|
||||||
const {fsPath} = this._resolvePath(path);
|
const {fsPath} = this._resolvePath(path);
|
||||||
return fs.statAsync(fsPath)
|
return fsAsync.stat(fsPath)
|
||||||
.then((stat) => {
|
.then((stat) => {
|
||||||
if (stat.isDirectory()) return fs.rmdirAsync(fsPath);
|
if (stat.isDirectory()) return fsAsync.rmdir(fsPath);
|
||||||
else return fs.unlinkAsync(fsPath);
|
else return fsAsync.unlink(fsPath);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
mkdir(path) {
|
mkdir(path) {
|
||||||
const {fsPath} = this._resolvePath(path);
|
const {fsPath} = this._resolvePath(path);
|
||||||
return fs.mkdirAsync(fsPath)
|
return fsAsync.mkdir(fsPath)
|
||||||
.then(() => fsPath);
|
.then(() => fsPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
rename(from, to) {
|
rename(from, to) {
|
||||||
const {fsPath: fromPath} = this._resolvePath(from);
|
const {fsPath: fromPath} = this._resolvePath(from);
|
||||||
const {fsPath: toPath} = this._resolvePath(to);
|
const {fsPath: toPath} = this._resolvePath(to);
|
||||||
return fs.renameAsync(fromPath, toPath);
|
return fsAsync.rename(fromPath, toPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
chmod(path, mode) {
|
chmod(path, mode) {
|
||||||
const {fsPath} = this._resolvePath(path);
|
const {fsPath} = this._resolvePath(path);
|
||||||
return fs.chmodAsync(fsPath, mode);
|
return fsAsync.chmod(fsPath, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
getUniqueName() {
|
getUniqueName() {
|
||||||
|
|||||||
18
src/helpers/fs-async.js
Normal file
18
src/helpers/fs-async.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const {promisify} = require('bluebird');
|
||||||
|
|
||||||
|
const methods = [
|
||||||
|
'stat',
|
||||||
|
'readdir',
|
||||||
|
'access',
|
||||||
|
'unlink',
|
||||||
|
'rmdir',
|
||||||
|
'mkdir',
|
||||||
|
'rename',
|
||||||
|
'chmod'
|
||||||
|
];
|
||||||
|
|
||||||
|
module.exports = methods.reduce((obj, method) => {
|
||||||
|
obj[method] = promisify(fs[method]);
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
Reference in New Issue
Block a user