diff --git a/examples/node/app.js b/examples/node/app.js index e2e5835aa..65bed3ba2 100644 --- a/examples/node/app.js +++ b/examples/node/app.js @@ -86,6 +86,21 @@ rl.on('line', function(line) { print("/invite Error: %s", err); }); } + else if (line.indexOf("/file ") === 0) { + var filename = line.split(" ")[1].trim(); + var stream = fs.createReadStream(filename); + matrixClient.uploadContent({ + stream: stream, + name: filename + }).done(function(url) { + var content = { + msgtype: "m.file", + body: filename, + url: JSON.parse(url).content_uri + }; + matrixClient.sendMessage(viewingRoom.roomId, content); + }); + } else { matrixClient.sendTextMessage(viewingRoom.roomId, line).finally(function() { printMessages(); @@ -388,4 +403,4 @@ function fixWidth(str, len) { return str; } -matrixClient.startClient(numMessagesToShow); // messages for each room. \ No newline at end of file +matrixClient.startClient(numMessagesToShow); // messages for each room. diff --git a/lib/http-api.js b/lib/http-api.js index a3390bea1..4f5e32fd2 100644 --- a/lib/http-api.js +++ b/lib/http-api.js @@ -138,6 +138,16 @@ module.exports.MatrixHttpApi.prototype = { }; }, + /** + * Upload content to the Home Server + * @param {File object} file A File object (in a browser) or in Node, + an object with properties: + name: The file's name + stream: A read stream + * @param {Function} callback Optional. The callback to invoke on + * success/failure. See the promise return values for more information. + * @return {module:client.Promise} Resolves to {data: {Object}, + */ uploadContent: function(file, callback) { if (callback !== undefined && !utils.isFunction(callback)) { throw Error( @@ -145,6 +155,7 @@ module.exports.MatrixHttpApi.prototype = { ); } var defer = q.defer(); + var url = this.opts.baseUrl+"/_matrix/media/v1/upload"; // browser-request doesn't support File objects because it deep-copies // the options using JSON.parse(JSON.stringify(options)). Instead of // loading the whole file into memory as a string and letting @@ -152,42 +163,55 @@ module.exports.MatrixHttpApi.prototype = { // use XMLHttpRequest directly. // (browser-request doesn't support progress either, which is also kind // of important here) - var xhr = new XMLHttpRequest(); - var cb = requestCallback(defer, callback, this.opts.onlyData); + if (global.XMLHttpRequest) { + var xhr = new global.XMLHttpRequest(); + var cb = requestCallback(defer, callback, this.opts.onlyData); - var timeout_fn = function() { - xhr.abort(); - cb(new Error('Timeout')); - }; + var timeout_fn = function() { + xhr.abort(); + cb(new Error('Timeout')); + }; - xhr.timeout_timer = setTimeout(timeout_fn, 30000); - - xhr.onreadystatechange = function() { - switch (xhr.readyState) { - case XMLHttpRequest.DONE: - clearTimeout(xhr.timeout_timer); - - var resp = JSON.parse(xhr.responseText); - if (resp.content_uri === undefined) { - cb(new Error('Bad response')); - return; - } - - cb(undefined, xhr, resp.content_uri); - break; - } - }; - xhr.upload.addEventListener("progress", function(ev) { - clearTimeout(xhr.timeout_timer); xhr.timeout_timer = setTimeout(timeout_fn, 30000); - defer.notify(ev); - }); - var url = this.opts.baseUrl+"/_matrix/media/v1/upload"; - url += "?access_token="+encodeURIComponent(this.opts.accessToken); - url += "&filename="+encodeURIComponent(file.name); - xhr.open("POST", url); - xhr.send(file); + xhr.onreadystatechange = function() { + switch (xhr.readyState) { + case global.XMLHttpRequest.DONE: + clearTimeout(xhr.timeout_timer); + + var resp = JSON.parse(xhr.responseText); + if (resp.content_uri === undefined) { + cb(new Error('Bad response')); + return; + } + + cb(undefined, xhr, resp.content_uri); + break; + } + }; + xhr.upload.addEventListener("progress", function(ev) { + clearTimeout(xhr.timeout_timer); + xhr.timeout_timer = setTimeout(timeout_fn, 30000); + defer.notify(ev); + }); + url += "?access_token="+encodeURIComponent(this.opts.accessToken); + url += "&filename="+encodeURIComponent(file.name); + + xhr.open("POST", url); + xhr.send(file); + } else { + var queryParams = { + filename: file.name, + access_token: this.opts.accessToken + }; + file.stream.pipe( + this.opts.request({ + uri: url, + qs: queryParams, + method: "POST" + }, requestCallback(defer, callback, this.opts.onlyData)) + ); + } return defer.promise; },