Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
sakno committed Dec 15, 2011
2 parents 092e5df + 7183816 commit 414be9b
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 1 deletion.
13 changes: 12 additions & 1 deletion Readme.md
Expand Up @@ -196,14 +196,25 @@ The second parameter of the `getParts` function can accept object with the follo

* `uploadId` - upload ID;
* `max-parts` - the maximum number of parts to return in the response body;
* `part-number-marker` - specifies the part after which listing should begin.
* `part-number-marker` - the part number after which listing should begin.

For example:

client.getParts('/test/blob.bin', {'uploadId': '<Upload-Id>', 'max-parts': 3}, function(err, info) { });

These paramaters are described [here](http://docs.amazonwebservices.com/AmazonS3/latest/API/index.html?mpUploadInitiate.html).

### How to resume the multipart upload

If you have partially uploaded file then it is not good solution to use `getParts` function to calculate remainded size and
resume uploading. Use `getUploadInfo` function for this purpose:

client.getUploadInfo('/test/blob.bin', '<Upload-id>', function(err, summary){
console.log(summary.totalSize); //total number of already uploaded bytes, this field can be used to compute offset in the blob
console.log(summary.count); //count of already uploaded parts
console.log(summary.lastPart); //the number of the last uploaded part.
});

## Running Tests

To run the test suite you must first have an S3 account, and create
Expand Down
49 changes: 49 additions & 0 deletions lib/knox/client.js
Expand Up @@ -274,6 +274,42 @@ Client.prototype.getParts = function(filename, parameters, headers, fn){
req.end();
};

/**
* Obtains an array of all uploaded parts.
* @param {String} filename Object name.
* @param {String} uploadInfo Identifier of the multipart uploading session.
* @param {Object} headers Set of advanced headers.
* @param {Function} fn A callback function that
*/
Client.prototype.getAllParts = function(filename, uploadInfo, headers, fn){
if(typeof headers == 'function') {fn = headers; headers = {}; }
this.getParts(filename, uploadInfo, headers, function(err, pinfo){
this.parts = this.parts.concat(pinfo.parts);
if(err) fn(err, null); //if error then returns immediately
else if(pinfo.truncated) fn(null, this.parts); //the last list of parts is obtained
else this.client.getParts(filename, uploadId, headers, arguments.callee);
}.bind({'parts': [], 'client': this}));
};

/**
* Obtains summary informatiob about multipart upload.
* @param {String} filename Object name.
* @param {String} uploadId Identifier of the multipart upload.
* @param {Object} headers Additional request headers.
* @param {Function} fn A callback function that accepts two parameters: err - exception info, summary - an object with the
* following structure: totalSize - size of the all uploaded parts (in bytes), count - count of uploaded parts, lastPart - the number of the last uploaded part.
*/
Client.prototype.getUploadInfo = function(filename, uploadId, headers, fn){
getAllParts(filename, uploadId, headers, function(err, parts){
if(err) fn(err, null);
else{
var totalSize = 0;
for(var i in parts) totalSize += parts[i];
fn(null, {'totalSize': totalSize, 'count': parts.length, 'lastPart': parts.length > 0 ? parts[parts.length - 1].partNumber : null});
}
});
};

/**
* Aborts a multipart upload.
* @param {String} filename Name of the remote object.
Expand Down Expand Up @@ -498,6 +534,19 @@ Client.prototype.headFile = function(filename, headers, fn){
}).end();
};

/**
* Obtains information about uploaded object.
* @param {String} filename
* @param {Object|Function} headers
* @param {Function} fn
*/
Client.prototype.fileInfo = function(filename, headers, fn){
this.headFile(filename, headers, function(res){
if(res.statusCode == 200) fn({'etag': JSON.parse(res.headers['etag']), 'size': JSON.parse(res.headers['content-length']), 'modified': res.headers['last-modified']});
else fn(null);
});
};

/**
* DELETE `filename` with optional `headers.
*
Expand Down
34 changes: 34 additions & 0 deletions test/knox.test.js
Expand Up @@ -184,5 +184,39 @@ module.exports = {
assert.equal(404, res.statusCode);
done();
}).end();
},

'test for multipart upload and commit': function(assert, done){
var resourceName = '/test/blob.bin';
client.beginUpload(resourceName, function(e, upinfo){
assert.ok(e === null);
var buf = new Buffer('Hello, world!', 'utf8');
client.putPart(resourceName, upinfo.uploadId, 1, buf, function(e, pinfo){
assert.ok(e === null);
assert.equal(1, pinfo.partNumber);
assert.ok(pinfo.etag !== null);
client.completeUpload(resourceName, upinfo.uploadId, [pinfo], function(e, cinfo){
assert.ok(e === null);
done();
});
});
});
},

'test for multipart upload and abort': function(assert, done){
var resourceName = '/test/blob.bin';
client.beginUpload(resourceName, function(e, upinfo){
assert.ok(e === null);
var buf = new Buffer('Hello, world!', 'utf8');
client.putPart(resourceName, upinfo.uploadId, 1, buf, function(e, pinfo){
assert.ok(e === null);
assert.equal(1, pinfo.partNumber);
assert.ok(pinfo.etag !== null);
client.abortUpload(resourceName, upinfo.uploadId, function(success){
assert.ok(success);
done();
});
});
});
}
};

0 comments on commit 414be9b

Please sign in to comment.