Добавлен abort конвертеров при истечении времени ожидания подвижек очереди
This commit is contained in:
@@ -14,7 +14,7 @@ class ConvertBase {
|
|||||||
this.calibrePath = `${config.dataDir}/calibre/ebook-convert`;
|
this.calibrePath = `${config.dataDir}/calibre/ebook-convert`;
|
||||||
this.sofficePath = '/usr/bin/soffice';
|
this.sofficePath = '/usr/bin/soffice';
|
||||||
this.pdfToHtmlPath = '/usr/bin/pdftohtml';
|
this.pdfToHtmlPath = '/usr/bin/pdftohtml';
|
||||||
this.queue = new LimitedQueue(2, 20, 3*60*1000);
|
this.queue = new LimitedQueue(2, 20, 3*60*1000);//3 минуты ожидание подвижек
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(data, opts) {// eslint-disable-line no-unused-vars
|
async run(data, opts) {// eslint-disable-line no-unused-vars
|
||||||
@@ -32,7 +32,7 @@ class ConvertBase {
|
|||||||
throw new Error('Внешний конвертер pdftohtml не найден');
|
throw new Error('Внешний конвертер pdftohtml не найден');
|
||||||
}
|
}
|
||||||
|
|
||||||
async execConverter(path, args, onData) {
|
async execConverter(path, args, onData, abort) {
|
||||||
let q = null;
|
let q = null;
|
||||||
try {
|
try {
|
||||||
q = await this.queue.get(() => {onData();});
|
q = await this.queue.get(() => {onData();});
|
||||||
@@ -41,7 +41,7 @@ class ConvertBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await utils.spawnProcess(path, {args, onData});
|
const result = await utils.spawnProcess(path, {args, onData, abort});
|
||||||
if (result.code != 0) {
|
if (result.code != 0) {
|
||||||
let error = result.code;
|
let error = result.code;
|
||||||
if (this.config.branch == 'development')
|
if (this.config.branch == 'development')
|
||||||
@@ -51,6 +51,8 @@ class ConvertBase {
|
|||||||
} catch(e) {
|
} catch(e) {
|
||||||
if (e.status == 'killed') {
|
if (e.status == 'killed') {
|
||||||
throw new Error('Слишком долгое ожидание конвертера');
|
throw new Error('Слишком долгое ожидание конвертера');
|
||||||
|
} else if (e.status == 'abort') {
|
||||||
|
throw new Error('abort');
|
||||||
} else if (e.status == 'error') {
|
} else if (e.status == 'error') {
|
||||||
throw new Error(e.error);
|
throw new Error(e.error);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class ConvertDoc extends ConvertDocX {
|
|||||||
return false;
|
return false;
|
||||||
await this.checkExternalConverterPresent();
|
await this.checkExternalConverterPresent();
|
||||||
|
|
||||||
const {inputFiles, callback} = opts;
|
const {inputFiles, callback, abort} = opts;
|
||||||
|
|
||||||
const outFile = `${inputFiles.filesDir}/${path.basename(inputFiles.sourceFile)}`;
|
const outFile = `${inputFiles.filesDir}/${path.basename(inputFiles.sourceFile)}`;
|
||||||
const docFile = `${outFile}.doc`;
|
const docFile = `${outFile}.doc`;
|
||||||
@@ -24,9 +24,9 @@ class ConvertDoc extends ConvertDocX {
|
|||||||
const fb2File = `${outFile}.fb2`;
|
const fb2File = `${outFile}.fb2`;
|
||||||
|
|
||||||
await fs.copy(inputFiles.sourceFile, docFile);
|
await fs.copy(inputFiles.sourceFile, docFile);
|
||||||
await this.execConverter(this.sofficePath, ['--headless', '--convert-to', 'docx', '--outdir', inputFiles.filesDir, docFile]);
|
await this.execConverter(this.sofficePath, ['--headless', '--convert-to', 'docx', '--outdir', inputFiles.filesDir, docFile], null, abort);
|
||||||
|
|
||||||
return await super.convert(docxFile, fb2File, callback);
|
return await super.convert(docxFile, fb2File, callback, abort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ class ConvertDocX extends ConvertBase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async convert(docxFile, fb2File, callback) {
|
async convert(docxFile, fb2File, callback, abort) {
|
||||||
let perc = 0;
|
let perc = 0;
|
||||||
await this.execConverter(this.calibrePath, [docxFile, fb2File], () => {
|
await this.execConverter(this.calibrePath, [docxFile, fb2File], () => {
|
||||||
perc = (perc < 100 ? perc + 5 : 50);
|
perc = (perc < 100 ? perc + 5 : 50);
|
||||||
callback(perc);
|
callback(perc);
|
||||||
});
|
}, abort);
|
||||||
|
|
||||||
return await fs.readFile(fb2File);
|
return await fs.readFile(fb2File);
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ class ConvertDocX extends ConvertBase {
|
|||||||
return false;
|
return false;
|
||||||
await this.checkExternalConverterPresent();
|
await this.checkExternalConverterPresent();
|
||||||
|
|
||||||
const {inputFiles, callback} = opts;
|
const {inputFiles, callback, abort} = opts;
|
||||||
|
|
||||||
const outFile = `${inputFiles.filesDir}/${path.basename(inputFiles.sourceFile)}`;
|
const outFile = `${inputFiles.filesDir}/${path.basename(inputFiles.sourceFile)}`;
|
||||||
const docxFile = `${outFile}.docx`;
|
const docxFile = `${outFile}.docx`;
|
||||||
@@ -43,7 +43,7 @@ class ConvertDocX extends ConvertBase {
|
|||||||
|
|
||||||
await fs.copy(inputFiles.sourceFile, docxFile);
|
await fs.copy(inputFiles.sourceFile, docxFile);
|
||||||
|
|
||||||
return await this.convert(docxFile, fb2File, callback);
|
return await this.convert(docxFile, fb2File, callback, abort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class ConvertEpub extends ConvertBase {
|
|||||||
return false;
|
return false;
|
||||||
await this.checkExternalConverterPresent();
|
await this.checkExternalConverterPresent();
|
||||||
|
|
||||||
const {inputFiles, callback} = opts;
|
const {inputFiles, callback, abort} = opts;
|
||||||
|
|
||||||
const outFile = `${inputFiles.filesDir}/${path.basename(inputFiles.sourceFile)}`;
|
const outFile = `${inputFiles.filesDir}/${path.basename(inputFiles.sourceFile)}`;
|
||||||
const epubFile = `${outFile}.epub`;
|
const epubFile = `${outFile}.epub`;
|
||||||
@@ -40,7 +40,7 @@ class ConvertEpub extends ConvertBase {
|
|||||||
await this.execConverter(this.calibrePath, [epubFile, fb2File], () => {
|
await this.execConverter(this.calibrePath, [epubFile, fb2File], () => {
|
||||||
perc = (perc < 100 ? perc + 5 : 50);
|
perc = (perc < 100 ? perc + 5 : 50);
|
||||||
callback(perc);
|
callback(perc);
|
||||||
});
|
}, abort);
|
||||||
|
|
||||||
return await fs.readFile(fb2File);
|
return await fs.readFile(fb2File);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class ConvertMobi extends ConvertBase {
|
|||||||
return false;
|
return false;
|
||||||
await this.checkExternalConverterPresent();
|
await this.checkExternalConverterPresent();
|
||||||
|
|
||||||
const {inputFiles, callback} = opts;
|
const {inputFiles, callback, abort} = opts;
|
||||||
|
|
||||||
const outFile = `${inputFiles.filesDir}/${path.basename(inputFiles.sourceFile)}`;
|
const outFile = `${inputFiles.filesDir}/${path.basename(inputFiles.sourceFile)}`;
|
||||||
const mobiFile = `${outFile}.mobi`;
|
const mobiFile = `${outFile}.mobi`;
|
||||||
@@ -28,7 +28,7 @@ class ConvertMobi extends ConvertBase {
|
|||||||
await this.execConverter(this.calibrePath, [mobiFile, fb2File], () => {
|
await this.execConverter(this.calibrePath, [mobiFile, fb2File], () => {
|
||||||
perc = (perc < 100 ? perc + 5 : 50);
|
perc = (perc < 100 ? perc + 5 : 50);
|
||||||
callback(perc);
|
callback(perc);
|
||||||
});
|
}, abort);
|
||||||
|
|
||||||
return await fs.readFile(fb2File);
|
return await fs.readFile(fb2File);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class ConvertPdf extends ConvertHtml {
|
|||||||
return false;
|
return false;
|
||||||
await this.checkExternalConverterPresent();
|
await this.checkExternalConverterPresent();
|
||||||
|
|
||||||
const {inputFiles, callback} = opts;
|
const {inputFiles, callback, abort} = opts;
|
||||||
|
|
||||||
const outFile = `${inputFiles.filesDir}/${utils.randomHexString(10)}.xml`;
|
const outFile = `${inputFiles.filesDir}/${utils.randomHexString(10)}.xml`;
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ class ConvertPdf extends ConvertHtml {
|
|||||||
await this.execConverter(this.pdfToHtmlPath, ['-c', '-s', '-xml', inputFiles.sourceFile, outFile], () => {
|
await this.execConverter(this.pdfToHtmlPath, ['-c', '-s', '-xml', inputFiles.sourceFile, outFile], () => {
|
||||||
perc = (perc < 80 ? perc + 10 : 40);
|
perc = (perc < 80 ? perc + 10 : 40);
|
||||||
callback(perc);
|
callback(perc);
|
||||||
});
|
}, abort);
|
||||||
callback(80);
|
callback(80);
|
||||||
|
|
||||||
const data = await fs.readFile(outFile);
|
const data = await fs.readFile(outFile);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class ConvertRtf extends ConvertDocX {
|
|||||||
return false;
|
return false;
|
||||||
await this.checkExternalConverterPresent();
|
await this.checkExternalConverterPresent();
|
||||||
|
|
||||||
const {inputFiles, callback} = opts;
|
const {inputFiles, callback, abort} = opts;
|
||||||
|
|
||||||
const outFile = `${inputFiles.filesDir}/${path.basename(inputFiles.sourceFile)}`;
|
const outFile = `${inputFiles.filesDir}/${path.basename(inputFiles.sourceFile)}`;
|
||||||
const rtfFile = `${outFile}.rtf`;
|
const rtfFile = `${outFile}.rtf`;
|
||||||
@@ -24,9 +24,9 @@ class ConvertRtf extends ConvertDocX {
|
|||||||
const fb2File = `${outFile}.fb2`;
|
const fb2File = `${outFile}.fb2`;
|
||||||
|
|
||||||
await fs.copy(inputFiles.sourceFile, rtfFile);
|
await fs.copy(inputFiles.sourceFile, rtfFile);
|
||||||
await this.execConverter(this.sofficePath, ['--headless', '--convert-to', 'docx', '--outdir', inputFiles.filesDir, rtfFile]);
|
await this.execConverter(this.sofficePath, ['--headless', '--convert-to', 'docx', '--outdir', inputFiles.filesDir, rtfFile], null, abort);
|
||||||
|
|
||||||
return await super.convert(docxFile, fb2File, callback);
|
return await super.convert(docxFile, fb2File, callback, abort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,11 +26,14 @@ class BookConverter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async convertToFb2(inputFiles, outputFile, opts, callback) {
|
async convertToFb2(inputFiles, outputFile, opts, callback, abort) {
|
||||||
|
if (abort && abort())
|
||||||
|
throw new Error('abort');
|
||||||
|
|
||||||
const selectedFileType = await this.detector.detectFile(inputFiles.selectedFile);
|
const selectedFileType = await this.detector.detectFile(inputFiles.selectedFile);
|
||||||
const data = await fs.readFile(inputFiles.selectedFile);
|
const data = await fs.readFile(inputFiles.selectedFile);
|
||||||
|
|
||||||
const convertOpts = Object.assign({}, opts, {inputFiles, callback, dataType: selectedFileType});
|
const convertOpts = Object.assign({}, opts, {inputFiles, callback, abort, dataType: selectedFileType});
|
||||||
let result = false;
|
let result = false;
|
||||||
for (const convert of this.convertFactory) {
|
for (const convert of this.convertFactory) {
|
||||||
result = await convert.run(data, convertOpts);
|
result = await convert.run(data, convertOpts);
|
||||||
@@ -41,7 +44,7 @@ class BookConverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!result && inputFiles.nesting) {
|
if (!result && inputFiles.nesting) {
|
||||||
result = await this.convertToFb2(inputFiles.nesting, outputFile, opts, callback);
|
result = await this.convertToFb2(inputFiles.nesting, outputFile, opts, callback, abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class ReaderWorker {
|
|||||||
this.config.tempPublicDir = `${config.publicDir}/tmp`;
|
this.config.tempPublicDir = `${config.publicDir}/tmp`;
|
||||||
fs.ensureDirSync(this.config.tempPublicDir);
|
fs.ensureDirSync(this.config.tempPublicDir);
|
||||||
|
|
||||||
this.queue = new LimitedQueue(5, 100, 3*60*1000);
|
this.queue = new LimitedQueue(5, 100, 5*60*1000);//5 минут ожидание подвижек
|
||||||
this.workerState = new WorkerState();
|
this.workerState = new WorkerState();
|
||||||
this.down = new FileDownloader(config.maxUploadFileSize);
|
this.down = new FileDownloader(config.maxUploadFileSize);
|
||||||
this.decomp = new FileDecompressor(2*config.maxUploadFileSize);
|
this.decomp = new FileDecompressor(2*config.maxUploadFileSize);
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ async function touchFile(filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function spawnProcess(cmd, opts) {
|
function spawnProcess(cmd, opts) {
|
||||||
let {args, killAfter, onData} = opts;
|
let {args, killAfter, onData, abort} = opts;
|
||||||
killAfter = (killAfter ? killAfter : 120*1000);
|
killAfter = (killAfter ? killAfter : 120);//seconds
|
||||||
onData = (onData ? onData : () => {});
|
onData = (onData ? onData : () => {});
|
||||||
args = (args ? args : []);
|
args = (args ? args : []);
|
||||||
|
|
||||||
@@ -67,10 +67,18 @@ function spawnProcess(cmd, opts) {
|
|||||||
reject({status: 'error', error, stdout, stderr});
|
reject({status: 'error', error, stdout, stderr});
|
||||||
});
|
});
|
||||||
|
|
||||||
await sleep(killAfter);
|
while (!resolved) {
|
||||||
if (!resolved) {
|
await sleep(1000);
|
||||||
process.kill(proc.pid);
|
killAfter -= 1;
|
||||||
reject({status: 'killed', stdout, stderr});
|
if (killAfter <= 0 || (abort && abort())) {
|
||||||
|
process.kill(proc.pid);
|
||||||
|
if (killAfter <= 0) {
|
||||||
|
reject({status: 'killed', stdout, stderr});
|
||||||
|
} else {
|
||||||
|
reject({status: 'abort', stdout, stderr});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})().catch(reject); });
|
})().catch(reject); });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user