UNPKG

@finos/legend-application

Version:
132 lines 5.32 kB
/** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { downloadFileUsingDataURI, guaranteeNonNullable, } from '@finos/legend-shared'; var DOWNLOAD_EVENTS; (function (DOWNLOAD_EVENTS) { DOWNLOAD_EVENTS["TAG_REQUEST"] = "download-request"; DOWNLOAD_EVENTS["TAG_RESPONSE"] = "download-response"; DOWNLOAD_EVENTS["STREAM_CLOSED"] = "#stream-closed"; DOWNLOAD_EVENTS["STREAM_ABORTED"] = "#stream-aborted"; })(DOWNLOAD_EVENTS || (DOWNLOAD_EVENTS = {})); function createWritableStreamFromMessageChannel(channel) { return new WritableStream({ write(chunk) { channel.port1.postMessage(chunk); }, close() { channel.port1.postMessage(DOWNLOAD_EVENTS.STREAM_CLOSED); }, abort() { channel.port1.postMessage(DOWNLOAD_EVENTS.STREAM_ABORTED); closeMessagePort(channel.port1); closeMessagePort(channel.port2); }, }); } function closeMessagePort(port) { port.onmessage = null; port.close(); } async function getServiceWorker() { if (!('serviceWorker' in navigator)) { return Promise.reject(new Error('Service worker is not available. Service Worker requires HTTPS protocol')); } return navigator.serviceWorker .getRegistration() .then((workerRegistration) => { if (workerRegistration === undefined) { return undefined; } const pending = workerRegistration.installing ?? workerRegistration.waiting; return (workerRegistration.active ?? new Promise((resolve) => { // if not activated, add listener to waiting or installing registration const listener = () => { if (pending?.state === 'activated') { pending.removeEventListener('statechange', listener); resolve(workerRegistration.active ?? undefined); } }; pending?.addEventListener('statechange', listener); })); }); } function createDownloadRequest(filename) { const PREFIX = 6; const prefix = String(Math.random()).slice(-PREFIX); const url = new URL(`${prefix}/${filename}`, window.location.href).toString(); return { tag: DOWNLOAD_EVENTS.TAG_REQUEST, filename, url }; } function handleServiceWorkerDownloadResponse(event) { const data = event.data; if (data?.tag === DOWNLOAD_EVENTS.TAG_RESPONSE && data.downloadUrl.length) { openInIframe(data.downloadUrl); } } function openInIframe(src) { const iframe = document.createElement('iframe'); iframe.hidden = true; iframe.src = src; document.body.appendChild(iframe); return iframe; } export async function downloadStream(response, filename, contentType) { const responseBody = guaranteeNonNullable(response.body); // creates communication channel with service worker with response handler const channel = new MessageChannel(); channel.port1.onmessage = handleServiceWorkerDownloadResponse; // grabs service worker and handles it download along with response channel port const serviceWorker = await getServiceWorker(); if (!serviceWorker) { // TODO: remove once service worker workflow is tested const text = await response.text(); // eslint-disable-next-line no-console console.debug('service worker not found. Using in memory file download'); downloadFileUsingDataURI(filename, text, contentType); return; } // eslint-disable-next-line no-console console.debug('Service worker found. Continuing download'); const downloadRequest = createDownloadRequest(filename); serviceWorker.postMessage(downloadRequest, [channel.port2]); // creates new data stream over communication channel and pipes given stream in it responseBody .pipeTo(createWritableStreamFromMessageChannel(channel)) .then(() => { // TODO: trace success }) .catch(() => { // TODO: fail }); } export function registerDownloadHelperServiceWorker(workerPath) { if ('serviceWorker' in navigator) { const path = workerPath ?? '/ServiceWorker.js'; navigator.serviceWorker .register(path) .then((reg) => { // TODO: add trace // eslint-disable-next-line no-console console.debug(`register service worker success with path: ${path}`, reg); }) .catch((error) => { // TODO: add trace // eslint-disable-next-line no-console console.debug(`register service worker error with path: ${path}`, error); }); } } //# sourceMappingURL=DownloadHelperServiceWorker.js.map