mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
refactor: async/await file
This commit is contained in:
@@ -12,7 +12,8 @@ const Translator = require('../translator').Translator;
|
|||||||
function filterDirectories(directories) {
|
function filterDirectories(directories) {
|
||||||
return directories.map(function (dir) {
|
return directories.map(function (dir) {
|
||||||
// get the relative path
|
// get the relative path
|
||||||
return dir.replace(/^.*(admin.*?).tpl$/, '$1');
|
// convert dir to use forward slashes
|
||||||
|
return dir.replace(/^.*(admin.*?).tpl$/, '$1').split(path.sep).join('/');
|
||||||
}).filter(function (dir) {
|
}).filter(function (dir) {
|
||||||
// exclude .js files
|
// exclude .js files
|
||||||
// exclude partials
|
// exclude partials
|
||||||
|
|||||||
17
src/batch.js
17
src/batch.js
@@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
|
|
||||||
var db = require('./database');
|
const db = require('./database');
|
||||||
var utils = require('./utils');
|
const utils = require('./utils');
|
||||||
|
|
||||||
var DEFAULT_BATCH_SIZE = 100;
|
const DEFAULT_BATCH_SIZE = 100;
|
||||||
|
|
||||||
const sleep = util.promisify(setTimeout);
|
const sleep = util.promisify(setTimeout);
|
||||||
|
|
||||||
@@ -32,8 +32,8 @@ exports.processSortedSet = async function (setKey, process, options) {
|
|||||||
// custom done condition
|
// custom done condition
|
||||||
options.doneIf = typeof options.doneIf === 'function' ? options.doneIf : function () {};
|
options.doneIf = typeof options.doneIf === 'function' ? options.doneIf : function () {};
|
||||||
|
|
||||||
var start = 0;
|
let start = 0;
|
||||||
var stop = options.batch;
|
let stop = options.batch;
|
||||||
|
|
||||||
if (process && process.constructor && process.constructor.name !== 'AsyncFunction') {
|
if (process && process.constructor && process.constructor.name !== 'AsyncFunction') {
|
||||||
process = util.promisify(process);
|
process = util.promisify(process);
|
||||||
@@ -66,14 +66,14 @@ exports.processArray = async function (array, process, options) {
|
|||||||
throw new Error('[[error:process-not-a-function]]');
|
throw new Error('[[error:process-not-a-function]]');
|
||||||
}
|
}
|
||||||
|
|
||||||
var batch = options.batch || DEFAULT_BATCH_SIZE;
|
const batch = options.batch || DEFAULT_BATCH_SIZE;
|
||||||
var start = 0;
|
let start = 0;
|
||||||
if (process && process.constructor && process.constructor.name !== 'AsyncFunction') {
|
if (process && process.constructor && process.constructor.name !== 'AsyncFunction') {
|
||||||
process = util.promisify(process);
|
process = util.promisify(process);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
var currentBatch = array.slice(start, start + batch);
|
const currentBatch = array.slice(start, start + batch);
|
||||||
|
|
||||||
if (!currentBatch.length) {
|
if (!currentBatch.length) {
|
||||||
return;
|
return;
|
||||||
@@ -88,4 +88,5 @@ exports.processArray = async function (array, process, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
require('./promisify')(exports);
|
require('./promisify')(exports);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
var nconf = require('nconf');
|
const nconf = require('nconf');
|
||||||
var meta = require('./meta');
|
const meta = require('./meta');
|
||||||
|
|
||||||
var coverPhoto = module.exports;
|
const coverPhoto = module.exports;
|
||||||
|
|
||||||
coverPhoto.getDefaultGroupCover = function (groupName) {
|
coverPhoto.getDefaultGroupCover = function (groupName) {
|
||||||
return getCover('groups', groupName);
|
return getCover('groups', groupName);
|
||||||
@@ -17,7 +17,7 @@ coverPhoto.getDefaultProfileCover = function (uid) {
|
|||||||
function getCover(type, id) {
|
function getCover(type, id) {
|
||||||
const defaultCover = nconf.get('relative_path') + '/assets/images/cover-default.png';
|
const defaultCover = nconf.get('relative_path') + '/assets/images/cover-default.png';
|
||||||
if (meta.config[type + ':defaultCovers']) {
|
if (meta.config[type + ':defaultCovers']) {
|
||||||
var covers = String(meta.config[type + ':defaultCovers']).trim().split(/[\s,]+/g);
|
const covers = String(meta.config[type + ':defaultCovers']).trim().split(/[\s,]+/g);
|
||||||
let coverPhoto = defaultCover;
|
let coverPhoto = defaultCover;
|
||||||
if (!covers.length) {
|
if (!covers.length) {
|
||||||
return coverPhoto;
|
return coverPhoto;
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ events.getEvents = async function (filter, start, stop, from, to) {
|
|||||||
event[key] = validator.escape(String(event[key] || ''));
|
event[key] = validator.escape(String(event[key] || ''));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var e = utils.merge(event);
|
const e = utils.merge(event);
|
||||||
e.eid = undefined;
|
e.eid = undefined;
|
||||||
e.uid = undefined;
|
e.uid = undefined;
|
||||||
e.type = undefined;
|
e.type = undefined;
|
||||||
|
|||||||
223
src/file.js
223
src/file.js
@@ -1,101 +1,54 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var fs = require('fs');
|
const fs = require('fs');
|
||||||
var nconf = require('nconf');
|
const nconf = require('nconf');
|
||||||
var path = require('path');
|
const path = require('path');
|
||||||
var winston = require('winston');
|
const winston = require('winston');
|
||||||
var mkdirp = require('mkdirp');
|
const mkdirp = require('mkdirp');
|
||||||
var mime = require('mime');
|
const mime = require('mime');
|
||||||
var graceful = require('graceful-fs');
|
const graceful = require('graceful-fs');
|
||||||
|
const util = require('util');
|
||||||
|
|
||||||
var utils = require('./utils');
|
const readdirAsync = util.promisify(fs.readdir);
|
||||||
|
const mkdirpAsync = util.promisify(mkdirp);
|
||||||
|
const copyFileAsync = util.promisify(fs.copyFile);
|
||||||
|
const writeFleAsync = util.promisify(fs.writeFile);
|
||||||
|
const statAsync = util.promisify(fs.stat);
|
||||||
|
const unlinkAsync = util.promisify(fs.unlink);
|
||||||
|
const linkAsync = util.promisify(fs.link);
|
||||||
|
const symlinkAsync = util.promisify(fs.symlink);
|
||||||
|
|
||||||
|
const utils = require('./utils');
|
||||||
|
|
||||||
graceful.gracefulify(fs);
|
graceful.gracefulify(fs);
|
||||||
|
|
||||||
var file = module.exports;
|
const file = module.exports;
|
||||||
|
|
||||||
/**
|
file.saveFileToLocal = async function (filename, folder, tempPath) {
|
||||||
* Asynchronously copies `src` to `dest`
|
|
||||||
* @param {string} src - source filename to copy
|
|
||||||
* @param {string} dest - destination filename of the copy operation
|
|
||||||
* @param {function(Error): void} callback
|
|
||||||
*/
|
|
||||||
function copyFile(src, dest, callback) {
|
|
||||||
var calledBack = false;
|
|
||||||
|
|
||||||
var read;
|
|
||||||
var write;
|
|
||||||
|
|
||||||
function done(err) {
|
|
||||||
if (calledBack) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
calledBack = true;
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
if (read) {
|
|
||||||
read.destroy();
|
|
||||||
}
|
|
||||||
if (write) {
|
|
||||||
write.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
read = fs.createReadStream(src);
|
|
||||||
read.on('error', done);
|
|
||||||
|
|
||||||
write = fs.createWriteStream(dest);
|
|
||||||
write.on('error', done);
|
|
||||||
write.on('close', function () {
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
read.pipe(write);
|
|
||||||
}
|
|
||||||
|
|
||||||
file.copyFile = (typeof fs.copyFile === 'function') ? fs.copyFile : copyFile;
|
|
||||||
|
|
||||||
file.saveFileToLocal = function (filename, folder, tempPath, callback) {
|
|
||||||
/*
|
/*
|
||||||
* remarkable doesn't allow spaces in hyperlinks, once that's fixed, remove this.
|
* remarkable doesn't allow spaces in hyperlinks, once that's fixed, remove this.
|
||||||
*/
|
*/
|
||||||
filename = filename.split('.').map(function (name) {
|
filename = filename.split('.').map(name => utils.slugify(name)).join('.');
|
||||||
return utils.slugify(name);
|
|
||||||
}).join('.');
|
|
||||||
|
|
||||||
var uploadPath = path.join(nconf.get('upload_path'), folder, filename);
|
const uploadPath = path.join(nconf.get('upload_path'), folder, filename);
|
||||||
|
|
||||||
winston.verbose('Saving file ' + filename + ' to : ' + uploadPath);
|
winston.verbose('Saving file ' + filename + ' to : ' + uploadPath);
|
||||||
mkdirp(path.dirname(uploadPath), function (err) {
|
await mkdirpAsync(path.dirname(uploadPath));
|
||||||
if (err) {
|
await copyFileAsync(tempPath, uploadPath);
|
||||||
return callback(err);
|
return {
|
||||||
}
|
url: '/assets/uploads/' + (folder ? folder + '/' : '') + filename,
|
||||||
|
path: uploadPath,
|
||||||
file.copyFile(tempPath, uploadPath, function (err) {
|
};
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(null, {
|
|
||||||
url: '/assets/uploads/' + (folder ? folder + '/' : '') + filename,
|
|
||||||
path: uploadPath,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
file.base64ToLocal = function (imageData, uploadPath, callback) {
|
file.base64ToLocal = async function (imageData, uploadPath) {
|
||||||
var buffer = Buffer.from(imageData.slice(imageData.indexOf('base64') + 7), 'base64');
|
const buffer = Buffer.from(imageData.slice(imageData.indexOf('base64') + 7), 'base64');
|
||||||
uploadPath = path.join(nconf.get('upload_path'), uploadPath);
|
uploadPath = path.join(nconf.get('upload_path'), uploadPath);
|
||||||
|
|
||||||
fs.writeFile(uploadPath, buffer, {
|
await writeFleAsync(uploadPath, buffer, {
|
||||||
encoding: 'base64',
|
encoding: 'base64',
|
||||||
}, function (err) {
|
|
||||||
callback(err, uploadPath);
|
|
||||||
});
|
});
|
||||||
|
return uploadPath;
|
||||||
};
|
};
|
||||||
|
|
||||||
file.isFileTypeAllowed = async function (path) {
|
file.isFileTypeAllowed = async function (path) {
|
||||||
@@ -111,7 +64,7 @@ file.isFileTypeAllowed = async function (path) {
|
|||||||
|
|
||||||
// https://stackoverflow.com/a/31205878/583363
|
// https://stackoverflow.com/a/31205878/583363
|
||||||
file.appendToFileName = function (filename, string) {
|
file.appendToFileName = function (filename, string) {
|
||||||
var dotIndex = filename.lastIndexOf('.');
|
const dotIndex = filename.lastIndexOf('.');
|
||||||
if (dotIndex === -1) {
|
if (dotIndex === -1) {
|
||||||
return filename + string;
|
return filename + string;
|
||||||
}
|
}
|
||||||
@@ -119,8 +72,8 @@ file.appendToFileName = function (filename, string) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
file.allowedExtensions = function () {
|
file.allowedExtensions = function () {
|
||||||
var meta = require('./meta');
|
const meta = require('./meta');
|
||||||
var allowedExtensions = (meta.config.allowedFileExtensions || '').trim();
|
let allowedExtensions = (meta.config.allowedFileExtensions || '').trim();
|
||||||
if (!allowedExtensions) {
|
if (!allowedExtensions) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -140,16 +93,16 @@ file.allowedExtensions = function () {
|
|||||||
return allowedExtensions;
|
return allowedExtensions;
|
||||||
};
|
};
|
||||||
|
|
||||||
file.exists = function (path, callback) {
|
file.exists = async function (path) {
|
||||||
fs.stat(path, function (err) {
|
try {
|
||||||
if (err) {
|
await statAsync(path);
|
||||||
if (err.code === 'ENOENT') {
|
} catch (err) {
|
||||||
return callback(null, false);
|
if (err.code === 'ENOENT') {
|
||||||
}
|
return false;
|
||||||
return callback(err);
|
|
||||||
}
|
}
|
||||||
callback(null, true);
|
throw err;
|
||||||
});
|
}
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
file.existsSync = function (path) {
|
file.existsSync = function (path) {
|
||||||
@@ -165,52 +118,40 @@ file.existsSync = function (path) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
file.delete = function (path, callback) {
|
file.delete = async function (path) {
|
||||||
callback = callback || function () {};
|
|
||||||
if (!path) {
|
if (!path) {
|
||||||
return setImmediate(callback);
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await unlinkAsync(path);
|
||||||
|
} catch (err) {
|
||||||
|
winston.warn(err);
|
||||||
}
|
}
|
||||||
fs.unlink(path, function (err) {
|
|
||||||
if (err) {
|
|
||||||
winston.warn(err);
|
|
||||||
}
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
file.link = function link(filePath, destPath, relative, callback) {
|
file.link = async function link(filePath, destPath, relative) {
|
||||||
if (!callback) {
|
|
||||||
callback = relative;
|
|
||||||
relative = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (relative && process.platform !== 'win32') {
|
if (relative && process.platform !== 'win32') {
|
||||||
filePath = path.relative(path.dirname(destPath), filePath);
|
filePath = path.relative(path.dirname(destPath), filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
fs.link(filePath, destPath, callback);
|
await linkAsync(filePath, destPath);
|
||||||
} else {
|
} else {
|
||||||
fs.symlink(filePath, destPath, 'file', callback);
|
await symlinkAsync(filePath, destPath, 'file');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
file.linkDirs = function linkDirs(sourceDir, destDir, relative, callback) {
|
file.linkDirs = async function linkDirs(sourceDir, destDir, relative) {
|
||||||
if (!callback) {
|
|
||||||
callback = relative;
|
|
||||||
relative = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (relative && process.platform !== 'win32') {
|
if (relative && process.platform !== 'win32') {
|
||||||
sourceDir = path.relative(path.dirname(destDir), sourceDir);
|
sourceDir = path.relative(path.dirname(destDir), sourceDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
var type = (process.platform === 'win32') ? 'junction' : 'dir';
|
const type = (process.platform === 'win32') ? 'junction' : 'dir';
|
||||||
fs.symlink(sourceDir, destDir, type, callback);
|
await symlinkAsync(sourceDir, destDir, type);
|
||||||
};
|
};
|
||||||
|
|
||||||
file.typeToExtension = function (type) {
|
file.typeToExtension = function (type) {
|
||||||
var extension;
|
let extension = '';
|
||||||
if (type) {
|
if (type) {
|
||||||
extension = '.' + mime.getExtension(type);
|
extension = '.' + mime.getExtension(type);
|
||||||
}
|
}
|
||||||
@@ -218,46 +159,14 @@ file.typeToExtension = function (type) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Adapted from http://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search
|
// Adapted from http://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search
|
||||||
file.walk = function (dir, callback) {
|
file.walk = async function (dir) {
|
||||||
var results = [];
|
const subdirs = await readdirAsync(dir);
|
||||||
|
const files = await Promise.all(subdirs.map(async (subdir) => {
|
||||||
fs.readdir(dir, function (err, list) {
|
const res = path.resolve(dir, subdir);
|
||||||
if (err) {
|
return (await statAsync(res)).isDirectory() ? file.walk(res) : res;
|
||||||
return callback(err);
|
}));
|
||||||
}
|
var result = files.reduce((a, f) => a.concat(f), []);
|
||||||
var pending = list.length;
|
return result;
|
||||||
if (!pending) {
|
|
||||||
return callback(null, results);
|
|
||||||
}
|
|
||||||
list.forEach(function (filename) {
|
|
||||||
filename = dir + '/' + filename;
|
|
||||||
fs.stat(filename, function (err, stat) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stat && stat.isDirectory()) {
|
|
||||||
file.walk(filename, function (err, res) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
results = results.concat(res);
|
|
||||||
pending -= 1;
|
|
||||||
if (!pending) {
|
|
||||||
callback(null, results);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
results.push(filename);
|
|
||||||
pending -= 1;
|
|
||||||
if (!pending) {
|
|
||||||
callback(null, results);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
require('./promisify')(file);
|
require('./promisify')(file);
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ JS.scripts = {
|
|||||||
|
|
||||||
function linkIfLinux(srcPath, destPath, next) {
|
function linkIfLinux(srcPath, destPath, next) {
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
file.copyFile(srcPath, destPath, next);
|
fs.copyFile(srcPath, destPath, next);
|
||||||
} else {
|
} else {
|
||||||
file.link(srcPath, destPath, true, next);
|
file.link(srcPath, destPath, true, next);
|
||||||
}
|
}
|
||||||
|
|||||||
14
test/file.js
14
test/file.js
@@ -22,7 +22,7 @@ describe('file', function () {
|
|||||||
|
|
||||||
describe('copyFile', function () {
|
describe('copyFile', function () {
|
||||||
it('should copy a file', function (done) {
|
it('should copy a file', function (done) {
|
||||||
file.copyFile(tempPath, uploadPath, function (err) {
|
fs.copyFile(tempPath, uploadPath, function (err) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
|
|
||||||
assert(file.existsSync(uploadPath));
|
assert(file.existsSync(uploadPath));
|
||||||
@@ -38,7 +38,7 @@ describe('file', function () {
|
|||||||
it('should override an existing file', function (done) {
|
it('should override an existing file', function (done) {
|
||||||
fs.writeFileSync(uploadPath, 'hsdkjhgkjsfhkgj');
|
fs.writeFileSync(uploadPath, 'hsdkjhgkjsfhkgj');
|
||||||
|
|
||||||
file.copyFile(tempPath, uploadPath, function (err) {
|
fs.copyFile(tempPath, uploadPath, function (err) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
|
|
||||||
assert(file.existsSync(uploadPath));
|
assert(file.existsSync(uploadPath));
|
||||||
@@ -52,7 +52,7 @@ describe('file', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should error if source file does not exist', function (done) {
|
it('should error if source file does not exist', function (done) {
|
||||||
file.copyFile(tempPath + '0000000000', uploadPath, function (err) {
|
fs.copyFile(tempPath + '0000000000', uploadPath, function (err) {
|
||||||
assert(err);
|
assert(err);
|
||||||
assert.strictEqual(err.code, 'ENOENT');
|
assert.strictEqual(err.code, 'ENOENT');
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ describe('file', function () {
|
|||||||
fs.writeFileSync(uploadPath, 'hsdkjhgkjsfhkgj');
|
fs.writeFileSync(uploadPath, 'hsdkjhgkjsfhkgj');
|
||||||
fs.chmodSync(uploadPath, '444');
|
fs.chmodSync(uploadPath, '444');
|
||||||
|
|
||||||
file.copyFile(tempPath, uploadPath, function (err) {
|
fs.copyFile(tempPath, uploadPath, function (err) {
|
||||||
assert(err);
|
assert(err);
|
||||||
assert(err.code === 'EPERM' || err.code === 'EACCES');
|
assert(err.code === 'EPERM' || err.code === 'EACCES');
|
||||||
|
|
||||||
@@ -105,4 +105,10 @@ describe('file', function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should convert mime type to extension', function (done) {
|
||||||
|
assert.equal(file.typeToExtension('image/png'), '.png');
|
||||||
|
assert.equal(file.typeToExtension(''), '');
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user