Skip to content
Snippets Groups Projects
Commit b70b9c44 authored by Alexander Rose's avatar Alexander Rose
Browse files

fix ajaxGet: handle case where download had finished before callback were registered

parent 88a4cf1a
No related branches found
No related tags found
No related merge requests found
/** /**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* *
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
...@@ -67,8 +67,8 @@ function decompress(buffer: Uint8Array): Uint8Array { ...@@ -67,8 +67,8 @@ function decompress(buffer: Uint8Array): Uint8Array {
// return gzip.decompress(); // return gzip.decompress();
} }
async function processFile(ctx: RuntimeContext, asUint8Array: boolean, compressed: boolean, e: any) { async function processFile(ctx: RuntimeContext, asUint8Array: boolean, compressed: boolean, fileReader: FileReader) {
const data = (e.target as FileReader).result; const data = fileReader.result;
if (compressed) { if (compressed) {
await ctx.update('Decompressing...'); await ctx.update('Decompressing...');
...@@ -84,11 +84,31 @@ async function processFile(ctx: RuntimeContext, asUint8Array: boolean, compresse ...@@ -84,11 +84,31 @@ async function processFile(ctx: RuntimeContext, asUint8Array: boolean, compresse
} }
} }
function readData(ctx: RuntimeContext, action: string, data: XMLHttpRequest | FileReader, asUint8Array: boolean): Promise<any> { function isDone(data: XMLHttpRequest | FileReader) {
return new Promise<any>((resolve, reject) => { if (data instanceof FileReader) {
data.onerror = (e: any) => { return data.readyState === FileReader.DONE
} else if (data instanceof XMLHttpRequest) {
return data.readyState === XMLHttpRequest.DONE
}
throw new Error('unknown data type')
}
function readData<T extends XMLHttpRequest | FileReader>(ctx: RuntimeContext, action: string, data: T, asUint8Array: boolean): Promise<T> {
return new Promise<T>((resolve, reject) => {
// first check if data reading is already done
if (isDone(data)) {
const error = (<FileReader>data).error;
if (error) {
reject((<FileReader>data).error || 'Failed.');
} else {
resolve(data);
}
return
}
data.onerror = (e: ProgressEvent) => {
const error = (<FileReader>e.target).error; const error = (<FileReader>e.target).error;
reject(error ? error : 'Failed.'); reject(error || 'Failed.');
}; };
let hasError = false; let hasError = false;
...@@ -106,7 +126,10 @@ function readData(ctx: RuntimeContext, action: string, data: XMLHttpRequest | Fi ...@@ -106,7 +126,10 @@ function readData(ctx: RuntimeContext, action: string, data: XMLHttpRequest | Fi
reject(e); reject(e);
} }
} }
data.onload = (e: any) => resolve(e);
data.onload = (e: ProgressEvent) => {
resolve(data);
}
}); });
} }
...@@ -121,8 +144,8 @@ function readFromFileInternal(file: File, asUint8Array: boolean): Task<string | ...@@ -121,8 +144,8 @@ function readFromFileInternal(file: File, asUint8Array: boolean): Task<string |
else reader.readAsBinaryString(file); else reader.readAsBinaryString(file);
ctx.update({ message: 'Opening file...', canAbort: true }); ctx.update({ message: 'Opening file...', canAbort: true });
const e = await readData(ctx, 'Reading...', reader, asUint8Array); const fileReader = await readData(ctx, 'Reading...', reader, asUint8Array);
const result = processFile(ctx, asUint8Array, isCompressed, e); const result = processFile(ctx, asUint8Array, isCompressed, fileReader);
return result; return result;
} finally { } finally {
reader = void 0; reader = void 0;
...@@ -156,27 +179,25 @@ class RequestPool { ...@@ -156,27 +179,25 @@ class RequestPool {
} }
} }
async function processAjax(ctx: RuntimeContext, asUint8Array: boolean, decompressGzip: boolean, e: any) { async function processAjax(ctx: RuntimeContext, asUint8Array: boolean, decompressGzip: boolean, req: XMLHttpRequest) {
const req = (e.target as XMLHttpRequest);
if (req.status >= 200 && req.status < 400) { if (req.status >= 200 && req.status < 400) {
if (asUint8Array) { if (asUint8Array === true) {
const buff = new Uint8Array(e.target.response); const buff = new Uint8Array(req.response);
RequestPool.deposit(e.target); RequestPool.deposit(req);
if (decompressGzip) { if (decompressGzip) {
return decompress(buff); return decompress(buff);
} else { } else {
return buff; return buff;
} }
} } else {
else { const text = req.responseText;
const text = e.target.responseText; RequestPool.deposit(req);
RequestPool.deposit(e.target);
return text; return text;
} }
} else { } else {
const status = req.statusText; const status = req.statusText;
RequestPool.deposit(e.target); RequestPool.deposit(req);
throw status; throw status;
} }
} }
...@@ -196,23 +217,23 @@ function ajaxGetInternal(title: string | undefined, url: string, type: 'json' | ...@@ -196,23 +217,23 @@ function ajaxGetInternal(title: string | undefined, url: string, type: 'json' |
xhttp.send(body); xhttp.send(body);
await ctx.update({ message: 'Waiting for server...', canAbort: true }); await ctx.update({ message: 'Waiting for server...', canAbort: true });
const e = await readData(ctx, 'Downloading...', xhttp, asUint8Array); const req = await readData(ctx, 'Downloading...', xhttp, asUint8Array);
xhttp = void 0; xhttp = void 0; // guard against reuse, help garbage collector
const result = await processAjax(ctx, asUint8Array, decompressGzip, e) const result = await processAjax(ctx, asUint8Array, decompressGzip, req)
if (type === 'json') { if (type === 'json') {
await ctx.update({ message: 'Parsing JSON...', canAbort: false }); await ctx.update({ message: 'Parsing JSON...', canAbort: false });
return JSON.parse(result); return JSON.parse(result as string);
} else if (type === 'xml') { } else if (type === 'xml') {
await ctx.update({ message: 'Parsing XML...', canAbort: false }); await ctx.update({ message: 'Parsing XML...', canAbort: false });
return parseXml(result); return parseXml(result as string);
} }
return result; return result;
}, () => { }, () => {
if (xhttp) { if (xhttp) {
xhttp.abort(); xhttp.abort();
xhttp = void 0; xhttp = void 0; // guard against reuse, help garbage collector
} }
}); });
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment