UNPKG

@cool-midway/cache-manager-fs-hash

Version:
118 lines (104 loc) 4.22 kB
const promisify = require('util').promisify; const fs = require('fs'); const zlib = require('zlib'); exports.write = async function (path, data, options) { const externalBuffers = []; let dataString = JSON.stringify(data, function replacerFunction(k, value) { //Buffers searilize to {data: [...], type: "Buffer"} if (value && value.type === 'Buffer' && value.data && value.data.length >= 1024 /* only save bigger Buffers external, small ones can be inlined */) { const buffer = Buffer.from(value.data); externalBuffers.push({ index: externalBuffers.length, buffer: buffer, }); return { type: 'ExternalBuffer', index: externalBuffers.length - 1, size: buffer.length, }; } else if (value === Infinity || value === -Infinity) { return { type: 'Infinity', sign: Math.sign(value) }; } else { return value; } }); let zipExtension = ''; if (options.zip) { zipExtension = '.gz'; dataString = await promisify(zlib.deflate)(dataString); } //save main json file await promisify(fs.writeFile)(path + '.json' + zipExtension, dataString, 'utf8'); //save external buffers await Promise.all(externalBuffers.map(async function (externalBuffer) { let buffer = externalBuffer.buffer; if (options.zip) { buffer = await promisify(zlib.deflate)(buffer); } await promisify(fs.writeFile)(path + '-' + externalBuffer.index + '.bin' + zipExtension, buffer, 'utf8'); })); }; exports.read = async function (path, options) { let zipExtension = ''; if (options.zip) { zipExtension = '.gz'; } //read main json file let dataString; if (options.zip) { const compressedData = await promisify(fs.readFile)(path + '.json' + zipExtension); dataString = (await promisify(zlib.unzip)(compressedData)).toString(); } else { dataString = await promisify(fs.readFile)(path + '.json' + zipExtension, 'utf8'); } const externalBuffers = []; const data = JSON.parse(dataString, function bufferReceiver(k, value) { if (value && value.type === 'Buffer' && value.data) { return Buffer.from(value.data); } else if (value && value.type === 'ExternalBuffer' && typeof value.index === 'number' && typeof value.size === 'number') { //JSON.parse is sync so we need to return a buffer sync, we will fill the buffer later const buffer = Buffer.alloc(value.size); externalBuffers.push({ index: +value.index, buffer: buffer, }); return buffer; } else if (value && value.type === 'Infinity' && typeof value.sign === 'number') { return Infinity * value.sign; } else { return value; } }); //read external buffers await Promise.all(externalBuffers.map(async function (externalBuffer) { if (options.zip) { const bufferCompressed = await promisify(fs.readFile)(path + '-' + +externalBuffer.index + '.bin' + zipExtension); const buffer = await promisify(zlib.unzip)(bufferCompressed); buffer.copy(externalBuffer.buffer); } else { const fd = await promisify(fs.open)(path + '-' + +externalBuffer.index + '.bin' + zipExtension, 'r'); await promisify(fs.read)(fd, externalBuffer.buffer, 0, externalBuffer.buffer.length, 0); await promisify(fs.close)(fd); } })); return data; }; exports.delete = async function (path, options) { let zipExtension = ''; if (options.zip) { zipExtension = '.gz'; } await promisify(fs.unlink)(path + '.json' + zipExtension); //delete binary files try { for (let i = 0; i < Infinity; i++) { await promisify(fs.unlink)(path + '-' + i + '.bin' + zipExtension); } } catch (err) { if (err.code === 'ENOENT') { // every binary is deleted, we are done } else { throw err; } } };