static.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. const fs = require('fs-extra');
  2. const path = require('path');
  3. const JSZip = require('jszip');
  4. const express = require('express');
  5. const utils = require('./core/utils');
  6. const webAppDir = require('../build/appdir');
  7. const log = new (require('./core/AppLogger'))().log;//singleton
  8. function generateZip(zipFile, dataFile, data) {
  9. return new Promise((resolve, reject) => {
  10. const zip = new JSZip();
  11. zip.file(dataFile, data)
  12. .generateNodeStream({
  13. streamFiles: true,
  14. compression: 'DEFLATE',
  15. compressionOptions: {level: 6},
  16. }).on('error', reject)
  17. .pipe(fs.createWriteStream(zipFile)).on('error', reject)
  18. .on('finish', (err) => {
  19. if (err) reject(err);
  20. else resolve();
  21. }
  22. );
  23. });
  24. }
  25. module.exports = (app, config) => {
  26. /*
  27. config.bookPathStatic = `${config.rootPathStatic}/book`;
  28. config.bookDir = `${config.publicFilesDir}/book`;
  29. */
  30. //загрузка или восстановление файлов в /public-files, при необходимости
  31. app.use([`${config.bookPathStatic}/:fileName/:fileType`, `${config.bookPathStatic}/:fileName`], async(req, res, next) => {
  32. if (req.method !== 'GET' && req.method !== 'HEAD') {
  33. return next();
  34. }
  35. try {
  36. const fileName = req.params.fileName;
  37. const fileType = req.params.fileType;
  38. if (path.extname(fileName) === '') {//восстановление файлов {hash}.raw, {hash}.zip
  39. let bookFile = `${config.bookDir}/${fileName}`;
  40. const bookFileDesc = `${bookFile}.d.json`;
  41. //восстановим из json-файла описания
  42. if (await fs.pathExists(bookFile) && await fs.pathExists(bookFileDesc)) {
  43. await utils.touchFile(bookFile);
  44. await utils.touchFile(bookFileDesc);
  45. let desc = await fs.readFile(bookFileDesc, 'utf8');
  46. let downFileName = (JSON.parse(desc)).downFileName;
  47. let gzipped = true;
  48. if (!req.acceptsEncodings('gzip') || fileType) {
  49. const rawFile = `${bookFile}.raw`;
  50. //не принимает gzip, тогда распакуем
  51. if (!await fs.pathExists(rawFile))
  52. await utils.gunzipFile(bookFile, rawFile);
  53. gzipped = false;
  54. if (fileType === undefined || fileType === 'raw') {
  55. bookFile = rawFile;
  56. } else if (fileType === 'zip') {
  57. //создаем zip-файл
  58. bookFile += '.zip';
  59. if (!await fs.pathExists(bookFile)) {
  60. const data = await fs.readFile(rawFile);
  61. await generateZip(bookFile, downFileName, data);
  62. }
  63. downFileName += '.zip';
  64. } else {
  65. throw new Error(`Unsupported file type: ${fileType}`);
  66. }
  67. }
  68. //отдача файла
  69. if (gzipped)
  70. res.set('Content-Encoding', 'gzip');
  71. res.set('Content-Disposition', `inline; filename*=UTF-8''${encodeURIComponent(downFileName)}`);
  72. res.sendFile(bookFile);
  73. return;
  74. } else {
  75. await fs.remove(bookFile);
  76. await fs.remove(bookFileDesc);
  77. }
  78. }
  79. } catch(e) {
  80. log(LM_ERR, e.message);
  81. }
  82. return next();
  83. });
  84. //иначе просто отдаем запрошенный файл из /public-files
  85. app.use(config.bookPathStatic, express.static(config.bookDir));
  86. if (config.rootPathStatic) {
  87. //подмена rootPath в файлах статики WebApp при необходимости
  88. app.use(config.rootPathStatic, async(req, res, next) => {
  89. if (req.method !== 'GET' && req.method !== 'HEAD') {
  90. return next();
  91. }
  92. try {
  93. const reqPath = (req.path == '/' ? '/index.html' : req.path);
  94. const ext = path.extname(reqPath);
  95. if (ext == '.html' || ext == '.js' || ext == '.css') {
  96. const reqFile = `${config.publicDir}${reqPath}`;
  97. const flagFile = `${reqFile}.replaced`;
  98. if (!await fs.pathExists(flagFile) && await fs.pathExists(reqFile)) {
  99. const content = await fs.readFile(reqFile, 'utf8');
  100. const re = new RegExp(`/${webAppDir}`, 'g');
  101. await fs.writeFile(reqFile, content.replace(re, `${config.rootPathStatic}/${webAppDir}`));
  102. await fs.writeFile(flagFile, '');
  103. }
  104. }
  105. } catch(e) {
  106. log(LM_ERR, e.message);
  107. }
  108. return next();
  109. });
  110. }
  111. //статика файлов WebApp
  112. app.use(config.rootPathStatic, express.static(config.publicDir));
  113. };