Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[api test] Added basic cache for local files. Added functionality and…

… tests for StorageObject.save
  • Loading branch information...
commit c6cae545acc7488d55d22173986ebf7b9bac97df 1 parent fccbe3f
@indexzero indexzero authored
View
2  .gitignore
@@ -0,0 +1,2 @@
+.cache/
+.cache/*
View
4 lib/cloudfiles/container.js
@@ -23,8 +23,8 @@ var Container = function (details) {
Container.prototype = {
// Remark: Not fully implemented
- addFile: function (file, data, callback) {
- cloudfiles.addFile(this.name, file, data, callback);
+ addFile: function (file, local, callback) {
+ cloudfiles.addFile(this.name, file, local, callback);
},
destory: function (callback) {
View
69 lib/cloudfiles/core.js
@@ -7,6 +7,8 @@
*/
var http = require('http'),
+ fs = require('fs'),
+ path = require('path'),
eyes = require('eyes'),
url = require('url'),
request = require('request'),
@@ -34,20 +36,22 @@ core.setAuth = function (options, callback) {
}
};
- request(authOptions, function (err, res, body) {
- if (err) {
- callback(err);
- return;
- }
-
- cloudfiles.config.serverUrl = res.headers['x-server-management-url'];
- cloudfiles.config.storageUrl = res.headers['x-storage-url'];
- cloudfiles.config.cdnUrl = res.headers['x-cdn-management-url'];
- cloudfiles.config.authToken = res.headers['x-auth-token'];
- cloudfiles.config.storageToken = res.headers['x-storage-token']
-
- callback(null, res);
- });
+ utils.statOrMkdir(cloudfiles.config.cache.path, function () {
+ request(authOptions, function (err, res, body) {
+ if (err) {
+ callback(err);
+ return;
+ }
+
+ cloudfiles.config.serverUrl = res.headers['x-server-management-url'];
+ cloudfiles.config.storageUrl = res.headers['x-storage-url'];
+ cloudfiles.config.cdnUrl = res.headers['x-cdn-management-url'];
+ cloudfiles.config.authToken = res.headers['x-auth-token'];
+ cloudfiles.config.storageToken = res.headers['x-storage-token']
+
+ callback(null, res);
+ });
+ });
};
core.getContainers = function () {
@@ -134,19 +138,32 @@ core.getFiles = function (container, callback) {
});
};
-core.getFile = function (container, fileName, callback) {
- utils.rackspace(utils.storageUrl(container, fileName), callback, function (body, res) {
- var file = {
- content_type: res.headers['content-type'],
- bytes: res.headers['content-length'],
- hash: res.headers['etag'],
- last_modified: res.headers['last-modified'],
- data: body,
- container: container,
- name: fileName
+core.getFile = function (container, filename, callback) {
+ var containerPath = path.join(cloudfiles.config.cache.path, container);
+
+ utils.statOrMkdir(containerPath, function () {
+ var cachePath = path.join(containerPath, filename);
+ fileStream = fs.createWriteStream(cachePath);
+
+ var options = {
+ method: 'GET',
+ uri: utils.storageUrl(container, filename),
+ responseBodyStream: fileStream
};
-
- callback(null, new (cloudfiles.StorageObject)(file));
+
+ utils.rackspace(options, callback, function (body, res) {
+ var file = {
+ content_type: res.headers['content-type'],
+ bytes: res.headers['content-length'],
+ hash: res.headers['etag'],
+ last_modified: res.headers['last-modified'],
+ local: cachePath,
+ container: container,
+ name: filename
+ };
+
+ callback(null, new (cloudfiles.StorageObject)(file));
+ });
});
};
View
49 lib/cloudfiles/storage-object.js
@@ -9,6 +9,8 @@
require.paths.unshift(require('path').join(__dirname, '..'));
var cloudfiles = require('cloudfiles'),
+ fs = require('fs'),
+ eyes = require('eyes'),
sys = require('sys'),
utils = require('./utils');
@@ -95,6 +97,39 @@ StorageObject.prototype = {
// TODO: Finish writing this method
},
+ save: function (options, callback) {
+ var self = this;
+ var fileStream = fs.createWriteStream(options.local, {
+ flags: options.flags || 'w+',
+ encoding: options.encoding || null,
+ mode: options.mode || 0666
+ });
+
+ fs.readFile(this.local, function (err, data) {
+ if (err) {
+ callback(err);
+ return;
+ }
+
+ function endWrite() {
+ fileStream.end();
+ callback(null, options.local);
+ }
+
+ var written = false;
+ fileStream.on('drain', function () {
+ if (!written) {
+ endWrite();
+ }
+ });
+
+ written = fileStream.write(data);
+ if (written) {
+ endWrite();
+ }
+ });
+ },
+
update: function (data, callback) {
},
@@ -111,13 +146,13 @@ StorageObject.prototype = {
// TODO: Should probably take this in from details or something.
this.metadata = {};
- this.container = details.container;
- this.name = details.name;
- this.hash = details.hash;
- this.bytes = details.bytes;
- this.data = details.data;
- this.contentType = details.content_type;
- this.lastModified = details.last_modified;
+ this.container = details.container || null;
+ this.name = details.name || null;
+ this.hash = details.hash || null;
+ this.bytes = details.bytes || null;
+ this.local = details.local || null;
+ this.contentType = details.content_type || null;
+ this.lastModified = details.last_modified || null;
},
_createHeaders: function (metadata) {
View
28 lib/cloudfiles/utils.js
@@ -48,7 +48,28 @@ var successCodes = {
// Export the set of Success Codes
utils.successCodes = successCodes;
+
+//
+// Checks if a directory exists. If not, creates that directory
+//
+utils.statOrMkdir = function (path, callback) {
+ fs.stat(path, function (err, stats) {
+ if (err) {
+ fs.mkdir(path, 0755, function (err) {
+ if (err) {
+ callback(err);
+ return;
+ }
+
+ callback(null, path);
+ });
+ return;
+ }
+ callback(null, path);
+ });
+}
+
//
// Core method that actually sends requests to Rackspace.
// This method is designed to be flexible w.r.t. arguments
@@ -71,7 +92,7 @@ utils.rackspace = function () {
var args = Array.prototype.slice.call(arguments),
success = (typeof(args[args.length - 1]) === 'function') && args.pop(),
callback = (typeof(args[args.length - 1]) === 'function') && args.pop(),
- uri, method, requestBody, headers = {};
+ uri, method, requestBody, responseBodyStream, headers = {};
// Now that we've popped off the two callbacks
// We can make decisions about other arguments
@@ -87,6 +108,7 @@ utils.rackspace = function () {
uri = args[0]['uri'];
requestBody = args[0]['body'];
headers = args[0]['headers'] || {};
+ responseBodyStream = args[0]['responseBodyStream'] || null;
}
}
else {
@@ -111,6 +133,10 @@ utils.rackspace = function () {
serverOptions.body = requestBody;
}
+ if (responseBodyStream) {
+ serverOptions.responseBodyStream = responseBodyStream;
+ }
+
request(serverOptions, function (err, res, body) {
if (err) {
if (callback) {
View
22 test/storage-object-test.js
@@ -71,7 +71,6 @@ vows.describe('node-cloudfiles/storage-object').addBatch({
cloudfiles.getFile('test_container', 'file2.txt', this.callback);
},
"should return a valid StorageObject": function (err, file) {
- assert.equal(file.data.length, sampleData.length);
helpers.assertFile(file);
testData.file = file;
}
@@ -80,6 +79,27 @@ vows.describe('node-cloudfiles/storage-object').addBatch({
}
}).addBatch({
"The node-cloudfiles client": {
+ "an instance of StorageObject": {
+ "the save() method": {
+ topic: function () {
+ var self = this;
+ testData.file.save({ local: path.join(__dirname, 'data', 'fillerama2.txt') }, function (err, filename) {
+ if (err) {
+ self.callback(err);
+ }
+
+ fs.stat(filename, self.callback)
+ });
+ },
+ "should write the file to the specified location": function (err, stats) {
+ assert.isNull(err);
+ assert.isNotNull(stats);
+ }
+ }
+ }
+ }
+}).addBatch({
+ "The node-cloudfiles client": {
"the destroyFile() method": {
"for a file that exists": {
topic: function () {
Please sign in to comment.
Something went wrong with that request. Please try again.