Skip to content
Browse files

Add `client#list()` to list all objects in a bucket.

Closes #101, closes #103.
  • Loading branch information...
1 parent b9c5506 commit c8a8631df4c802bda85ecf32098ae438021cee90 @kof kof committed with domenic
Showing with 131 additions and 3 deletions.
  1. +102 −1 lib/client.js
  2. +4 −2 package.json
  3. +25 −0 test/knox.test.js
View
103 lib/client.js
@@ -16,7 +16,9 @@ var Emitter = require('events').EventEmitter
, url = require('url')
, mime = require('mime')
, fs = require('fs')
- , crypto = require('crypto');
+ , crypto = require('crypto')
+ , xml2js = require('xml2js')
+ , qs = require('querystring');
// The max for multi-object delete, bucket listings, etc.
var BUCKET_OPS_MAX = 1000;
@@ -478,6 +480,105 @@ Client.prototype.deleteMultiple = function(filenames, headers, fn){
};
/**
+ * Possible params for Client#list.
+ *
+ * @type {Object}
+ */
+
+var LIST_PARAMS = {
+ delimiter: true
+ , marker: true
+ ,'max-keys': true
+ , prefix: true
+};
+
+/**
+ * Normalization map for Client#list.
+ *
+ * @type {Object}
+ */
+
+var RESPONSE_NORMALIZATION = {
+ MaxKeys: Number,
+ IsTruncated: Boolean,
+ LastModified: Date,
+ Size: Number
+};
+
+/**
+ * Convert data we get from S3 xml in Client#list, since every primitive
+ * value there is a string.
+ *
+ * @type {Object}
+ */
+
+function normalizeResponse(data) {
+ for (var key in data) {
+ var Constr = RESPONSE_NORMALIZATION[key];
+
+ if (Constr) {
+ if (Constr === Date) {
+ data[key] = new Date(data[key]);
+ } else {
+ data[key] = Constr(data[key]);
+ }
+ } else if (Array.isArray(data[key])) {
+ data[key].forEach(normalizeResponse);
+ }
+ }
+}
+
+/**
+ * List up to 1000 objects at a time, with optional `headers`, `params`
+ * and callback `fn` with a possible exception and the response.
+ *
+ * @param {Object|Function} params
+ * @param {Object|Function} headers
+ * @param {Function} fn
+ * @api public
+ */
+
+Client.prototype.list = function(params, headers, fn){
+ if ('function' == typeof headers) {
+ fn = headers;
+ headers = {};
+ }
+
+ if ('function' == typeof params) {
+ fn = params;
+ params = null;
+ }
+
+ if (params && !LIST_PARAMS[Object.keys(params)[0]]) {
+ headers = params;
+ params = null;
+ }
+
+ var url = params ? '?' + qs.stringify(params) : '';
+
+ this.getFile(url, headers, function(err, res){
+ if (err) return fn(err);
+
+ var xmlStr = '';
+
+ res.on('data', function(chunk){
+ xmlStr += chunk;
+ });
+
+ res.on('end', function(){
+ new xml2js.Parser({explicitArray: false, explicitRoot: false})
+ .parseString(xmlStr, function(err, data){
+ if (err) return fn(err);
+
+ delete data.$;
+ normalizeResponse(data);
+ fn(null, data);
+ });
+ }).on('error', fn);
+ });
+};
+
+/**
* Return a url to the given `filename`.
*
* @param {String} filename
View
6 package.json
@@ -6,7 +6,8 @@
"author": "TJ Holowaychuk <tj@learnboost.com>",
"contributors": [
"TJ Holowaychuk <tj@learnboost.com>",
- "Domenic Denicola <domenic@domenicdenicola.com>"
+ "Domenic Denicola <domenic@domenicdenicola.com>",
+ "Oleg Slobodksoi <oleg008@gmail.com>"
],
"license": "MIT",
"main": "./lib/index.js",
@@ -18,7 +19,8 @@
"url": "https://github.com/LearnBoost/knox/issues"
},
"dependencies": {
- "mime": "*"
+ "mime": "*",
+ "xml2js": "0.2.x"
},
"devDependencies": {
"mocha": "*"
View
25 test/knox.test.js
@@ -334,6 +334,31 @@ module.exports = {
});
},
+ 'test .list()': function(done){
+ var files = ['/list/user1.json', '/list/user2.json'];
+
+ client.putFile(jsonFixture, files[0], function(err, res){
+ client.putFile(jsonFixture, files[1], function(err, res){
+ client.list({prefix: 'list'}, function(err, data){
+ assert.ok(!err);
+ assert.equal(data.Prefix, 'list');
+ assert.strictEqual(data.IsTruncated, true);
+ assert.strictEqual(data.MaxKeys, 1000);
+ assert.equal(data.Contents.length, 2);
+ assert.ok(data.Contents[0].LastModified instanceof Date);
+ assert.equal(typeof data.Contents[0].Size, 'number');
+ assert.deepEqual(
+ Object.keys(data.Contents[0]),
+ ['Key', 'LastModified', 'ETag', 'Size', 'Owner', 'StorageClass']
+ );
+ client.deleteMultiple(files, function(err, res) {
+ done();
+ });
+ });
+ });
+ });
+ },
+
'test /?delete': function (done) {
var xml = ['<?xml version="1.0" encoding="UTF-8"?>\n','<Delete>'];
xml.push('<Object><Key>/test/user4.json</Key></Object>');

0 comments on commit c8a8631

Please sign in to comment.
Something went wrong with that request. Please try again.