Comparing version 0.7.0 to 0.8.0
# WebDAV-client changelog | ||
## 0.8.0 | ||
_2017-06-07_ | ||
* Add stream support (GET) | ||
* Add `createReadStream` method | ||
* Add `getFileStream` method | ||
* Update option merging behaviour for default values | ||
## 0.7.0 | ||
@@ -4,0 +12,0 @@ _2017-06-03_ |
{ | ||
"name": "webdav", | ||
"version": "0.7.0", | ||
"version": "0.8.0", | ||
"description": "WebDAV client for NodeJS", | ||
@@ -5,0 +5,0 @@ "main": "source/index.js", |
@@ -29,5 +29,2 @@ # WebDAV client | ||
console.log(JSON.stringify(contents, undefined, 4)); | ||
}) | ||
.catch(function(err) { | ||
console.error(err); | ||
}); | ||
@@ -44,2 +41,7 @@ ``` | ||
#### createReadStream(remotePath _[, options]_) | ||
Creates a readable stream on the remote path. Options is the same format as `getReadStream`. | ||
Returns a readable stream instance. | ||
#### deleteFile(remotePath _[, options]_) | ||
@@ -56,5 +58,2 @@ Delete a file or directory at `remotePath`. | ||
console.log(JSON.stringify(contents, undefined, 2)); | ||
}) | ||
.catch(function(err) { | ||
console.error(err); | ||
}); | ||
@@ -65,3 +64,3 @@ ``` | ||
#### getFileContents(remotePath, format _[, options]_) | ||
#### getFileContents(remotePath _[, options]_) | ||
Get the contents of the file at `remotePath` as a `Buffer` or `String`. `format` can either be "binary" or "text", where "binary" is default. | ||
@@ -76,5 +75,2 @@ | ||
fs.writeFileSync("./myImage.jpg", imageData); | ||
}) | ||
.catch(function(err) { | ||
console.error(err); | ||
}); | ||
@@ -90,8 +86,37 @@ ``` | ||
console.log(text); | ||
}) | ||
.catch(function(err) { | ||
console.error(err); | ||
}); | ||
``` | ||
#### getFileStream(remotePath _[, options]_) | ||
Get a readable stream on a remote file. Returns a Promise that resolves with a readable stream instance. | ||
_This is the underlying method to `createReadStream` (uses a `PassThrough` stream to delay the data). Due to the requirement of waiting on the request to complete before being able to get the **true** read stream, a Promise is returned that resolves when it becomes available. `createReadStream` simply creates and returns a `PassThrough` stream immediately and writes to it once this method resolves._ | ||
```js | ||
var fs = require("fs"); | ||
client | ||
.getFileStream("/test/image.png") | ||
.then(function(imageStream) { | ||
imageStream.pipe(fs.createWriteStream("./image.png")); | ||
}); | ||
``` | ||
`options` is an object that may look like the following: | ||
```json | ||
{ | ||
"headers": {} | ||
} | ||
``` | ||
##### options.range | ||
Optionally request part of the remote file by specifying the `start` and `end` byte positions. | ||
```javascript | ||
var stream = client.getFileStream("/test/image.png", { | ||
range: { start: 0, end: 499 } // first 500 bytes | ||
}); | ||
``` | ||
#### moveFile(remotePath, targetPath _[, options]_) | ||
@@ -102,14 +127,6 @@ Move a file or directory from `remotePath` to `targetPath`. | ||
// Move a directory | ||
client | ||
.moveFile("/some-dir", "/storage/moved-dir") | ||
.catch(function(err) { | ||
console.error(err); | ||
}); | ||
client.moveFile("/some-dir", "/storage/moved-dir"); | ||
// Rename a file | ||
client | ||
.moveFile("/images/pic.jpg", "/images/profile.jpg") | ||
.catch(function(err) { | ||
console.error(err); | ||
}); | ||
client.moveFile("/images/pic.jpg", "/images/profile.jpg"); | ||
``` | ||
@@ -125,15 +142,7 @@ | ||
client | ||
.putFileContents("/folder/myImage.jpg", imageData, { format: "binary" }) | ||
.catch(function(err) { | ||
console.error(err); | ||
}); | ||
client.putFileContents("/folder/myImage.jpg", imageData, { format: "binary" }); | ||
``` | ||
```js | ||
client | ||
.putFileContents("/example.txt", "some text", { format: "text" }) | ||
.catch(function(err) { | ||
console.error(err); | ||
}); | ||
client.putFileContents("/example.txt", "some text", { format: "text" }); | ||
``` | ||
@@ -140,0 +149,0 @@ |
@@ -9,3 +9,3 @@ var deepmerge = require("deepmerge"); | ||
deleteItem: function deleteItem(url, targetPath, options) { | ||
options = options || { headers: {} }; | ||
options = deepmerge({ headers: {} }, options || {}); | ||
return fetch(url + targetPath, { | ||
@@ -19,3 +19,3 @@ method: "DELETE", | ||
moveItem: function moveItem(url, filePath, targetFilePath, options) { | ||
options = options || { headers: {} }; | ||
options = deepmerge({ headers: {} }, options || {}); | ||
return fetch(url + filePath, { | ||
@@ -22,0 +22,0 @@ method: "MOVE", |
var xml2js = require("xml2js"), | ||
deepmerge = require("deepmerge"); | ||
var Stream = require("stream"), | ||
ReadableStream = Stream.Readable, | ||
PassThroughStream = Stream.PassThrough; | ||
var fetch = require("./request.js"), | ||
@@ -8,7 +12,20 @@ parsing = require("./parse.js"), | ||
module.exports = { | ||
var adapter = module.exports = { | ||
createReadStream: function createReadStream(url, filePath, options) { | ||
var outStream = new PassThroughStream(); | ||
adapter | ||
.getFileStream(url, filePath, options) | ||
.then(function __handleStream(stream) { | ||
stream.pipe(outStream); | ||
}) | ||
.catch(function __handleReadError(err) { | ||
outStream.emit("error", err); | ||
}); | ||
return outStream; | ||
}, | ||
getDirectoryContents: function getDirectoryContents(url, dirPath, options) { | ||
dirPath = dirPath || "/"; | ||
options = options || { headers: {} }; | ||
options = deepmerge({ headers: {} }, options || {}); | ||
var fetchURL = url + dirPath; | ||
@@ -48,3 +65,3 @@ return fetch( | ||
getFileContents: function getFileContents(url, filePath, options) { | ||
options = options || { headers: {} }; | ||
options = deepmerge({ headers: {} }, options || {}); | ||
return fetch(url + filePath, { | ||
@@ -60,4 +77,20 @@ method: "GET", | ||
getFileStream: function getFileStream(url, filePath, options) { | ||
options = deepmerge({ headers: {} }, options || {}); | ||
if (typeof options.range === "object") { | ||
options.headers.Range = "bytes=" + options.range.start + "-" + | ||
options.range.end; | ||
} | ||
return fetch(url + filePath, { | ||
method: "GET", | ||
headers: options.headers | ||
}) | ||
.then(responseHandlers.handleResponseCode) | ||
.then(function(res) { | ||
return res.body; | ||
}); | ||
}, | ||
getStat: function getStat(url, itemPath, options) { | ||
options = options || { headers: {} }; | ||
options = deepmerge({ headers: {} }, options || {}); | ||
return fetch(url + itemPath, { | ||
@@ -97,3 +130,3 @@ method: "PROPFIND", | ||
getTextContents: function getTextContents(url, filePath, options) { | ||
options = options || { headers: {} }; | ||
options = deepmerge({ headers: {} }, options || {}); | ||
return fetch(url + filePath, { | ||
@@ -100,0 +133,0 @@ headers: options.headers |
@@ -18,3 +18,3 @@ var deepmerge = require("deepmerge"); | ||
createDirectory: function createDirectory(url, directoryPath, options) { | ||
options = options || { headers: {} }; | ||
options = deepmerge({ headers: {} }, options || {}); | ||
return fetch(url + directoryPath, { | ||
@@ -21,0 +21,0 @@ method: "MKCOL", |
@@ -59,2 +59,17 @@ var deepmerge = require("deepmerge"); | ||
/** | ||
* Create a readable stream of a remote file | ||
* @param {String} remoteFilename The file to stream | ||
* @param {OptionsHeadersAndFormat=} options Options for the request | ||
* @memberof ClientInterface | ||
* @returns {Readable} A readable stream | ||
*/ | ||
createReadStream: function createReadStream(remoteFilename, options) { | ||
var getOptions = deepmerge( | ||
baseOptions, | ||
options || {} | ||
); | ||
return getAdapter.createReadStream(__url, remoteFilename, getOptions); | ||
}, | ||
/** | ||
* Delete a remote file | ||
@@ -111,2 +126,17 @@ * @param {String} remotePath The remote path to delete | ||
/** | ||
* Get a readable stream of a remote file | ||
* @param {String} remoteFilename The file to stream | ||
* @param {OptionsHeadersAndFormat=} options Options for the request | ||
* @memberof ClientInterface | ||
* @returns {Promise.<Readable>} A promise that resolves with a readable stream | ||
*/ | ||
getFileStream: function getFileStream(remoteFilename, options) { | ||
var getOptions = deepmerge( | ||
baseOptions, | ||
options || {} | ||
); | ||
return getAdapter.getFileStream(__url, remoteFilename, getOptions); | ||
}, | ||
/** | ||
* Move a remote item to another path | ||
@@ -113,0 +143,0 @@ * @param {String} remotePath The remote item path |
var path = require("path"); | ||
var ReadableStream = require("stream").Readable; | ||
@@ -64,2 +65,18 @@ var directoryExists = require("directory-exists").sync, | ||
describe("createReadStream", function() { | ||
it("streams contents of a remote file", function(done) { | ||
var stream = getAdapter.createReadStream(SERVER_URL, "/gem.png"); | ||
expect(stream instanceof ReadableStream).to.be.true; | ||
var buffers = []; | ||
stream.on("data", function(d) { buffers.push(d); }); | ||
stream.on("end", function() { | ||
var final = Buffer.concat(buffers); | ||
expect(final.length).to.equal(279); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
describe("getDirectoryContents", function() { | ||
@@ -111,2 +128,58 @@ | ||
describe("getFileStream", function() { | ||
it("streams contents of a remote file", function() { | ||
return getAdapter | ||
.getFileStream(SERVER_URL, "/gem.png") | ||
.then(function(stream) { | ||
expect(stream instanceof ReadableStream).to.be.true; | ||
var buffers = []; | ||
return new Promise(function(resolve) { | ||
stream.on("data", function(d) { buffers.push(d); }); | ||
stream.on('end', function() { | ||
resolve(Buffer.concat(buffers)); | ||
}); | ||
}); | ||
}) | ||
.then(function(buff) { | ||
expect(buff.length).to.equal(279); | ||
}); | ||
}); | ||
it("streams portions (ranges) of a remote file", function() { | ||
return Promise | ||
.all([ | ||
getAdapter.getFileStream(SERVER_URL, "/gem.png", { range: { start: 0, end: 199 } }), | ||
getAdapter.getFileStream(SERVER_URL, "/gem.png", { range: { start: 200, end: 278 } }) | ||
]) | ||
.then(function(streams) { | ||
var part1 = streams.shift(), | ||
part2 = streams.shift(); | ||
var part1Buffers = [], | ||
part2Buffers = []; | ||
return Promise.all([ | ||
new Promise(function(resolve) { | ||
part1.on("data", function(d) { part1Buffers.push(d); }); | ||
part1.on('end', function() { | ||
resolve(Buffer.concat(part1Buffers)); | ||
}); | ||
}), | ||
new Promise(function(resolve) { | ||
part2.on("data", function(d) { part2Buffers.push(d); }); | ||
part2.on('end', function() { | ||
resolve(Buffer.concat(part2Buffers)); | ||
}); | ||
}) | ||
]); | ||
}) | ||
.then(function(buffers) { | ||
var part1 = buffers.shift(), | ||
part2 = buffers.shift(); | ||
expect(part1.length).to.equal(200); | ||
expect(part2.length).to.equal(79); | ||
}); | ||
}); | ||
}); | ||
describe("getStat", function() { | ||
@@ -113,0 +186,0 @@ |
57231
1002
197
11