report attachment upload progress

This commit is contained in:
Bruno Windels 2020-11-16 10:45:46 +01:00
parent 1dd46b875b
commit 83cbe78cd6
4 changed files with 31 additions and 10 deletions

View File

@ -110,6 +110,7 @@ export class HomeServerApi {
headers, headers,
body: encodedBody, body: encodedBody,
timeout: options?.timeout, timeout: options?.timeout,
uploadProgress: options?.uploadProgress,
format: "json" // response format format: "json" // response format
}); });

View File

@ -35,12 +35,17 @@ export class AttachmentUpload {
this._aborted = false; this._aborted = false;
this._error = null; this._error = null;
this._status = new ObservableValue(UploadStatus.Waiting); this._status = new ObservableValue(UploadStatus.Waiting);
this._progress = new ObservableValue(0);
} }
get status() { get status() {
return this._status; return this._status;
} }
get uploadProgress() {
return this._progress;
}
async upload() { async upload() {
if (this._status.get() === UploadStatus.Waiting) { if (this._status.get() === UploadStatus.Waiting) {
this._upload(); this._upload();
@ -66,9 +71,13 @@ export class AttachmentUpload {
if (this._aborted) { if (this._aborted) {
throw new AbortError("upload aborted during encryption"); throw new AbortError("upload aborted during encryption");
} }
this._progress.set(0);
this._status.set(UploadStatus.Uploading); this._status.set(UploadStatus.Uploading);
this._uploadRequest = this._hsApi.uploadAttachment(transferredBlob, this._filename); this._uploadRequest = this._hsApi.uploadAttachment(transferredBlob, this._filename, {
uploadProgress: sentBytes => this._progress.set(sentBytes / transferredBlob.size)
});
const {content_uri} = await this._uploadRequest.response(); const {content_uri} = await this._uploadRequest.response();
this._progress.set(1);
this._mxcUrl = content_uri; this._mxcUrl = content_uri;
this._transferredBlob = transferredBlob; this._transferredBlob = transferredBlob;
this._status.set(UploadStatus.Uploaded); this._status.set(UploadStatus.Uploaded);

View File

@ -21,6 +21,7 @@ import {
} from "../../../../matrix/error.js"; } from "../../../../matrix/error.js";
import {abortOnTimeout} from "./timeout.js"; import {abortOnTimeout} from "./timeout.js";
import {addCacheBuster} from "./common.js"; import {addCacheBuster} from "./common.js";
import {xhrRequest} from "./xhr.js";
class RequestResult { class RequestResult {
constructor(promise, controller) { constructor(promise, controller) {
@ -51,7 +52,12 @@ class RequestResult {
} }
export function createFetchRequest(createTimeout) { export function createFetchRequest(createTimeout) {
return function fetchRequest(url, {method, headers, body, timeout, format, cache = false}) { return function fetchRequest(url, requestOptions) {
// fetch doesn't do upload progress yet, delegate to xhr
if (requestOptions?.uploadProgress) {
return xhrRequest(url, requestOptions);
}
let {method, headers, body, timeout, format, cache = false} = requestOptions;
const controller = typeof AbortController === "function" ? new AbortController() : null; const controller = typeof AbortController === "function" ? new AbortController() : null;
// if a BlobHandle, take native blob // if a BlobHandle, take native blob
if (body?.nativeBlob) { if (body?.nativeBlob) {

View File

@ -35,7 +35,7 @@ class RequestResult {
} }
} }
function send(url, {method, headers, timeout, body, format}) { function createXhr(url, {method, headers, timeout, format, uploadProgress}) {
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
xhr.open(method, url); xhr.open(method, url);
@ -52,11 +52,9 @@ function send(url, {method, headers, timeout, body, format}) {
xhr.timeout = timeout; xhr.timeout = timeout;
} }
// if a BlobHandle, take native blob if (uploadProgress) {
if (body?.nativeBlob) { xhr.upload.addEventListener("progress", evt => uploadProgress(evt.loaded));
body = body.nativeBlob;
} }
xhr.send(body || null);
return xhr; return xhr;
} }
@ -71,12 +69,12 @@ function xhrAsPromise(xhr, method, url) {
} }
export function xhrRequest(url, options) { export function xhrRequest(url, options) {
const {cache, format} = options; let {cache, format, body, method} = options;
if (!cache) { if (!cache) {
url = addCacheBuster(url); url = addCacheBuster(url);
} }
const xhr = send(url, options); const xhr = createXhr(url, options);
const promise = xhrAsPromise(xhr, options.method, url).then(xhr => { const promise = xhrAsPromise(xhr, method, url).then(xhr => {
const {status} = xhr; const {status} = xhr;
let body = null; let body = null;
if (format === "buffer") { if (format === "buffer") {
@ -86,5 +84,12 @@ export function xhrRequest(url, options) {
} }
return {status, body}; return {status, body};
}); });
// if a BlobHandle, take native blob
if (body?.nativeBlob) {
body = body.nativeBlob;
}
xhr.send(body || null);
return new RequestResult(promise, xhr); return new RequestResult(promise, xhr);
} }