'use strict'
var crypto = require('crypto')
var async = require('async')
var util = require('util')
var zlib = require('zlib')
var constants = require('../constants/general.server.constants')
var fs = require('fs-extra')
var path = require('path')
function localFileHandler (options) {
options = options || {}
var hashKey = options.hashkey || function (value) {
return crypto.createHash('md5').update(value).digest('hex')
}
if (!options.encryption) {
throw new Error('options.encryption is required')
}
var encryption = options.encryption
if (!options.destination) {
throw new Error('options.destination is required')
}
var destination = options.destination
return {
getFolderDestination: function (storageUnit, scope, key, callback) {
var filePrefix = hashKey(key)
var firstLevel = filePrefix.substring(0, 3)
var secondLevel = filePrefix.substring(3, 6)
var storeFileLocation = path.join(destination, storageUnit, scope, firstLevel, secondLevel)
try {
fs.existsSync(storeFileLocation) || fs.mkdirsSync(storeFileLocation)
} catch (err) {
return callback(err)
}
return callback(null, storeFileLocation)
},
saveStream: function (storageUnit, scope, key, filename, mimetype, stream, encrypt, compress, callback) {
this.getFolderDestination(storageUnit, scope, key, function (err, destinationFolder) {
if (err) {
return callback(err)
}
var encodedFilename = hashKey(key) + '-' + filename
var finalPath = path.join(destinationFolder, encodedFilename)
var outStream = fs.createWriteStream(finalPath)
async.waterfall([
function (wfNext) {
if (encrypt === true) {
var encKey = encryption.generateKeyId()
var encIv = encryption.generateiv()
encryption.getCipher(storageUnit, encKey, encIv, function (err, cipher) {
wfNext(err, cipher, encKey, encIv)
})
} else {
wfNext(null, null, null, null)
}
},
function (cipher, encKey, encIv, wfNext) {
if (compress === true) {
stream = stream.pipe(zlib.createDeflate())
}
if (encrypt === true) {
stream = stream.pipe(cipher)
}
stream.pipe(outStream)
outStream.on('error', wfNext)
outStream.on('finish', function () {
wfNext(null, destinationFolder, finalPath, outStream.bytesWritten, encKey, encIv, (compress === true))
})
}
], callback)
})
},
getStream: function (storageUnit, scope, key, srFileId, encKey, encIv, isCompressed, callback) {
var self = this
async.waterfall([
function (wfNext) {
self.getFolderDestination(storageUnit, scope, key, function (err, destinationFolder) {
if (err) {
return wfNext(err)
}
var encodedFilename = hashKey(key) + '-' + srFileId
var fileLocation = path.join(destinationFolder, encodedFilename)
var fileStream = fs.createReadStream(fileLocation)
wfNext(null, fileStream)
})
},
function (fileStream, wfNext) {
if (!util.isNullOrUndefined(encKey)) {
encryption.getDecipher(storageUnit, encKey, encIv, function (err, decipher) {
wfNext(err, fileStream.pipe(decipher))
})
} else {
wfNext(null, fileStream)
}
}, function (fileStream, wfNext) {
if (isCompressed === true) {
wfNext(null, fileStream.pipe(zlib.createInflate()))
} else {
wfNext(null, fileStream)
}
}], callback)
},
deletePath: function (path, callback) {
if (callback) {
return fs.remove(path, callback)
}
return fs.removeSync(path)
},
deleteFileById: function (storageUnit, scope, key, srFileId, callback) {
var self = this
self.getFolderDestination(storageUnit, scope, key, function (err, destination) {
if (err) {
return callback(err)
}
var hashedKey = hashKey(key)
var filePath = path.join(destination, hashedKey + '-' + srFileId)
self.deletePath(filePath, callback)
})
},
deleteFilesByKey: function (storageUnit, scope, key, callback) {
var self = this
var hashedKey = hashKey(key)
if (scope === constants.recordScope) {
var filePath = path.join(destination, storageUnit, '*', '*', '*', hashedKey + '-*')
self.deletePath(filePath, callback)
} else {
self.getFolderDestination(storageUnit, scope, key, function (err, destination) {
if (err) {
return callback(err)
}
var filePath = path.join(destination, hashedKey + '-*')
self.deletePath(filePath, callback)
})
}
},
deleteFilesByScope: function (storageUnit, scope, callback) {
var scopeLocation = path.join(destination, storageUnit, scope)
this.deletePath(scopeLocation, callback)
},
deleteFilesByStorageUnit: function (storageUnit, callback) {
var storageUnitLocation = path.join(destination, storageUnit)
this.deletePath(storageUnitLocation, callback)
},
changeFileNameToId: function (storageUnit, scope, key, filename, srFileId, callback) {
this.getFolderDestination(storageUnit, scope, key, function (err, destination) {
if (err) {
return callback(err)
}
var hashedKey = hashKey(key)
var inFilePath = path.join(destination, hashedKey + '-' + filename)
var outFilePath = path.join(destination, hashedKey + '-' + srFileId)
fs.rename(inFilePath, outFilePath, function (err) {
callback(err, outFilePath)
})
})
},
fileExists: function (path, callback) {
if (callback) {
return fs.exists(path, callback)
}
return fs.existsSync(path)
}
}
}
module.exports = localFileHandler
|