Desktop, Cli: Fixes #3958: Fixed freeze when importing ENEX as HTML, and fixed potential error when importing resources

openProfileDirectory
Laurent Cozic 2020-10-21 12:02:06 +01:00
parent 1ca44b8f44
commit 8dc0deb2a4
2 changed files with 32 additions and 10 deletions

View File

@ -1,5 +1,5 @@
const stringToStream = require('string-to-stream');
const cleanHtml = require('clean-html');
// const cleanHtml = require('clean-html');
const resourceUtils = require('lib/resourceUtils.js');
const { isSelfClosingTag } = require('lib/htmlUtils');
const Entities = require('html-entities').AllHtmlEntities;
@ -161,14 +161,22 @@ async function enexXmlToHtml(xmlString, resources, options = {}) {
}
const beautifyHtml = (html) => {
return new Promise((resolve) => {
try {
cleanHtml.clean(html, { wrap: 0 }, (...cleanedHtml) => resolve(cleanedHtml));
} catch (error) {
console.warn(`Could not clean HTML - the "unclean" version will be used: ${error.message}: ${html.trim().substr(0, 512).replace(/[\n\r]/g, ' ')}...`);
resolve([html]);
}
});
// The clean-html package doesn't appear to be robust enough to deal with the crazy HTML that Evernote can generate.
// In the best case scenario it will throw an error but in some cases it will go into an infinite loop, so
// for that reason we need to disable it.
//
// Fixed https://github.com/laurent22/joplin/issues/3958
return [html];
// return new Promise((resolve) => {
// try {
// cleanHtml.clean(html, { wrap: 0 }, (...cleanedHtml) => resolve(cleanedHtml));
// } catch (error) {
// console.warn(`Could not clean HTML - the "unclean" version will be used: ${error.message}: ${html.trim().substr(0, 512).replace(/[\n\r]/g, ' ')}...`);
// resolve([html]);
// }
// });
};
module.exports = { enexXmlToHtml };

View File

@ -40,6 +40,16 @@ function extractRecognitionObjId(recognitionXml) {
}
async function decodeBase64File(sourceFilePath, destFilePath) {
// When something goes wrong with streams you can get an error "EBADF, Bad file descriptor"
// with no strack trace to tell where the error happened.
// Also note that this code is not great because there's a source and a destination stream
// and while one stream might end, the other might throw an error or vice-versa. However
// we can only throw one error from a promise. So before one stream
// could end with resolve(), then another stream would get an error and call reject(), which
// would be ignored. I don't think it's happening anymore, but something to keep in mind
// anyway.
return new Promise(function(resolve, reject) {
// Note: we manually handle closing the file so that we can
// force flusing it before close. This is needed because
@ -55,13 +65,17 @@ async function decodeBase64File(sourceFilePath, destFilePath) {
});
sourceStream.pipe(new Base64Decode()).pipe(destStream);
sourceStream.on('end', () => {
// We wait for the destination stream "finish" event, not the source stream "end" event
// because even if the source has finished sending data, the destination might not have
// finished receiving it and writing it to disk.
destStream.on('finish', () => {
fs.fdatasyncSync(destFile);
fs.closeSync(destFile);
resolve();
});
sourceStream.on('error', (error) => reject(error));
destStream.on('error', (error) => reject(error));
});
}