const { createCipher, createDecipher } = require('crypto'); const { createGzip, createGunzip } = require('zlib'); const combiner = require('stream-combiner'); const copy = require('./copy'); const utils = require('./utils'); module.exports = function sync(source, target, crypt, decrypt) { return new Promise(async (resolve, reject) => { // Generate crypt and decrypt streams const transformStreams = []; if (crypt) { // Set stream to zip transformStreams.push(createGzip()); // Set stream to crypt transformStreams.push(createCipher(crypt.algorithm, crypt.password)); } else if (decrypt) { // Set stream to decrypt transformStreams.push(createDecipher(decrypt.algorithm, decrypt.password)); // Set stream to unzip transformStreams.push(createGunzip()); } const combinedStreams = combiner(transformStreams); try { await syncAction(source, target, combinedStreams); return resolve(); } catch (err) { return reject(err); } }); }; function syncAction(source, target, cryptDecryptTransform) { return new Promise(async (resolve, reject) => { try { // Get stats of source and target const [ statSource, statTarget ] = await Promise.all([ utils.getStats(source), utils.getStats(target) ]); // Source does not exists and target exists, delete target if (statSource === null && statTarget !== null) { await utils.delete(target); return resolve(); } // Dost not exists in the target, copy if (statSource !== null && statTarget === null) { await copy(source, target, cryptDecryptTransform); return resolve(); } if (statSource.isDirectory() && statTarget.isDirectory()) { // Verify if both are directories const nextPaths = await utils.readRecursive(source, target); for (let index = 0; index < nextPaths.length; index++) { const [ nextSource, nextTarget ] = nextPaths[index]; // Start to sync next paths await syncAction(nextSource, nextTarget, cryptDecryptTransform); } } else if (statSource.isFile() && statTarget.isFile()) { // Verify if both are files if (statSource.mtime <= statTarget.mtime) { // Source is newer, copy the new version to the target await copy(source, target, cryptDecryptTransform); } } return resolve(); } catch (err) { return reject(err); } }); }