Initial commits

This commit is contained in:
Raymond Feng 2013-06-24 14:07:12 -07:00
parent a8dcc3e15a
commit 5b3d431488
6 changed files with 286 additions and 0 deletions

2
.gitignore vendored
View File

@ -12,3 +12,5 @@ logs
results
npm-debug.log
.idea
node_modules

22
app.js Normal file
View File

@ -0,0 +1,22 @@
var storage = require('pkgcloud').storage;
var client = storage.createClient({
provider: 'rackspace',
username: 'your-user-name',
apiKey: 'your-api-key'
});
// Container
client.getContainers(function (err, containers) { });
client.createContainer(options, function (err, container) { });
client.destroyContainer(containerName, function (err) { });
client.getContainer(containerName, function (err, container) { });
// File
client.upload(options, function (err) { });
client.download(options, function (err) { });
client.getFiles(container, function (err, files) { });
client.getFile(container, file, function (err, server) { });
client.removeFile(container, file, function (err) { });

162
lib/providers/file.js Normal file
View File

@ -0,0 +1,162 @@
/**
* File system based on storage provider
*/
var fs = require('fs'),
path = require('path'),
async = require('async');
module.exports = FileSystemProvider;
function FileSystemProvider(options) {
options = options || {};
this.root = options.root;
var stat = fs.statSync(this.root);
if (!stat.isDirectory()) {
throw new Error('Invalid directory: ' + this.root);
}
}
var namePattern = new RegExp('[^' + path.sep + '/]+');
function validateName(name, cb) {
if (!name) {
cb && process.nextTick(cb.bind(null, new Error('Invalid name: ' + name)));
return false;
}
var match = namePattern.exec(name);
if (match && match.index === 0 && match[0].length === name.length) {
return true;
} else {
cb && process.nextTick(cb.bind(null, new Error('Invalid name: ' + name)));
return false;
}
}
// Container related functions
FileSystemProvider.prototype.getContainers = function (cb) {
var self = this;
fs.readdir(self.root, function (err, files) {
var dirs = [];
var tasks = [];
files.forEach(function (f) {
tasks.push(fs.stat.bind(null, path.join(self.root, f)));
});
async.parallel(tasks, function (err, stats) {
if (err) {
cb && cb(err);
} else {
stats.forEach(function (stat, index) {
if (stat.isDirectory()) {
dirs.push(files[index]);
}
});
cb && cb(err, dirs);
}
});
});
}
FileSystemProvider.prototype.createContainer = function (options, cb) {
var name = options.name;
var mode = options.mode || 0777;
validateName(name, cb) && fs.mkdir(path.join(this.root, name), options, cb);
}
FileSystemProvider.prototype.destroyContainer = function (containerName, cb) {
if(!validateName(containerName, cb)) return;
var dir = path.join(this.root, containerName);
fs.readdir(dir, function (err, files) {
var tasks = [];
files.forEach(function (f) {
tasks.push(fs.unlink.bind(null, f));
});
async.parallel(tasks, function (err) {
if (err) {
cb && cb(err);
} else {
fs.rmdir(dir, cb);
}
});
});
}
FileSystemProvider.prototype.getContainer = function (containerName, cb) {
if(!validateName(containerName, cb)) return;
var dir = path.join(this.root, containerName);
fs.stat(dir, cb);
}
// File related functions
FileSystemProvider.prototype.upload = function (options, cb) {
var container = options.container;
if(!validateName(container, cb)) return;
var file = options.remote;
if(!validateName(file, cb)) return;
var filePath = path.join(this.root, container, file);
var fileOpts = {flags: 'w+',
encoding: null,
mode: 0666 };
return fs.createWriteStream(filePath, fileOpts);
}
FileSystemProvider.prototype.download = function (options, cb) {
var container = options.container;
if(!validateName(container, cb)) return;
var file = options.remote;
if(!validateName(file, cb)) return;
var filePath = path.join(this.root, container, file);
var fileOpts = {flags: 'r',
autoClose: true };
return fs.createReadStream(filePath, fileOpts);
}
FileSystemProvider.prototype.getFiles = function (container, cb) {
if(!validateName(container, cb)) return;
var dir = path.join(this.root, container);
fs.readdir(dir, function (err, files) {
var dirs = [];
var tasks = [];
files.forEach(function (f) {
tasks.push(fs.stat.bind(null, f));
});
async.parallel(tasks, function (err, stats) {
if (err) {
cb && cb(err);
} else {
stats.forEach(function (stat, index) {
if (stat.isFile()) {
dirs.push(files[index]);
}
});
cb && cb(err, dirs);
}
});
});
}
FileSystemProvider.prototype.getFile = function (container, file, cb) {
if(!validateName(container, cb)) return;
var container = options.container;
if(!validateName(file, cb)) return;
var filePath = path.join(this.root, container, file);
fs.stat(filePath, cb);
}
FileSystemProvider.prototype.removeFile = function (container, file, cb) {
if(!validateName(container, cb)) return;
var container = options.container;
if(!validateName(file, cb)) return;
var filePath = path.join(this.root, container, file);
fs.unlink(filePath, cb);
}

22
package.json Normal file
View File

@ -0,0 +1,22 @@
{
"name": "asteroid-storage-service",
"description": "Asteroid Storage Service",
"version": "0.0.1",
"main": "index.js",
"scripts": {
"test": "./node_modules/.bin/mocha --timeout 30000 test/*test.js"
},
"dependencies": {
"pkgcloud": "latest",
"async": "latest"
},
"devDependencies": {
"mocha": "latest",
"supertest": "latest"
},
"repository": {
"type": "git",
"url": "https://github.com/strongloop/asteroid-storage-service.git"
}
}

76
test/fs.test.js Normal file
View File

@ -0,0 +1,76 @@
var FileSystemProvider = require('../lib/providers/file.js');
var assert = require('assert');
var path = require('path');
describe('FileSystem based storage provider', function () {
var client = null;
it('should require an existing directory as the root', function (done) {
client = new FileSystemProvider({root: path.join(__dirname, 'storage')});
process.nextTick(done);
});
var client = null;
it('should complain if the root directory doesn\'t exist', function (done) {
try {
client = new FileSystemProvider({root: path.join(__dirname, '_storage')});
process.nextTick(done.bind(null, 'Error'));
} catch (err) {
// Should be here
process.nextTick(done);
}
});
it('should return an empty list of containers', function (done) {
client.getContainers(function (err, containers) {
assert(!err);
assert.equal(0, containers.length);
done(err, containers);
});
});
it('should create a new container', function (done) {
client.createContainer({name: 'c1'}, function (err, container) {
assert(!err);
done(err, container);
});
});
it('should get a container c1', function (done) {
client.getContainer('c1', function (err, container) {
assert(!err);
done(err, container);
});
});
it('should not get a container c2', function (done) {
client.getContainer('c2', function (err, container) {
assert(err);
done(null, container);
});
});
it('should return one container', function (done) {
client.getContainers(function (err, containers) {
assert(!err);
assert.equal(1, containers.length);
done(err, containers);
});
});
it('should destroy a container c1', function (done) {
client.destroyContainer('c1', function (err, container) {
assert(!err);
done(err, container);
});
});
it('should not get a container c1 after destroy', function (done) {
client.getContainer('c1', function (err, container) {
assert(err);
done(null, container);
});
});
});

2
test/storage/.storage Normal file
View File

@ -0,0 +1,2 @@
This is the test folder for file system based storage