109 lines
3.0 KiB
JavaScript
109 lines
3.0 KiB
JavaScript
const fs = require('fs-extra');
|
||
const zlib = require('zlib');
|
||
const crypto = require('crypto');
|
||
const path = require('path');
|
||
const utils = require('./utils');
|
||
const decompress = require('decompress');
|
||
const decompressGz = require('decompress-gz');
|
||
const decompressBzip2 = require('decompress-bzip2');
|
||
|
||
const FileDetector = require('./FileDetector');
|
||
|
||
class FileDecompressor {
|
||
constructor() {
|
||
this.detector = new FileDetector();
|
||
}
|
||
|
||
async decompressFile(filename, outputDir) {
|
||
const fileType = await this.detector.detectFile(filename);
|
||
|
||
let result = {
|
||
sourceFile: filename,
|
||
sourceFileType: fileType,
|
||
selectedFile: filename,
|
||
fileListDir: outputDir,
|
||
fileList: []
|
||
};
|
||
|
||
if (!fileType || !(fileType.ext == 'zip' || fileType.ext == 'bz2' || fileType.ext == 'gz')) {
|
||
return result;
|
||
}
|
||
|
||
//дурной decompress, поэтому в 2 этапа
|
||
//этап 1
|
||
let files = [];
|
||
try {
|
||
files = await decompress(filename, outputDir);
|
||
} catch (e) {
|
||
//
|
||
}
|
||
|
||
//этап 2
|
||
if (files.length == 0) {
|
||
try {
|
||
files = await decompress(filename, outputDir, {
|
||
inputFile: filename,
|
||
plugins: [
|
||
decompressGz(),
|
||
decompressBzip2({path: path.basename(filename)}),
|
||
]
|
||
});
|
||
} catch (e) {
|
||
//
|
||
}
|
||
}
|
||
|
||
let sel = filename;
|
||
let fileList = [];
|
||
let max = 0;
|
||
if (files.length) {
|
||
//ищем файл с максимальным размером
|
||
for (let file of files) {
|
||
fileList.push(file.path);
|
||
if (file.data.length > max) {
|
||
sel = `${outputDir}/${file.path}`;
|
||
max = file.data.length;
|
||
}
|
||
}
|
||
}
|
||
//дурной decompress
|
||
if (sel != filename)
|
||
await fs.chmod(sel, 0o664);
|
||
|
||
result.selectedFile = sel;
|
||
result.fileList = fileList;
|
||
|
||
if (sel != filename) {
|
||
result.nesting = await this.decompressFile(sel, `${outputDir}/${utils.randomHexString(10)}`);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
async gzipBuffer(buf) {
|
||
return new Promise((resolve, reject) => {
|
||
zlib.gzip(buf, {level: 1}, (err, result) => {
|
||
if (err) reject(err);
|
||
resolve(result);
|
||
});
|
||
});
|
||
}
|
||
|
||
async gzipFileIfNotExists(filename, outDir) {
|
||
const buf = await fs.readFile(filename);
|
||
|
||
const hash = crypto.createHash('sha256').update(buf).digest('hex');
|
||
|
||
const outFilename = `${outDir}/${hash}`;
|
||
|
||
if (!await fs.pathExists(outFilename)) {
|
||
await fs.writeFile(outFilename, await this.gzipBuffer(buf))
|
||
} else {
|
||
await utils.touchFile(outFilename);
|
||
}
|
||
|
||
return outFilename;
|
||
}
|
||
}
|
||
|
||
module.exports = FileDecompressor; |