ReaderWorker.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. const workerState = require('./workerState');
  2. const FileDetector = require('./FileDetector');
  3. const FileDecompressor = require('./FileDecompressor');
  4. const BookConverter = require('./BookConverter');
  5. const utils = require('./utils');
  6. const fs = require('fs-extra');
  7. const util = require('util');
  8. const stream = require('stream');
  9. const pipeline = util.promisify(stream.pipeline);
  10. const download = require('download');
  11. class ReaderWorker {
  12. constructor(config) {
  13. this.config = Object.assign({}, config);
  14. this.config.tempDownloadDir = `${config.tempDir}/download`;
  15. fs.ensureDirSync(this.config.tempDownloadDir);
  16. this.config.tempPublicDir = `${config.publicDir}/tmp`;
  17. fs.ensureDirSync(this.config.tempPublicDir);
  18. this.detector = new FileDetector();
  19. this.decomp = new FileDecompressor();
  20. this.bookConverter = new BookConverter();
  21. }
  22. async loadBook(url, wState) {
  23. const maxDownloadSize = 10*1024*1024;
  24. let errMes = '';
  25. let decompDir = '';
  26. let downloadedFilename = '';
  27. try {
  28. wState.set({state: 'download', step: 1, totalSteps: 3, url});
  29. const tempFilename = utils.randomHexString(30);
  30. const tempFilename2 = utils.randomHexString(30);
  31. const decompDirname = utils.randomHexString(30);
  32. //download
  33. const d = download(url);
  34. d.on('downloadProgress', progress => {
  35. if (progress.transferred > maxDownloadSize) {
  36. errMes = 'file too big';
  37. d.destroy();
  38. }
  39. const prog = Math.round(progress.transferred/10000);
  40. wState.set({progress: (prog > 100 ? 100 : prog) });
  41. });
  42. downloadedFilename = `${this.config.tempDownloadDir}/${tempFilename}`;
  43. await pipeline(d, fs.createWriteStream(downloadedFilename));
  44. wState.set({progress: 100});
  45. //decompress
  46. wState.set({state: 'decompress', step: 2, progress: 0});
  47. decompDir = `${this.config.tempDownloadDir}/${decompDirname}`;
  48. const decompFilename = await this.decomp.decompressFile(downloadedFilename, decompDir);
  49. wState.set({progress: 100});
  50. //parse book
  51. wState.set({state: 'parse', step: 3, progress: 0});
  52. const fileType = await this.detector.detectFile(decompFilename);
  53. fileType.url = url;
  54. let resultFilename = `${this.config.tempPublicDir}/${tempFilename2}`;
  55. await this.bookConverter.convertToFb2(decompFilename, resultFilename, fileType, progress => {
  56. wState.set({progress});
  57. });
  58. wState.set({progress: 100});
  59. //finish
  60. wState.finish({path: `/tmp/${tempFilename2}`});
  61. } catch (e) {
  62. wState.set({state: 'error', error: (errMes ? errMes : e.message)});
  63. } finally {
  64. //clean
  65. if (decompDir)
  66. await fs.remove(decompDir);
  67. if (downloadedFilename)
  68. await fs.remove(downloadedFilename);
  69. }
  70. }
  71. loadBookUrl(url) {
  72. const workerId = workerState.generateWorkerId();
  73. const wState = workerState.getControl(workerId);
  74. wState.set({state: 'start'});
  75. this.loadBook(url, wState);
  76. return workerId;
  77. }
  78. }
  79. module.exports = ReaderWorker;