import/export: Promisify Abiword and LibreOffice conversion

This commit is contained in:
Richard Hansen 2021-03-18 01:01:47 -04:00 committed by John McLear
parent b321267e66
commit b2c0837cf5
4 changed files with 67 additions and 91 deletions

View file

@ -98,8 +98,7 @@ exports.doExport = async (req, res, padId, readOnlyId, type) => {
settings.soffice != null ? require('../utils/LibreOffice')
: settings.abiword != null ? require('../utils/Abiword')
: null;
// @TODO no Promise interface for converters (yet)
await util.promisify(converter.convertFile)(srcFile, destFile, type);
await converter.convertFile(srcFile, destFile, type);
}
// send the file

View file

@ -179,17 +179,12 @@ const doImport = async (req, res, padId) => {
// if no converter only rename
await fs.rename(srcFile, destFile);
} else {
// @TODO - no Promise interface for converters (yet)
await new Promise((resolve, reject) => {
converter.convertFile(srcFile, destFile, exportExtension, (err) => {
// catch convert errors
if (err) {
try {
await converter.convertFile(srcFile, destFile, exportExtension);
} catch (err) {
logger.warn(`Converting Error: ${err.stack || err}`);
return reject(new ImportError('convertFailed'));
throw new ImportError('convertFailed');
}
resolve();
});
});
}
}

View file

@ -24,27 +24,23 @@ const async = require('async');
const settings = require('./Settings');
const os = require('os');
let doConvertTask;
// on windows we have to spawn a process for each convertion,
// cause the plugin abicommand doesn't exist on this platform
if (os.type().indexOf('Windows') > -1) {
doConvertTask = (task, callback) => {
const abiword = spawn(settings.abiword, [`--to=${task.destFile}`, task.srcFile]);
exports.convertFile = async (srcFile, destFile, type) => {
const abiword = spawn(settings.abiword, [`--to=${destFile}`, srcFile]);
let stdoutBuffer = '';
abiword.stdout.on('data', (data) => { stdoutBuffer += data.toString(); });
abiword.stderr.on('data', (data) => { stdoutBuffer += data.toString(); });
await new Promise((resolve, reject) => {
abiword.on('exit', (code) => {
if (code !== 0) return callback(new Error(`Abiword died with exit code ${code}`));
if (code !== 0) return reject(new Error(`Abiword died with exit code ${code}`));
if (stdoutBuffer !== '') {
console.log(stdoutBuffer);
}
callback();
resolve();
});
});
};
exports.convertFile = (srcFile, destFile, type, callback) => {
doConvertTask({srcFile, destFile, type}, callback);
};
// on unix operating systems, we can start abiword with abicommand and
// communicate with it via stdin/stdout
@ -85,7 +81,7 @@ if (os.type().indexOf('Windows') > -1) {
};
}, 1);
exports.convertFile = (srcFile, destFile, type, callback) => {
queue.push({srcFile, destFile, type}, callback);
exports.convertFile = async (srcFile, destFile, type) => {
await queue.pushAsync({srcFile, destFile, type});
};
}

View file

@ -18,7 +18,7 @@
*/
const async = require('async');
const fs = require('fs');
const fs = require('fs').promises;
const log4js = require('log4js');
const os = require('os');
const path = require('path');
@ -27,14 +27,11 @@ const spawn = require('child_process').spawn;
const libreOfficeLogger = log4js.getLogger('LibreOffice');
const doConvertTask = (task, callback) => {
const doConvertTask = async (task) => {
const tmpDir = os.tmpdir();
async.series([
(callback) => {
libreOfficeLogger.debug(
`Converting ${task.srcFile} to format ${task.type}. The result will be put in ${tmpDir}`
);
`Converting ${task.srcFile} to format ${task.type}. The result will be put in ${tmpDir}`);
const soffice = spawn(settings.soffice, [
'--headless',
'--invisible',
@ -56,28 +53,29 @@ const doConvertTask = (task, callback) => {
let stdoutBuffer = '';
soffice.stdout.on('data', (data) => { stdoutBuffer += data.toString(); });
soffice.stderr.on('data', (data) => { stdoutBuffer += data.toString(); });
await new Promise((resolve, reject) => {
soffice.on('exit', (code) => {
clearTimeout(hangTimeout);
if (code !== 0) {
return callback(
return reject(
new Error(`LibreOffice died with exit code ${code} and message: ${stdoutBuffer}`));
}
callback();
resolve();
});
});
},
(callback) => {
const filename = path.basename(task.srcFile);
const sourceFile = `${filename.substr(0, filename.lastIndexOf('.'))}.${task.fileExtension}`;
const sourcePath = path.join(tmpDir, sourceFile);
libreOfficeLogger.debug(`Renaming ${sourcePath} to ${task.destFile}`);
fs.rename(sourcePath, task.destFile, callback);
},
], callback);
await fs.rename(sourcePath, task.destFile);
};
// Conversion tasks will be queued up, so we don't overload the system
const queue = async.queue(doConvertTask, 1);
const queue = async.queue(
// For some reason util.callbackify() throws "TypeError [ERR_INVALID_ARG_TYPE]: The last
// argument must be of type Function. Received type object" on Node.js 10.x.
(task, cb) => doConvertTask(task).then(() => cb(), (err) => cb(err || new Error(err))), 1);
/**
* Convert a file from one type to another
@ -87,7 +85,7 @@ const queue = async.queue(doConvertTask, 1);
* @param {String} type The type to convert into
* @param {Function} callback Standard callback function
*/
exports.convertFile = (srcFile, destFile, type, callback) => {
exports.convertFile = async (srcFile, destFile, type) => {
// Used for the moving of the file, not the conversion
const fileExtension = type;
@ -107,21 +105,9 @@ exports.convertFile = (srcFile, destFile, type, callback) => {
// to avoid `Error: no export filter for /tmp/xxxx.doc` error
if (type === 'doc') {
const intermediateFile = destFile.replace(/\.doc$/, '.odt');
async.series([
(callback) => queue.push({
srcFile,
destFile: intermediateFile,
type: 'odt',
fileExtension: 'odt',
}, callback),
(callback) => queue.push({
srcFile: intermediateFile,
destFile,
type,
fileExtension,
}, callback),
], callback);
await queue.pushAsync({srcFile, destFile: intermediateFile, type: 'odt', fileExtension: 'odt'});
await queue.pushAsync({srcFile: intermediateFile, destFile, type, fileExtension});
} else {
queue.push({srcFile, destFile, type, fileExtension}, callback);
await queue.pushAsync({srcFile, destFile, type, fileExtension});
}
};