Добавлено формирование zip-файла (#4)
This commit is contained in:
@@ -128,7 +128,19 @@ class BookPage extends BasePage {
|
|||||||
|
|
||||||
if (bookInfo) {
|
if (bookInfo) {
|
||||||
const {genreMap} = await this.getGenres();
|
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
|
//entry
|
||||||
const e = this.makeEntry({
|
const e = this.makeEntry({
|
||||||
@@ -183,7 +195,7 @@ class BookPage extends BasePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//links
|
//links
|
||||||
e.link = [ this.downLink({href: bookInfo.link, type: `application/${fileFormat}`}) ];
|
e.link = [ this.downLink({href: downHref, type: `application/${fileFormat}`}) ];
|
||||||
if (bookInfo.cover) {
|
if (bookInfo.cover) {
|
||||||
let coverType = 'image/jpeg';
|
let coverType = 'image/jpeg';
|
||||||
if (path.extname(bookInfo.cover) == '.png')
|
if (path.extname(bookInfo.cover) == '.png')
|
||||||
|
|||||||
@@ -111,7 +111,8 @@ function gzipFile(inputFile, outputFile, level = 1) {
|
|||||||
.on('finish', (err) => {
|
.on('finish', (err) => {
|
||||||
if (err) reject(err);
|
if (err) reject(err);
|
||||||
else resolve();
|
else resolve();
|
||||||
});
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +128,8 @@ function gunzipFile(inputFile, outputFile) {
|
|||||||
.on('finish', (err) => {
|
.on('finish', (err) => {
|
||||||
if (err) reject(err);
|
if (err) reject(err);
|
||||||
else resolve();
|
else resolve();
|
||||||
});
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const JSZip = require('jszip');
|
||||||
|
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const utils = require('./core/utils');
|
const utils = require('./core/utils');
|
||||||
@@ -7,68 +8,95 @@ const webAppDir = require('../build/appdir');
|
|||||||
|
|
||||||
const log = new (require('./core/AppLogger'))().log;//singleton
|
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) => {
|
module.exports = (app, config) => {
|
||||||
/*
|
/*
|
||||||
config.bookPathStatic = `${config.rootPathStatic}/book`;
|
config.bookPathStatic = `${config.rootPathStatic}/book`;
|
||||||
config.bookDir = `${config.publicFilesDir}/book`;
|
config.bookDir = `${config.publicFilesDir}/book`;
|
||||||
*/
|
*/
|
||||||
//загрузка или восстановление файлов в /public-files, при необходимости
|
//загрузка или восстановление файлов в /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') {
|
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.extname(req.path) == '') {
|
try {
|
||||||
const bookFile = `${config.bookDir}${req.path}`;
|
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`;
|
const bookFileDesc = `${bookFile}.d.json`;
|
||||||
|
|
||||||
let downFileName = '';
|
|
||||||
//восстановим из json-файла описания
|
//восстановим из json-файла описания
|
||||||
try {
|
|
||||||
if (await fs.pathExists(bookFile) && await fs.pathExists(bookFileDesc)) {
|
if (await fs.pathExists(bookFile) && await fs.pathExists(bookFileDesc)) {
|
||||||
await utils.touchFile(bookFile);
|
await utils.touchFile(bookFile);
|
||||||
await utils.touchFile(bookFileDesc);
|
await utils.touchFile(bookFileDesc);
|
||||||
|
|
||||||
let desc = await fs.readFile(bookFileDesc, 'utf8');
|
let desc = await fs.readFile(bookFileDesc, 'utf8');
|
||||||
desc = JSON.parse(desc);
|
let downFileName = (JSON.parse(desc)).downFileName;
|
||||||
downFileName = 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 {
|
} else {
|
||||||
await fs.remove(bookFile);
|
await fs.remove(bookFile);
|
||||||
await fs.remove(bookFileDesc);
|
await fs.remove(bookFileDesc);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
log(LM_ERR, e.message);
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
|
|
||||||
//заголовки при отдаче
|
//иначе просто отдаем запрошенный файл из /public-files
|
||||||
app.use(config.bookPathStatic, express.static(config.bookDir, {
|
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)}`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (config.rootPathStatic) {
|
if (config.rootPathStatic) {
|
||||||
//подмена rootPath в файлах статики WebApp при необходимости
|
//подмена rootPath в файлах статики WebApp при необходимости
|
||||||
@@ -77,6 +105,7 @@ module.exports = (app, config) => {
|
|||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
const reqPath = (req.path == '/' ? '/index.html' : req.path);
|
const reqPath = (req.path == '/' ? '/index.html' : req.path);
|
||||||
const ext = path.extname(reqPath);
|
const ext = path.extname(reqPath);
|
||||||
if (ext == '.html' || ext == '.js' || ext == '.css') {
|
if (ext == '.html' || ext == '.js' || ext == '.css') {
|
||||||
@@ -90,6 +119,9 @@ module.exports = (app, config) => {
|
|||||||
await fs.writeFile(flagFile, '');
|
await fs.writeFile(flagFile, '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch(e) {
|
||||||
|
log(LM_ERR, e.message);
|
||||||
|
}
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user