|
const util = require('util'); |
|
const AWS = require('aws-sdk'); |
|
const path = require('path'); |
|
|
|
/** |
|
* getClient |
|
* @returns {object} s3 client instance |
|
*/ |
|
const getClient = (function() { |
|
let s3Client; |
|
return function() { |
|
if (s3Client) { |
|
return s3Client; |
|
} |
|
s3Client = new AWS.S3({apiVersion: '2006-03-01'}); |
|
return s3Client; |
|
}; |
|
})(); |
|
|
|
/** |
|
* listDirectory |
|
* @param {array} accumulator - array to accumulate listed files |
|
* @param {string} bucket - the s3 bucket |
|
* @param {string} prefix - the s3 prefix |
|
* @param {string} lastKey - the last key if the results were truncated |
|
* @returns {list} accumulator |
|
*/ |
|
const listDirectory = (list, bucket, prefix, lastKey) => { |
|
if (!list) { |
|
list = []; |
|
} |
|
const s3Client = getClient(); |
|
const params = { |
|
Bucket: bucket, |
|
Prefix: prefix, |
|
}; |
|
|
|
if (lastKey) { |
|
params.NextMarker = lastKey; |
|
} |
|
|
|
return util.promisify(s3Client.listObjects.bind(s3Client))( |
|
params, |
|
).then(data => { |
|
const keys = data.Contents.map(item => { |
|
return item.Key; |
|
}); |
|
list.push(...keys); |
|
if (data.IsTruncated) { |
|
return listDirectory(list, bucket, prefix, keys[keys.length - 1]); |
|
} |
|
return list; |
|
}); |
|
}; |
|
|
|
module.exports = { |
|
/** |
|
* Check for existing key |
|
* @param {string} bucket |
|
* @param {string} prefix |
|
* @returns {promise} |
|
*/ |
|
exists: function(bucket, prefix) { |
|
const s3Client = getClient(); |
|
const params = { |
|
Bucket: bucket, |
|
Key: prefix, |
|
}; |
|
return util.promisify(s3Client.headObject.bind(s3Client))(params).then( |
|
_ => { |
|
return true; |
|
}, |
|
_ => { |
|
return false; |
|
}, |
|
); |
|
}, |
|
|
|
/** |
|
* CleanFolder |
|
* Deletes all items in a folder |
|
* @param {string} bucket |
|
* @param {string} prefix |
|
* @returns {promise} |
|
*/ |
|
cleanFolder: function(bucket, prefix) { |
|
const s3Client = getClient(); |
|
const deleteObjects = s3Client.deleteObjects.bind(s3Client); |
|
return listDirectory([], bucket, prefix).then(data => { |
|
if (!data.length) { |
|
return; |
|
} |
|
const params = { |
|
Bucket: bucket, |
|
Delete: { |
|
Objects: data.map(key => { |
|
return {Key: key}; |
|
}), |
|
}, |
|
}; |
|
return util.promisify(deleteObjects)(params); |
|
}); |
|
}, |
|
|
|
/** |
|
* Copy a folder located at one prefix to another |
|
* @param {string} bucket |
|
* @param {string} sourcePrefix |
|
* @param {string} destPrefix |
|
* @returns {promise} |
|
*/ |
|
copyFolder: function(bucket, sourcePrefix, destPrefix) { |
|
const s3Client = getClient(); |
|
const copyObject = s3Client.copyObject.bind(s3Client); |
|
const list = []; |
|
|
|
return listDirectory(list, bucket, sourcePrefix).then(data => { |
|
if (!data.length) { |
|
return; |
|
} |
|
return Promise.all( |
|
data.map(key => { |
|
const params = { |
|
Bucket: bucket, |
|
CopySource: path.join('/', bucket, key), |
|
Key: key.replace(sourcePrefix, destPrefix), |
|
ACL: 'public-read', |
|
}; |
|
return util.promisify(copyObject)(params); |
|
}), |
|
); |
|
}); |
|
}, |
|
|
|
/** |
|
* uploadFile |
|
* @param {string} bucket |
|
* @param {string} key |
|
* @param {buffer} data |
|
* @param {string} contentType |
|
* @param {string} acl (default='private') |
|
* @returns {promise} |
|
*/ |
|
uploadFile: function(bucket, key, body, contentType, acl = 'private') { |
|
const s3Client = getClient(); |
|
const params = { |
|
Bucket: bucket, |
|
ACL: acl, |
|
Key: key, |
|
Body: body, |
|
ContentType: contentType, |
|
}; |
|
return util.promisify(s3Client.putObject.bind(s3Client))(params); |
|
}, |
|
}; |