diff --git a/server/core/LibSharedStorage/MegaStorage.js b/server/core/LibSharedStorage/MegaStorage.js new file mode 100644 index 00000000..de5b5df8 --- /dev/null +++ b/server/core/LibSharedStorage/MegaStorage.js @@ -0,0 +1,70 @@ +const fs = require('fs-extra'); +const path = require('path'); +const ZipStreamer = require('../ZipStreamer'); + +const utils = require('../utils'); + +class MegaStorage { + constructor() { + this.readingFiles = false; + this.stats = null; + } + + async init(config) { + this.config = config; + this.megaStorageDir = config.megaStorageDir; + this.compressLevel = (config.compressLevel ? config.compressLevel : 4); + await fs.ensureDir(this.megaStorageDir); + } + + async nameHash(filename) { + const hash = utils.toBase36(await utils.getFileHash(filename, 'sha1')); + const hashPath = `${hash.substr(0, 2)}/${hash.substr(2, 2)}/${hash}`; + const fullHashPath = `${this.megaStorageDir}/${hashPath}`; + return { + filename, + hash, + hashPath, + fullHashPath, + zipPath: `${fullHashPath}.zip`, + descPath: `${fullHashPath}.desc`, + }; + } + + async checkFileExists(nameHash) { + return await fs.pathExists(nameHash.zipPath); + } + + async addFile(nameHash, desc = null, force = false) { + if (await this.checkFileExists(nameHash) && !force) + return false; + + await fs.ensureDir(path.dirname(nameHash.zipPath)); + const zip = new ZipStreamer(); + let entry = {}; + let resultFile = await zip.pack(nameHash.zipPath, [nameHash.filename], {zlib: {level: this.compressLevel}}, (ent) => { + entry = ent; + }); + + if (desc) { + desc = Object.assign({}, desc, {fileSize: entry.size, zipFileSize: resultFile.size}); + this.updateDesc(nameHash, desc); + } + return desc; + } + + async updateDesc(nameHash, desc) { + await fs.writeFile(nameHash.descPath, JSON.stringify(desc, null, 2)); + } + + async readFiles(callback) { + } + + async stopReadFiles() { + } + + async getStats(gather = false) { + } +} + +module.exports = MegaStorage; \ No newline at end of file diff --git a/server/core/ZipStreamer.js b/server/core/ZipStreamer.js new file mode 100644 index 00000000..7c6b1a30 --- /dev/null +++ b/server/core/ZipStreamer.js @@ -0,0 +1,59 @@ +const fs = require('fs-extra'); +const path = require('path'); + +const zipStream = require('zip-stream'); +const unzipStream = require('node-stream-zip'); + +class ZipStreamer { + constructor() { + } + + //TODO: сделать рекурсивный обход директорий, пока только файлы + //files = ['filename', 'dirname/'] + pack(zipFile, files, options, entryCallback) { + return new Promise((resolve, reject) => { (async() => { + entryCallback = (entryCallback ? entryCallback : () => {}); + const zip = new zipStream(options); + + const outputStream = fs.createWriteStream(zipFile); + + outputStream.on('error', reject); + outputStream.on('finish', async() => { + let file = {path: zipFile}; + try { + file.size = (await fs.stat(zipFile)).size; + } catch (e) { + reject(e); + } + resolve(file); + }); + + zip.on('error', reject); + zip.pipe(outputStream); + + const zipAddEntry = (filename) => { + return new Promise((resolve, reject) => { + const basename = path.basename(filename); + const source = fs.createReadStream(filename); + + zip.entry(source, {name: basename}, (err, entry) => { + if (err) reject(err); + resolve(entry); + }); + }); + }; + + for (const filename of files) { + const entry = await zipAddEntry(filename); + entryCallback({path: entry.name, size: entry.size, compressedSize: entry.csize}); + } + + zip.finish(); + })().catch(reject); }); + } + + unpack(zipFile, entryCallback) { + } +} + +module.exports = ZipStreamer; \ No newline at end of file