src/file.js
'use strict';
var bluebird = require('bluebird');
var fs = bluebird.promisifyAll(require('fs'));
var path = require('path');
var rp = require('request-promise');
var request = require('request');
var crypto = require('crypto');
var authorize = require('./authorize.js');
var bucket = require('./bucket.js');
class Upload {
constructor(cache) {
this.Authorize = new authorize(cache);
this.Bucket = new bucket(cache);
}
/**
* Gets the uploadUrl for uploadinga file to b2cloud
*
* @param {string} bucketName - Name of the bucket to get a uploadUrl for
* @param {function} [callback] - Optional callback
*/
getUploadUrl(bucketName, callback) {
var _this = this;
var props = {
auth: this.Authorize.getBasicAuth(callback),
bucket: this.Bucket.getBucketByName(bucketName, callback)
};
return bluebird.props(props).then(function(res) {
var opts = {
url: res.auth.apiUrl + '/b2api/v1/b2_get_upload_url',
headers: {
Authorization: res.auth.authorizationToken
},
body: {
bucketId: res.bucket.bucketId
},
json: true,
method: 'POST'
};
return rp(opts);
}).then(function(response) {
return response;
}).asCallback(callback);
}
/**
* Helper function that automatically generates the uploadUrl, hashes the file and
* uploads it to b2cloud.
*
* @param {string} filePath - The file path to the file you want to upload
* @param {string} bucketName - The bucke to upload the file to.
* @param {function} [callback] - The optional callback
*/
uploadFile(filePath, bucketName, callback) {
var _this = this;
var filename = path.basename(filePath);
var props = {
url: _this.getUploadUrl(bucketName, callback),
stats: fs.statAsync(filePath),
hash: getShaPromise(filePath)
};
return bluebird.props(props).then(function(res) {
var opts = {
url: res.url.uploadUrl,
headers: {
Authorization: res.url.authorizationToken,
"X-Bz-File-Name": filename,
"Content-Type": "b2/x-auto", // @todo allow content-type to be specified
"Content-Length": res.stats.size,
"X-Bz-Content-Sha1": res.hash,
},
method: 'POST'
};
return new bluebird(function(resolve, reject) {
fs.createReadStream(filePath).pipe(request(opts, function(err, res) {
if(res.statusCode === 200) {
resolve(res.body);
} else {
reject(res.body);
}
}));
});
}).asCallback(callback);
}
/**
* Downloads a file from b2cloud
*
* @param {string} name - Name of the file to download
* @param {string} bucketName - Bucket the file resides in
* @param {string} savePath - Path to save the file to
* @param {object} range - The range object used to fetch only a byte range, byte range is inclusive
* @param {number} range.start - The start byte to download
* @param {number} range.end - The end byte to download
* @see https://www.backblaze.com/b2/docs/b2_download_file_by_name.html
* @param {function} [callback] - The optional callback
*/
downloadFile(name, bucketName, savePath, range, callback) {
if(typeof range === 'function') {
callback = range;
}
return this.Authorize.getBasicAuth().then(function(auth) {
var url = auth.downloadUrl + "/file/" + bucketName + "/" + name;
var opts = {
url: url,
headers: {
Authorization: auth.authorizationToken,
},
method: 'GET'
};
if (typeof range === "object" && range !== null) {
opts.headers.range = "bytes=" + range.start + "-" + range.end
}
savePath = path.resolve(savePath);
return new bluebird(function(resolve, reject) {
var download = request(opts);
var headers;
download.on('response', function(res) {
headers = res.headers;
res.pipe(fs.createWriteStream(savePath));
});
download.on('end', function() {
return resolve(headers);
});
});
}).asCallback(callback);
}
}
// Returns a promise that resolves with the hex digest, otherwise rejects
function getShaPromise(filePath) {
return new bluebird(function(resolve, reject) {
var fd = fs.createReadStream(filePath);
var hash = crypto.createHash('sha1');
hash.setEncoding('hex');
fd.on('end', function() {
hash.end();
return resolve(hash.read());
});
fd.on('error', function(err) {
return reject(err);
});
fd.pipe(hash);
});
}
module.exports = Upload;