Добавлено формирование zip-файла (#4)

This commit is contained in:
Book Pauk
2022-12-05 18:06:20 +07:00
parent de9471c2d5
commit b3ed9ea89c
3 changed files with 100 additions and 54 deletions

View File

@@ -128,7 +128,19 @@ class BookPage extends BasePage {
if (bookInfo) {
const {genreMap} = await this.getGenres();
const fileFormat = `${bookInfo.book.ext}+zip`;
//format
const ext = bookInfo.book.ext;
let fileFormat = `${ext}+zip`;
let downHref = bookInfo.link;
if (ext === 'mobi') {
fileFormat = 'x-mobipocket-ebook';
} else if (ext == 'epub') {
//
} else {
downHref = `${bookInfo.link}/zip`;
}
//entry
const e = this.makeEntry({
@@ -183,7 +195,7 @@ class BookPage extends BasePage {
}
//links
e.link = [ this.downLink({href: bookInfo.link, type: `application/${fileFormat}`}) ];
e.link = [ this.downLink({href: downHref, type: `application/${fileFormat}`}) ];
if (bookInfo.cover) {
let coverType = 'image/jpeg';
if (path.extname(bookInfo.cover) == '.png')

View File

@@ -109,9 +109,10 @@ function gzipFile(inputFile, outputFile, level = 1) {
.pipe(gzip).on('error', reject)
.pipe(output).on('error', reject)
.on('finish', (err) => {
if (err) reject(err);
else resolve();
});
if (err) reject(err);
else resolve();
}
);
});
}
@@ -125,9 +126,10 @@ function gunzipFile(inputFile, outputFile) {
.pipe(gzip).on('error', reject)
.pipe(output).on('error', reject)
.on('finish', (err) => {
if (err) reject(err);
else resolve();
});
if (err) reject(err);
else resolve();
}
);
});
}

View File

@@ -1,5 +1,6 @@
const fs = require('fs-extra');
const path = require('path');
const JSZip = require('jszip');
const express = require('express');
const utils = require('./core/utils');
@@ -7,68 +8,95 @@ const webAppDir = require('../build/appdir');
const log = new (require('./core/AppLogger'))().log;//singleton
function generateZip(zipFile, dataFile, data) {
return new Promise((resolve, reject) => {
const zip = new JSZip();
zip.file(dataFile, data)
.generateNodeStream({
streamFiles: true,
compression: 'DEFLATE',
compressionOptions: {level: 6},
}).on('error', reject)
.pipe(fs.createWriteStream(zipFile)).on('error', reject)
.on('finish', (err) => {
if (err) reject(err);
else resolve();
}
);
});
}
module.exports = (app, config) => {
/*
config.bookPathStatic = `${config.rootPathStatic}/book`;
config.bookDir = `${config.publicFilesDir}/book`;
*/
//загрузка или восстановление файлов в /public-files, при необходимости
app.use(config.bookPathStatic, async(req, res, next) => {
app.use([`${config.bookPathStatic}/:fileName/:fileType`, `${config.bookPathStatic}/:fileName`], async(req, res, next) => {
if (req.method !== 'GET' && req.method !== 'HEAD') {
return next();
}
if (path.extname(req.path) == '') {
const bookFile = `${config.bookDir}${req.path}`;
const bookFileDesc = `${bookFile}.d.json`;
try {
const fileName = req.params.fileName;
const fileType = req.params.fileType;
let downFileName = '';
//восстановим из json-файла описания
try {
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');
desc = JSON.parse(desc);
downFileName = desc.downFileName;
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)) {
const data = await fs.readFile(rawFile);
await generateZip(bookFile, downFileName, data);
}
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);
}
if (downFileName) {
res.downFileName = downFileName;
if (!req.acceptsEncodings('gzip')) {
//не принимает gzip, тогда распакуем
const rawFile = `${bookFile}.raw`;
if (!await fs.pathExists(rawFile))
await utils.gunzipFile(bookFile, rawFile);
req.url += '.raw';
res.rawFile = true;
}
}
} catch(e) {
log(LM_ERR, e.message);
}
return next();
});
//заголовки при отдаче
app.use(config.bookPathStatic, express.static(config.bookDir, {
setHeaders: (res) => {
if (res.downFileName) {
if (!res.rawFile)
res.set('Content-Encoding', 'gzip');
res.set('Content-Disposition', `inline; filename*=UTF-8''${encodeURIComponent(res.downFileName)}`);
}
},
}));
//иначе просто отдаем запрошенный файл из /public-files
app.use(config.bookPathStatic, express.static(config.bookDir));
if (config.rootPathStatic) {
//подмена rootPath в файлах статики WebApp при необходимости
@@ -77,18 +105,22 @@ module.exports = (app, config) => {
return next();
}
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`;
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, '');
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();