From 92ea2752750ac5cc583fbee2bf6df075836ee96e Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 2 Dec 2015 18:14:13 +0000 Subject: [PATCH] Add ability to cancel file uploads --- lib/client.js | 21 +++++++++++++++++++ lib/http-api.js | 54 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/lib/client.js b/lib/client.js index fade4dfe8..47ae2c895 100644 --- a/lib/client.js +++ b/lib/client.js @@ -1284,6 +1284,27 @@ MatrixClient.prototype.uploadContent = function(file, callback) { return this._http.uploadContent(file, callback); }; +/** + * Cancel a file upload in progress + * @param {module:client.Promise} promise The promise returned from uploadContent + * @return {boolean} true if canceled, otherwise false + */ +MatrixClient.prototype.cancelUpload = function(promise) { + return this._http.cancelUpload(promise); +}; + +/** + * Get a list of all file uploads in progress + * @return {array} Array of objects representing current uploads. + * Currently in progress is element 0. Keys: + * - promise: The promise associated with the upload + * - loaded: Number of bytes uploaded + * - total: Total number of bytes to upload + */ +MatrixClient.prototype.getCurrentUploads = function() { + return this._http.getCurrentUploads(); +}; + /** * @param {string} roomId * @param {boolean} isTyping diff --git a/lib/http-api.js b/lib/http-api.js index 797daa426..1a4727712 100644 --- a/lib/http-api.js +++ b/lib/http-api.js @@ -50,6 +50,7 @@ module.exports.MatrixHttpApi = function MatrixHttpApi(opts) { utils.checkObjectHasKeys(opts, ["baseUrl", "request", "prefix"]); opts.onlyData = opts.onlyData || false; this.opts = opts; + this.uploads = []; }; module.exports.MatrixHttpApi.prototype = { @@ -95,8 +96,12 @@ module.exports.MatrixHttpApi.prototype = { // use XMLHttpRequest directly. // (browser-request doesn't support progress either, which is also kind // of important here) + + var upload = { loaded: 0, total: 0 }; + if (global.XMLHttpRequest) { var xhr = new global.XMLHttpRequest(); + upload.xhr = xhr; var cb = requestCallback(defer, callback, this.opts.onlyData); var timeout_fn = function() { @@ -128,6 +133,8 @@ module.exports.MatrixHttpApi.prototype = { }; xhr.upload.addEventListener("progress", function(ev) { clearTimeout(xhr.timeout_timer); + upload.loaded = ev.loaded; + upload.total = ev.total; xhr.timeout_timer = setTimeout(timeout_fn, 30000); defer.notify(ev); }); @@ -148,16 +155,47 @@ module.exports.MatrixHttpApi.prototype = { 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)) - ); + upload.request = this.opts.request({ + uri: url, + qs: queryParams, + method: "POST" + }, requestCallback(defer, callback, this.opts.onlyData)); + file.stream.pipe(this.opts.request); } - return defer.promise; + this.uploads.push(upload); + + var self = this; + upload.promise = defer.promise.finally(function() { + var uploadsKeys = Object.keys(self.uploads); + for (var i = 0; i < uploadsKeys.length; ++i) { + if (self.uploads[uploadsKeys[i]].promise === defer.promise) { + self.uploads.splice(uploadsKeys[i], 1); + } + } + }); + return upload.promise; + }, + + cancelUpload: function(promise) { + var uploadsKeys = Object.keys(this.uploads); + for (var i = 0; i < uploadsKeys.length; ++i) { + var upload = this.uploads[uploadsKeys[i]]; + if (upload.promise === promise) { + if (upload.xhr !== undefined) { + upload.xhr.abort(); + return true; + } else if (upload.request !== undefined) { + upload.request.abort(); + return true; + } + } + } + return false; + }, + + getCurrentUploads: function() { + return this.uploads; }, idServerRequest: function(callback, method, path, params, prefix) {