1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2019 The Android Open Source Project 2*6dbdd20aSAndroid Build Coastguard Worker// 3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*6dbdd20aSAndroid Build Coastguard Worker// 7*6dbdd20aSAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*6dbdd20aSAndroid Build Coastguard Worker// 9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License. 14*6dbdd20aSAndroid Build Coastguard Worker 15*6dbdd20aSAndroid Build Coastguard Workerimport {assertTrue} from './logging'; 16*6dbdd20aSAndroid Build Coastguard Worker 17*6dbdd20aSAndroid Build Coastguard Workerexport function fetchWithTimeout( 18*6dbdd20aSAndroid Build Coastguard Worker input: RequestInfo, 19*6dbdd20aSAndroid Build Coastguard Worker init: RequestInit, 20*6dbdd20aSAndroid Build Coastguard Worker timeoutMs: number, 21*6dbdd20aSAndroid Build Coastguard Worker) { 22*6dbdd20aSAndroid Build Coastguard Worker return new Promise<Response>((resolve, reject) => { 23*6dbdd20aSAndroid Build Coastguard Worker const timer = setTimeout( 24*6dbdd20aSAndroid Build Coastguard Worker () => 25*6dbdd20aSAndroid Build Coastguard Worker reject(new Error(`fetch(${input}) timed out after ${timeoutMs} ms`)), 26*6dbdd20aSAndroid Build Coastguard Worker timeoutMs, 27*6dbdd20aSAndroid Build Coastguard Worker ); 28*6dbdd20aSAndroid Build Coastguard Worker fetch(input, init) 29*6dbdd20aSAndroid Build Coastguard Worker .then((response) => resolve(response)) 30*6dbdd20aSAndroid Build Coastguard Worker .catch((err) => reject(err)) 31*6dbdd20aSAndroid Build Coastguard Worker .finally(() => clearTimeout(timer)); 32*6dbdd20aSAndroid Build Coastguard Worker }); 33*6dbdd20aSAndroid Build Coastguard Worker} 34*6dbdd20aSAndroid Build Coastguard Worker 35*6dbdd20aSAndroid Build Coastguard Workerexport function fetchWithProgress( 36*6dbdd20aSAndroid Build Coastguard Worker url: string, 37*6dbdd20aSAndroid Build Coastguard Worker onProgress?: (percentage: number) => void, 38*6dbdd20aSAndroid Build Coastguard Worker): Promise<Blob> { 39*6dbdd20aSAndroid Build Coastguard Worker return new Promise((resolve, reject) => { 40*6dbdd20aSAndroid Build Coastguard Worker const xhr = new XMLHttpRequest(); 41*6dbdd20aSAndroid Build Coastguard Worker 42*6dbdd20aSAndroid Build Coastguard Worker xhr.open('GET', url, /* async= */ true); 43*6dbdd20aSAndroid Build Coastguard Worker xhr.responseType = 'blob'; 44*6dbdd20aSAndroid Build Coastguard Worker 45*6dbdd20aSAndroid Build Coastguard Worker xhr.onprogress = (event) => { 46*6dbdd20aSAndroid Build Coastguard Worker if (event.lengthComputable) { 47*6dbdd20aSAndroid Build Coastguard Worker const percentComplete = Math.round((event.loaded / event.total) * 100); 48*6dbdd20aSAndroid Build Coastguard Worker onProgress?.(percentComplete); 49*6dbdd20aSAndroid Build Coastguard Worker } 50*6dbdd20aSAndroid Build Coastguard Worker }; 51*6dbdd20aSAndroid Build Coastguard Worker 52*6dbdd20aSAndroid Build Coastguard Worker xhr.onload = () => { 53*6dbdd20aSAndroid Build Coastguard Worker if (xhr.status >= 200 && xhr.status < 300) { 54*6dbdd20aSAndroid Build Coastguard Worker resolve(xhr.response); // Resolve with the Blob response 55*6dbdd20aSAndroid Build Coastguard Worker } else { 56*6dbdd20aSAndroid Build Coastguard Worker reject( 57*6dbdd20aSAndroid Build Coastguard Worker new Error(`Failed to download: ${xhr.status} ${xhr.statusText}`), 58*6dbdd20aSAndroid Build Coastguard Worker ); 59*6dbdd20aSAndroid Build Coastguard Worker } 60*6dbdd20aSAndroid Build Coastguard Worker }; 61*6dbdd20aSAndroid Build Coastguard Worker 62*6dbdd20aSAndroid Build Coastguard Worker xhr.onerror = () => { 63*6dbdd20aSAndroid Build Coastguard Worker reject(new Error(`Network error in fetchWithProgress(${url})`)); 64*6dbdd20aSAndroid Build Coastguard Worker }; 65*6dbdd20aSAndroid Build Coastguard Worker 66*6dbdd20aSAndroid Build Coastguard Worker xhr.send(); 67*6dbdd20aSAndroid Build Coastguard Worker }); 68*6dbdd20aSAndroid Build Coastguard Worker} 69*6dbdd20aSAndroid Build Coastguard Worker 70*6dbdd20aSAndroid Build Coastguard Worker/** 71*6dbdd20aSAndroid Build Coastguard Worker * NOTE: this function can only be called from synchronous contexts. It will 72*6dbdd20aSAndroid Build Coastguard Worker * fail if called in timer handlers or async continuations (e.g. after an await) 73*6dbdd20aSAndroid Build Coastguard Worker * Use assetSrc(relPath) which caches it on startup. 74*6dbdd20aSAndroid Build Coastguard Worker * @returns the directory where the app is served from, e.g. 'v46.0-a2082649b' 75*6dbdd20aSAndroid Build Coastguard Worker */ 76*6dbdd20aSAndroid Build Coastguard Workerexport function getServingRoot() { 77*6dbdd20aSAndroid Build Coastguard Worker // Works out the root directory where the content should be served from 78*6dbdd20aSAndroid Build Coastguard Worker // e.g. `http://origin/v1.2.3/`. 79*6dbdd20aSAndroid Build Coastguard Worker const script = document.currentScript as HTMLScriptElement; 80*6dbdd20aSAndroid Build Coastguard Worker 81*6dbdd20aSAndroid Build Coastguard Worker if (script === null) { 82*6dbdd20aSAndroid Build Coastguard Worker // Can be null in tests. 83*6dbdd20aSAndroid Build Coastguard Worker assertTrue(typeof jest !== 'undefined'); 84*6dbdd20aSAndroid Build Coastguard Worker return ''; 85*6dbdd20aSAndroid Build Coastguard Worker } 86*6dbdd20aSAndroid Build Coastguard Worker 87*6dbdd20aSAndroid Build Coastguard Worker let root = script.src; 88*6dbdd20aSAndroid Build Coastguard Worker root = root.substring(0, root.lastIndexOf('/') + 1); 89*6dbdd20aSAndroid Build Coastguard Worker return root; 90*6dbdd20aSAndroid Build Coastguard Worker} 91