Merge pull request #260 from mrbatista/feat/promise

add support to promise
This commit is contained in:
Raymond Feng 2019-03-20 07:34:48 -07:00 committed by GitHub
commit 00092b5129
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 291 additions and 22 deletions

View File

@ -18,6 +18,8 @@ var fs = require('fs'),
File = require('./file').File, File = require('./file').File,
Container = require('./container').Container; Container = require('./container').Container;
var utils = require('./../../utils');
module.exports.storage = module.exports; // To make it consistent with pkgcloud module.exports.storage = module.exports; // To make it consistent with pkgcloud
module.exports.File = File; module.exports.File = File;
@ -95,6 +97,8 @@ function populateMetadata(stat, props) {
} }
FileSystemProvider.prototype.getContainers = function(cb) { FileSystemProvider.prototype.getContainers = function(cb) {
cb = cb || utils.createPromiseCallback();
var self = this; var self = this;
fs.readdir(self.root, function(err, files) { fs.readdir(self.root, function(err, files) {
var containers = []; var containers = [];
@ -119,15 +123,20 @@ FileSystemProvider.prototype.getContainers = function(cb) {
} }
}); });
}); });
return cb.promise;
}; };
FileSystemProvider.prototype.createContainer = function(options, cb) { FileSystemProvider.prototype.createContainer = function(options, cb) {
cb = cb || utils.createPromiseCallback();
var self = this; var self = this;
var name = options.name; var name = options.name;
var dir = path.join(this.root, name); var dir = path.join(this.root, name);
validateName(name, cb) && fs.mkdir(dir, options, function(err) { validateName(name, cb) && fs.mkdir(dir, options, function(err) {
if (err) { if (err) {
return cb && cb(err); cb && cb(err);
return;
} }
fs.stat(dir, function(err, stat) { fs.stat(dir, function(err, stat) {
var container = null; var container = null;
@ -139,9 +148,13 @@ FileSystemProvider.prototype.createContainer = function(options, cb) {
cb && cb(err, container); cb && cb(err, container);
}); });
}); });
return cb.promise;
}; };
FileSystemProvider.prototype.destroyContainer = function(containerName, cb) { FileSystemProvider.prototype.destroyContainer = function(containerName, cb) {
cb = cb || utils.createPromiseCallback();
if (!validateName(containerName, cb)) return; if (!validateName(containerName, cb)) return;
var dir = path.join(this.root, containerName); var dir = path.join(this.root, containerName);
@ -160,9 +173,13 @@ FileSystemProvider.prototype.destroyContainer = function(containerName, cb) {
} }
}); });
}); });
return cb.promise;
}; };
FileSystemProvider.prototype.getContainer = function(containerName, cb) { FileSystemProvider.prototype.getContainer = function(containerName, cb) {
cb = cb || utils.createPromiseCallback();
var self = this; var self = this;
if (!validateName(containerName, cb)) return; if (!validateName(containerName, cb)) return;
var dir = path.join(this.root, containerName); var dir = path.join(this.root, containerName);
@ -175,6 +192,8 @@ FileSystemProvider.prototype.getContainer = function(containerName, cb) {
} }
cb && cb(err, container); cb && cb(err, container);
}); });
return cb.promise;
}; };
// File related functions // File related functions
@ -252,6 +271,9 @@ FileSystemProvider.prototype.getFiles = function(container, options, cb) {
cb = options; cb = options;
options = false; options = false;
} }
cb = cb || utils.createPromiseCallback();
var self = this; var self = this;
if (!validateName(container, cb)) return; if (!validateName(container, cb)) return;
var dir = path.join(this.root, container); var dir = path.join(this.root, container);
@ -278,9 +300,13 @@ FileSystemProvider.prototype.getFiles = function(container, options, cb) {
} }
}); });
}); });
return cb.promise;
}; };
FileSystemProvider.prototype.getFile = function(container, file, cb) { FileSystemProvider.prototype.getFile = function(container, file, cb) {
cb = cb || utils.createPromiseCallback();
var self = this; var self = this;
if (!validateName(container, cb)) return; if (!validateName(container, cb)) return;
if (!validateName(file, cb)) return; if (!validateName(file, cb)) return;
@ -294,6 +320,8 @@ FileSystemProvider.prototype.getFile = function(container, file, cb) {
} }
cb && cb(err, f); cb && cb(err, f);
}); });
return cb.promise;
}; };
FileSystemProvider.prototype.getUrl = function(options) { FileSystemProvider.prototype.getUrl = function(options) {
@ -303,9 +331,13 @@ FileSystemProvider.prototype.getUrl = function(options) {
}; };
FileSystemProvider.prototype.removeFile = function(container, file, cb) { FileSystemProvider.prototype.removeFile = function(container, file, cb) {
cb = cb || utils.createPromiseCallback();
if (!validateName(container, cb)) return; if (!validateName(container, cb)) return;
if (!validateName(file, cb)) return; if (!validateName(file, cb)) return;
var filePath = path.join(this.root, container, file); var filePath = path.join(this.root, container, file);
fs.unlink(filePath, cb); fs.unlink(filePath, cb);
return cb.promise;
}; };

View File

@ -6,6 +6,7 @@
var factory = require('./factory'); var factory = require('./factory');
var handler = require('./storage-handler'); var handler = require('./storage-handler');
var utils = require('./utils');
var storage = require('pkgcloud').storage; var storage = require('pkgcloud').storage;
var debug = require('debug')('loopback:storage:service'); var debug = require('debug')('loopback:storage:service');
@ -64,8 +65,11 @@ function map(obj) {
* @callback {Function} callback Callback function * @callback {Function} callback Callback function
* @param {Object|String} err Error string or object * @param {Object|String} err Error string or object
* @param {Object[]} containers An array of container metadata objects * @param {Object[]} containers An array of container metadata objects
* @promise
*/ */
StorageService.prototype.getContainers = function(cb) { StorageService.prototype.getContainers = function(cb) {
cb = cb || utils.createPromiseCallback();
this.client.getContainers(function(err, containers) { this.client.getContainers(function(err, containers) {
if (err) { if (err) {
cb(err, containers); cb(err, containers);
@ -75,6 +79,8 @@ StorageService.prototype.getContainers = function(cb) {
})); }));
} }
}); });
return cb.promise;
}; };
/** /**
@ -85,19 +91,24 @@ StorageService.prototype.getContainers = function(cb) {
* @callback {Function} cb Callback function * @callback {Function} cb Callback function
* @param {Object|String} err Error string or object * @param {Object|String} err Error string or object
* @param {Object} container Container metadata object * @param {Object} container Container metadata object
* @promise
*/ */
StorageService.prototype.createContainer = function(options, cb) { StorageService.prototype.createContainer = function(options, cb) {
options = options || {}; options = options || {};
cb = cb || utils.createPromiseCallback();
if ('object' === typeof options && !(options instanceof storage.Container)) { if ('object' === typeof options && !(options instanceof storage.Container)) {
options.Name = options.name; // Amazon expects Name options.Name = options.name; // Amazon expects Name
var Container = factory.getProvider(this.provider).storage.Container; var Container = factory.getProvider(this.provider).storage.Container;
options = new Container(this.client, options); options = new Container(this.client, options);
} }
debug('Creating container with options %o', options); debug('Creating container with options %o', options);
return this.client.createContainer(options, function(err, container) { this.client.createContainer(options, function(err, container) {
return cb(err, map(container)); return cb(err, map(container));
}); });
return cb.promise;
}; };
/** /**
@ -105,9 +116,13 @@ StorageService.prototype.createContainer = function(options, cb) {
* @param {String} container Container name. * @param {String} container Container name.
* @callback {Function} callback Callback function. * @callback {Function} callback Callback function.
* @param {Object|String} err Error string or object * @param {Object|String} err Error string or object
* @promise
*/ */
StorageService.prototype.destroyContainer = function(container, cb) { StorageService.prototype.destroyContainer = function(container, cb) {
return this.client.destroyContainer(container, cb); cb = cb || utils.createPromiseCallback();
this.client.destroyContainer(container, cb);
return cb.promise;
}; };
/** /**
@ -116,15 +131,20 @@ StorageService.prototype.destroyContainer = function(container, cb) {
* @callback {Function} callback Callback function. * @callback {Function} callback Callback function.
* @param {Object|String} err Error string or object * @param {Object|String} err Error string or object
* @param {Object} container Container metadata object * @param {Object} container Container metadata object
* @promise
*/ */
StorageService.prototype.getContainer = function(container, cb) { StorageService.prototype.getContainer = function(container, cb) {
return this.client.getContainer(container, function(err, container) { cb = cb || utils.createPromiseCallback();
this.client.getContainer(container, function(err, container) {
if (err && err.code === 'ENOENT') { if (err && err.code === 'ENOENT') {
err.statusCode = err.status = 404; err.statusCode = err.status = 404;
return cb(err); return cb(err);
} }
return cb(err, map(container)); return cb(err, map(container));
}); });
return cb.promise;
}; };
/** /**
@ -178,6 +198,7 @@ StorageService.prototype.downloadStream = function(container, file, options) {
* @callback {Function} cb Callback function * @callback {Function} cb Callback function
* @param {Object|String} err Error string or object * @param {Object|String} err Error string or object
* @param {Object[]} files An array of file metadata objects * @param {Object[]} files An array of file metadata objects
* @promise
*/ */
StorageService.prototype.getFiles = function(container, options, cb) { StorageService.prototype.getFiles = function(container, options, cb) {
if (typeof options === 'function' && !cb) { if (typeof options === 'function' && !cb) {
@ -185,7 +206,10 @@ StorageService.prototype.getFiles = function(container, options, cb) {
cb = options; cb = options;
options = {}; options = {};
} }
return this.client.getFiles(container, options, function(err, files) {
cb = cb || utils.createPromiseCallback();
this.client.getFiles(container, options, function(err, files) {
if (err) { if (err) {
cb(err, files); cb(err, files);
} else { } else {
@ -194,6 +218,8 @@ StorageService.prototype.getFiles = function(container, options, cb) {
})); }));
} }
}); });
return cb.promise;
}; };
/** /**
@ -203,15 +229,20 @@ StorageService.prototype.getFiles = function(container, options, cb) {
* @callback {Function} cb Callback function * @callback {Function} cb Callback function
* @param {Object|String} err Error string or object * @param {Object|String} err Error string or object
* @param {Object} file File metadata object * @param {Object} file File metadata object
* @promise
*/ */
StorageService.prototype.getFile = function(container, file, cb) { StorageService.prototype.getFile = function(container, file, cb) {
return this.client.getFile(container, file, function(err, f) { cb = cb || utils.createPromiseCallback();
this.client.getFile(container, file, function(err, f) {
if (err && err.code === 'ENOENT') { if (err && err.code === 'ENOENT') {
err.statusCode = err.status = 404; err.statusCode = err.status = 404;
return cb(err); return cb(err);
} }
return cb(err, map(f)); return cb(err, map(f));
}); });
return cb.promise;
}; };
/** /**
@ -220,9 +251,13 @@ StorageService.prototype.getFile = function(container, file, cb) {
* @param {String} file File name * @param {String} file File name
* @callback {Function} cb Callback function * @callback {Function} cb Callback function
* @param {Object|String} err Error string or object * @param {Object|String} err Error string or object
* @promise
*/ */
StorageService.prototype.removeFile = function(container, file, cb) { StorageService.prototype.removeFile = function(container, file, cb) {
return this.client.removeFile(container, file, cb); cb = cb || utils.createPromiseCallback();
this.client.removeFile(container, file, cb);
return cb.promise;
}; };
/** /**
@ -232,6 +267,7 @@ StorageService.prototype.removeFile = function(container, file, cb) {
* @param {Response} res Response object * @param {Response} res Response object
* @param {Object} [options] Options for upload * @param {Object} [options] Options for upload
* @param {Function} cb Callback function * @param {Function} cb Callback function
* @promise
*/ */
StorageService.prototype.upload = function(container, req, res, options, cb) { StorageService.prototype.upload = function(container, req, res, options, cb) {
debug('Configuring upload with options %o', options); debug('Configuring upload with options %o', options);
@ -247,6 +283,9 @@ StorageService.prototype.upload = function(container, req, res, options, cb) {
cb = options; cb = options;
options = {}; options = {};
} }
cb = cb || utils.createPromiseCallback();
if (this.getFilename && !options.getFilename) { if (this.getFilename && !options.getFilename) {
options.getFilename = this.getFilename; options.getFilename = this.getFilename;
} }
@ -269,7 +308,9 @@ StorageService.prototype.upload = function(container, req, res, options, cb) {
options.container = container; options.container = container;
} }
debug('Upload configured with options %o', options); debug('Upload configured with options %o', options);
return handler.upload(this.client, req, res, options, cb);
handler.upload(this.client, req, res, options, cb);
return cb.promise;
}; };
/** /**
@ -279,9 +320,13 @@ StorageService.prototype.upload = function(container, req, res, options, cb) {
* @param {Request} req HTTP request * @param {Request} req HTTP request
* @param {Response} res HTTP response * @param {Response} res HTTP response
* @param {Function} cb Callback function * @param {Function} cb Callback function
* @promise
*/ */
StorageService.prototype.download = function(container, file, req, res, cb) { StorageService.prototype.download = function(container, file, req, res, cb) {
return handler.download(this.client, req, res, container, file, cb); cb = cb || utils.createPromiseCallback();
handler.download(this.client, req, res, container, file, cb);
return cb.promise;
}; };
StorageService.modelName = 'storage'; StorageService.modelName = 'storage';

15
lib/utils.js Normal file
View File

@ -0,0 +1,15 @@
'use strict';
exports.createPromiseCallback = createPromiseCallback;
function createPromiseCallback() {
var cb;
var promise = new Promise(function(resolve, reject) {
cb = function(err, data) {
if (err) return reject(err);
return resolve(data);
};
});
cb.promise = promise;
return cb;
}

View File

@ -45,11 +45,20 @@ describe('FileSystem based storage provider', function() {
it('should return an empty list of containers', function(done) { it('should return an empty list of containers', function(done) {
client.getContainers(function(err, containers) { client.getContainers(function(err, containers) {
assert(!err); assert(!err);
assert.equal(0, containers.length); assert.equal(containers.length, 0);
done(err, containers); done(err, containers);
}); });
}); });
it('should return an empty list of containers - promise', function(done) {
client.getContainers()
.then(function(containers) {
assert.equal(containers.length, 0);
done();
})
.catch(done);
});
it('should create a new container', function(done) { it('should create a new container', function(done) {
client.createContainer({name: 'c1'}, function(err, container) { client.createContainer({name: 'c1'}, function(err, container) {
assert(!err); assert(!err);
@ -58,6 +67,15 @@ describe('FileSystem based storage provider', function() {
}); });
}); });
it('should create a new container - promise', function(done) {
client.createContainer({name: 'c3'})
.then(function(container) {
verifyMetadata(container, 'c3');
done();
})
.catch(done);
});
it('should get a container c1', function(done) { it('should get a container c1', function(done) {
client.getContainer('c1', function(err, container) { client.getContainer('c1', function(err, container) {
assert(!err); assert(!err);
@ -66,6 +84,15 @@ describe('FileSystem based storage provider', function() {
}); });
}); });
it('should get a container c1 - promise', function(done) {
client.getContainer('c1')
.then(function(container) {
verifyMetadata(container, 'c1');
done();
})
.catch(done);
});
it('should not get a container c2', function(done) { it('should not get a container c2', function(done) {
client.getContainer('c2', function(err, container) { client.getContainer('c2', function(err, container) {
assert(err); assert(err);
@ -73,10 +100,18 @@ describe('FileSystem based storage provider', function() {
}); });
}); });
it('should destroy a container c3 - promise', function(done) {
client.destroyContainer('c3')
.then(function(container) {
done(null, container);
})
.catch(done);
});
it('should return one container', function(done) { it('should return one container', function(done) {
client.getContainers(function(err, containers) { client.getContainers(function(err, containers) {
assert(!err); assert(!err);
assert.equal(1, containers.length); assert.equal(containers.length, 1);
done(err, containers); done(err, containers);
}); });
}); });
@ -167,11 +202,20 @@ describe('FileSystem based storage provider', function() {
it('should get files for a container', function(done) { it('should get files for a container', function(done) {
client.getFiles('c1', function(err, files) { client.getFiles('c1', function(err, files) {
assert(!err); assert(!err);
assert.equal(1, files.length); assert.equal(files.length, 1);
done(err, files); done(err, files);
}); });
}); });
it('should get files for a container - promise', function(done) {
client.getFiles('c1')
.then(function(files) {
assert.equal(files.length, 1);
done();
})
.catch(done);
});
it('should get a file', function(done) { it('should get a file', function(done) {
client.getFile('c1', 'f1.txt', function(err, f) { client.getFile('c1', 'f1.txt', function(err, f) {
assert(!err); assert(!err);
@ -181,6 +225,16 @@ describe('FileSystem based storage provider', function() {
}); });
}); });
it('should get a file - promise', function(done) {
client.getFile('c1', 'f1.txt')
.then(function(f) {
assert.ok(f);
verifyMetadata(f, 'f1.txt');
done();
})
.catch(done);
});
it('should remove a file', function(done) { it('should remove a file', function(done) {
client.removeFile('c1', 'f1.txt', function(err) { client.removeFile('c1', 'f1.txt', function(err) {
assert(!err); assert(!err);
@ -188,29 +242,67 @@ describe('FileSystem based storage provider', function() {
}); });
}); });
it('should remove a file - promise', function(done) {
createFile('c1', 'f1.txt').then(function() {
return client.removeFile('c1', 'f1.txt')
.then(function() {
done();
});
})
.catch(done);
});
it('should get no files from a container', function(done) { it('should get no files from a container', function(done) {
client.getFiles('c1', function(err, files) { client.getFiles('c1', function(err, files) {
assert(!err); assert(!err);
assert.equal(0, files.length); assert.equal(files.length, 0);
done(err, files); done(err, files);
}); });
}); });
it('should get no files from a container - promise', function(done) {
client.getFiles('c1')
.then(function(files) {
assert.equal(files.length, 0);
done();
})
.catch(done);
});
it('should not get a file from a container', function(done) { it('should not get a file from a container', function(done) {
client.getFile('c1', 'f2.txt', function(err, f) { client.getFile('c1', 'f2.txt', function(err, f) {
assert(err); assert(err);
assert.equal('ENOENT', err.code); assert.equal(err.code, 'ENOENT');
assert(!f); assert(!f);
done(); done();
}); });
}); });
it('should not get a file from a container - promise', function(done) {
client.getFile('c1', 'f2.txt')
.then(function() {
throw new Error('should not be throw');
})
.catch(function(err) {
assert.equal(err.code, 'ENOENT');
done();
});
});
it('should destroy a container c1', function(done) { it('should destroy a container c1', function(done) {
client.destroyContainer('c1', function(err, container) { client.destroyContainer('c1', function(err, container) {
// console.error(err);
assert(!err); assert(!err);
done(err, container); done(err, container);
}); });
}); });
function createFile(container, file) {
return new Promise(function(resolve, reject) {
var writer = client.upload({container: container, remote: file});
fs.createReadStream(path.join(__dirname, 'files/f1.txt')).pipe(writer);
writer.on('finish', resolve);
writer.on('error', reject);
});
}
}); });
}); });

View File

@ -19,11 +19,20 @@ describe('Storage service', function() {
it('should return an empty list of containers', function(done) { it('should return an empty list of containers', function(done) {
storageService.getContainers(function(err, containers) { storageService.getContainers(function(err, containers) {
assert(!err); assert(!err);
assert.equal(0, containers.length); assert.equal(containers.length, 0);
done(err, containers); done(err, containers);
}); });
}); });
it('should return an empty list of containers - promise', function(done) {
storageService.getContainers()
.then(function(containers) {
assert.equal(containers.length, 0);
done();
})
.catch(done);
});
it('should create a new container', function(done) { it('should create a new container', function(done) {
storageService.createContainer({name: 'c1'}, function(err, container) { storageService.createContainer({name: 'c1'}, function(err, container) {
assert(!err); assert(!err);
@ -32,6 +41,15 @@ describe('Storage service', function() {
}); });
}); });
it('should create a new container - promise', function(done) {
storageService.createContainer({name: 'c3'})
.then(function(container) {
assert(container.getMetadata());
done();
})
.catch(done);
});
it('should get a container c1', function(done) { it('should get a container c1', function(done) {
storageService.getContainer('c1', function(err, container) { storageService.getContainer('c1', function(err, container) {
assert(!err); assert(!err);
@ -40,6 +58,15 @@ describe('Storage service', function() {
}); });
}); });
it('should get a container c1 - promise', function(done) {
storageService.getContainer('c1')
.then(function(container) {
assert(container.getMetadata());
done();
})
.catch(done);
});
it('should not get a container c2', function(done) { it('should not get a container c2', function(done) {
storageService.getContainer('c2', function(err, container) { storageService.getContainer('c2', function(err, container) {
assert(err); assert(err);
@ -47,10 +74,18 @@ describe('Storage service', function() {
}); });
}); });
it('should destroy a container c3 - promise', function(done) {
storageService.destroyContainer('c3')
.then(function(container) {
done(null, container);
})
.catch(done);
});
it('should return one container', function(done) { it('should return one container', function(done) {
storageService.getContainers(function(err, containers) { storageService.getContainers(function(err, containers) {
assert(!err); assert(!err);
assert.equal(1, containers.length); assert.equal(containers.length, 1);
done(err, containers); done(err, containers);
}); });
}); });
@ -104,11 +139,20 @@ describe('Storage service', function() {
it('should get files for a container', function(done) { it('should get files for a container', function(done) {
storageService.getFiles('c1', function(err, files) { storageService.getFiles('c1', function(err, files) {
assert(!err); assert(!err);
assert.equal(1, files.length); assert.equal(files.length, 1);
done(err, files); done(err, files);
}); });
}); });
it('should get files for a container - promise', function(done) {
storageService.getFiles('c1')
.then(function(files) {
assert.equal(files.length, 1);
done();
})
.catch(done);
});
it('should get a file', function(done) { it('should get a file', function(done) {
storageService.getFile('c1', 'f1.txt', function(err, f) { storageService.getFile('c1', 'f1.txt', function(err, f) {
assert(!err); assert(!err);
@ -118,6 +162,16 @@ describe('Storage service', function() {
}); });
}); });
it('should get a file - promise', function(done) {
storageService.getFile('c1', 'f1.txt')
.then(function(f) {
assert.ok(f);
assert(f.getMetadata());
done();
})
.catch(done);
});
it('should remove a file', function(done) { it('should remove a file', function(done) {
storageService.removeFile('c1', 'f1.txt', function(err) { storageService.removeFile('c1', 'f1.txt', function(err) {
assert(!err); assert(!err);
@ -125,10 +179,21 @@ describe('Storage service', function() {
}); });
}); });
it('should remove a file - promise', function(done) {
createFile('c1', 'f1.txt')
.then(function() {
return storageService.removeFile('c1', 'f1.txt')
.then(function() {
done();
});
})
.catch(done);
});
it('should get no files from a container', function(done) { it('should get no files from a container', function(done) {
storageService.getFiles('c1', function(err, files) { storageService.getFiles('c1', function(err, files) {
assert(!err); assert(!err);
assert.equal(0, files.length); assert.equal(files.length, 0);
done(err, files); done(err, files);
}); });
}); });
@ -136,19 +201,39 @@ describe('Storage service', function() {
it('should not get a file from a container', function(done) { it('should not get a file from a container', function(done) {
storageService.getFile('c1', 'f1.txt', function(err, f) { storageService.getFile('c1', 'f1.txt', function(err, f) {
assert(err); assert(err);
assert.equal('ENOENT', err.code); assert.equal(err.code, 'ENOENT');
assert.equal(404, err.status); assert.equal(err.status, 404);
assert(!f); assert(!f);
done(); done();
}); });
}); });
it('should not get a file from a container - promise', function(done) {
storageService.getFile('c1', 'f1.txt')
.then(function() {
throw new Error('should not be throw');
})
.catch(function(err) {
assert.equal(err.code, 'ENOENT');
assert.equal(err.status, 404);
done();
});
});
it('should destroy a container c1', function(done) { it('should destroy a container c1', function(done) {
storageService.destroyContainer('c1', function(err, container) { storageService.destroyContainer('c1', function(err, container) {
// console.error(err);
assert(!err); assert(!err);
done(err, container); done(err, container);
}); });
}); });
function createFile(container, file) {
return new Promise(function(resolve, reject) {
var writer = storageService.uploadStream(container, file);
fs.createReadStream(path.join(__dirname, 'files/f1.txt')).pipe(writer);
writer.on('finish', resolve);
writer.on('error', reject);
});
}
}); });
}); });