const fs = require('fs-extra'); const path = require('path'); const yazl = require('yazl'); const express = require('express'); const utils = require('./core/utils'); const webAppDir = require('../build/appdir'); const log = new (require('./core/AppLogger'))().log;//singleton function generateZip(zipFile, dataFile, dataFileInZip) { return new Promise((resolve, reject) => { const zip = new yazl.ZipFile(); zip.addFile(dataFile, dataFileInZip); zip.outputStream .pipe(fs.createWriteStream(zipFile)).on('error', reject) .on('finish', (err) => { if (err) reject(err); else resolve(); } ); zip.end(); }); } module.exports = (app, config) => { /* config.bookPathStatic = `${config.rootPathStatic}/book`; config.bookDir = `${config.publicFilesDir}/book`; */ //загрузка или восстановление файлов в /public-files, при необходимости app.use([`${config.bookPathStatic}/:fileName/:fileType`, `${config.bookPathStatic}/:fileName`], async(req, res, next) => { if (req.method !== 'GET' && req.method !== 'HEAD') { return next(); } try { const fileName = req.params.fileName; const fileType = req.params.fileType; if (path.extname(fileName) === '') {//восстановление файлов {hash}.raw, {hash}.zip let bookFile = `${config.bookDir}/${fileName}`; const bookFileDesc = `${bookFile}.d.json`; //восстановим из json-файла описания if (await fs.pathExists(bookFile) && await fs.pathExists(bookFileDesc)) { await utils.touchFile(bookFile); await utils.touchFile(bookFileDesc); let desc = await fs.readFile(bookFileDesc, 'utf8'); let downFileName = (JSON.parse(desc)).downFileName; let gzipped = true; if (!req.acceptsEncodings('gzip') || fileType) { const rawFile = `${bookFile}.raw`; //не принимает gzip, тогда распакуем if (!await fs.pathExists(rawFile)) await utils.gunzipFile(bookFile, rawFile); gzipped = false; if (fileType === undefined || fileType === 'raw') { bookFile = rawFile; } else if (fileType === 'zip') { //создаем zip-файл bookFile += '.zip'; if (!await fs.pathExists(bookFile)) await generateZip(bookFile, rawFile, downFileName); downFileName += '.zip'; } else { throw new Error(`Unsupported file type: ${fileType}`); } } //отдача файла if (gzipped) res.set('Content-Encoding', 'gzip'); res.set('Content-Disposition', `inline; filename*=UTF-8''${encodeURIComponent(downFileName)}`); res.sendFile(bookFile); return; } else { await fs.remove(bookFile); await fs.remove(bookFileDesc); } } } catch(e) { log(LM_ERR, e.message); } return next(); }); //иначе просто отдаем запрошенный файл из /public-files app.use(config.bookPathStatic, express.static(config.bookDir)); if (config.rootPathStatic) { //подмена rootPath в файлах статики WebApp при необходимости app.use(config.rootPathStatic, async(req, res, next) => { if (req.method !== 'GET' && req.method !== 'HEAD') { return next(); } try { const reqPath = (req.path == '/' ? '/index.html' : req.path); const ext = path.extname(reqPath); if (ext == '.html' || ext == '.js' || ext == '.css') { const reqFile = `${config.publicDir}${reqPath}`; const flagFile = `${reqFile}.replaced`; if (!await fs.pathExists(flagFile) && await fs.pathExists(reqFile)) { const content = await fs.readFile(reqFile, 'utf8'); const re = new RegExp(`/${webAppDir}`, 'g'); await fs.writeFile(reqFile, content.replace(re, `${config.rootPathStatic}/${webAppDir}`)); await fs.writeFile(flagFile, ''); } } } catch(e) { log(LM_ERR, e.message); } return next(); }); } //статика файлов WebApp app.use(config.rootPathStatic, express.static(config.publicDir)); };