From 71af9f0ad21466de13d70f693ceb50633390883e Mon Sep 17 00:00:00 2001 From: Christian Genco Date: Thu, 24 Oct 2013 00:11:10 -0500 Subject: [PATCH] add support for chunked uploads --- README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/dbox.js | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/helpers.js | 3 +++ test/all.js | 2 +- 4 files changed, 111 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 212cf89..5ba5ebd 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ OR, if you just want to start playing with the library run... shares <-- create link to view file media <-- create streamable link to file thumbnails <-- get thumbnail of file + chunk <-- upload a chunk of a large file + commit_chunks <-- complete a chunked upload copyref <-- create copy reference to file delta <-- get list of delta entries stream <-- creates readable stream @@ -468,6 +470,57 @@ output of `metadata` returns... "size": "762.5 KB" } +### chunk(body, [options,] cb) + +Uploads large files to Dropbox in multiple chunks. Also has the ability to resume if the upload is interrupted. This allows for uploads larger than the /files and /files_put maximum of 150 MB. Note that chunks must be submitted in order, else the response will be a 400 error that includes the current offset. + + client.chunk("some data", {offset: 0, upload_id: null}, function(status, reply){ + console.dir(reply); + + require('fs').writeFile('koala_small.jpg', reply, function () { + console.log('Thumbnail saved!'); + }); + }) + +output of `reply` returns... + + { + expires: 'Fri, 25 Oct 2013 04:51:52 +0000', + upload_id: 'nLkA-eBpXUcr07JPq_ShRA', + offset: 4 + } + +Typical usage: + +1. Send your first chunk of your file to `chunk` and receive an upload_id in the reply. +2. Repeatedly submit subsequent chunks using the upload_id to identify the upload in progress and an offset representing the number of bytes transferred so far. +3. After each chunk has been uploaded, the server returns a new offset representing the total amount transferred. +4. After the last chunk, call `commit_chunks` to complete the upload. + +### commit_chunks(path, [options,] callback) + +Completes an upload initiated by `chunk`. Similar to `put`, but takes an `upload_id` instead of `data`. + + client.commit_chunks(filename, {upload_id: 'nLkA-eBpXUcr07JPq_ShRA'}, function(status, reply){ + console.dir(reply) + }) + +output of `reply` returns... + + { + "size": "225.4KB", + "rev": "35e97029684fe", + "thumb_exists": false, + "bytes": 230783, + "modified": "Tue, 19 Jul 2011 21:55:38 +0000", + "path": "/foo/hello.txt", + "is_dir": false, + "icon": "page_white_text", + "root": "sandbox", + "mime_type": "text/plain", + "revision": 220823 + } + ### cpref(path, [options,] callback) client.cpref("song.mp3", function(status, reply){ diff --git a/lib/dbox.js b/lib/dbox.js index d39a258..6a63a41 100644 --- a/lib/dbox.js +++ b/lib/dbox.js @@ -195,6 +195,60 @@ exports.app = function(config){ }) }, + chunk: function(body, args, cb){ + if(!cb){ + cb = args + args = {} + } + + var signature = helpers.sign(options, args) + + var url = helpers.url({ + hostname: "api-content.dropbox.com", + action: "chunked_upload", + // path: path, + root: "", + query: signature + }); + + args["method"] = "PUT"; + args["headers"] = { "content-length": body.length }; + args["url"] = url; + + // do not send empty body + if(body.length > 0) args["body"] = body + + return request(args, function(e, r, b){ + cb(e ? null : r.statusCode, e ? null : helpers.parseJSON(b)) + }) + }, + + commit_chunks: function(path, args, cb){ + if(!cb){ + cb = args + args = null + } + + var signature = helpers.sign(options, args) + + var url = helpers.url({ + hostname: "api-content.dropbox.com", + action: "commit_chunked_upload", + path: path, + query: signature + }) + + var args = { + "method": "POST", + "url": url + } + + return request(args, function(e, r, b){ + cb(e ? null : r.statusCode, e ? null : helpers.parseJSON(b)) + }) + }, + + metadata: function(path, args, cb){ if(!cb){ cb = args diff --git a/lib/helpers.js b/lib/helpers.js index e532ffd..4c7cbcb 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -112,6 +112,9 @@ module.exports = function(config){ // fileops calls desn't want root in path var rootpath = fileop ? "" : root + + // override rootpath if obj.root is specified + if(typeof obj.root !== "undefined" && obj.root !== null) rootpath = obj.root; // fileops calls desn't want scope in path var scopepath = fileop ? "" : scope diff --git a/test/all.js b/test/all.js index 10cc019..eb155f3 100644 --- a/test/all.js +++ b/test/all.js @@ -48,7 +48,7 @@ describe("all", function(){ done() }) }) - + it("should get metadatq of file", function(done) { client.metadata("myfirstfile.txt", function(status, reply){ status.should.eql(200)