From 639522f80d1cc9c9701160ec4bd448b1ac09705c Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 8 Jul 2015 14:33:46 +0100 Subject: [PATCH] Add uploadContent method --- lib/client.js | 10 +++++++++ lib/http-api.js | 59 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/lib/client.js b/lib/client.js index 02b93d3c2..856ecb3ad 100644 --- a/lib/client.js +++ b/lib/client.js @@ -462,6 +462,16 @@ MatrixClient.prototype.sendHtmlMessage = function(roomId, body, htmlBody, callba return this.sendMessage(roomId, content, callback); }; +/** + * @param {File} file object + * @param {module:client.callback} callback Optional. + * @return {module:client.Promise} Resolves: TODO + * @return {module:http-api.MatrixError} Rejects: with an error response. + */ +MatrixClient.prototype.uploadContent = function(file, callback) { + return this._http.uploadContent(file, callback); +}; + /** * @param {string} roomId * @param {boolean} isTyping diff --git a/lib/http-api.js b/lib/http-api.js index 62109ac38..14074e0c1 100644 --- a/lib/http-api.js +++ b/lib/http-api.js @@ -10,7 +10,6 @@ var utils = require("./utils"); TODO: - CS: complete register function (doing stages) - Identity server: linkEmail, authEmail, bindEmail, lookup3pid -- uploadContent (?) */ /** @@ -139,6 +138,64 @@ module.exports.MatrixHttpApi.prototype = { }; }, + uploadContent: function(file, callback) { + if (callback !== undefined && !utils.isFunction(callback)) { + throw Error( + "Expected callback to be a function but got " + typeof callback + ); + } + var queryParams = { + filename: file.name, + access_token: this.opts.accessToken + }; + var defer = q.defer(); + // 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 + // browser-request base64 encode and then decode it again, we just + // 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); + + 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); + + return defer.promise; + }, + /** * Perform an authorised request to the homeserver. * @param {Function} callback Optional. The callback to invoke on