UNPKG

voluptasmollitia

Version:
124 lines (116 loc) 4.54 kB
/** * @license * Copyright 2020 Google LLC. * * 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 { AuthErrorCode } from '../../core/errors'; import { _createError } from '../../core/util/assert'; import { Delay } from '../../core/util/delay'; import { AuthInternal } from '../../model/auth'; import { _window } from '../auth_window'; import * as js from '../load_js'; const NETWORK_TIMEOUT = new Delay(30000, 60000); /** * Reset unlaoded GApi modules. If gapi.load fails due to a network error, * it will stop working after a retrial. This is a hack to fix this issue. */ function resetUnloadedGapiModules(): void { // Clear last failed gapi.load state to force next gapi.load to first // load the failed gapi.iframes module. // Get gapix.beacon context. const beacon = _window().___jsl; // Get current hint. if (beacon?.H) { // Get gapi hint. for (const hint of Object.keys(beacon.H)) { // Requested modules. beacon.H[hint].r = beacon.H[hint].r || []; // Loaded modules. beacon.H[hint].L = beacon.H[hint].L || []; // Set requested modules to a copy of the loaded modules. beacon.H[hint].r = [...beacon.H[hint].L]; // Clear pending callbacks. if (beacon.CP) { for (let i = 0; i < beacon.CP.length; i++) { // Remove all failed pending callbacks. beacon.CP[i] = null; } } } } } function loadGapi(auth: AuthInternal): Promise<gapi.iframes.Context> { return new Promise<gapi.iframes.Context>((resolve, reject) => { // Function to run when gapi.load is ready. function loadGapiIframe(): void { // The developer may have tried to previously run gapi.load and failed. // Run this to fix that. resetUnloadedGapiModules(); gapi.load('gapi.iframes', { callback: () => { resolve(gapi.iframes.getContext()); }, ontimeout: () => { // The above reset may be sufficient, but having this reset after // failure ensures that if the developer calls gapi.load after the // connection is re-established and before another attempt to embed // the iframe, it would work and would not be broken because of our // failed attempt. // Timeout when gapi.iframes.Iframe not loaded. resetUnloadedGapiModules(); reject(_createError(auth, AuthErrorCode.NETWORK_REQUEST_FAILED)); }, timeout: NETWORK_TIMEOUT.get() }); } if (_window().gapi?.iframes?.Iframe) { // If gapi.iframes.Iframe available, resolve. resolve(gapi.iframes.getContext()); } else if (!!_window().gapi?.load) { // Gapi loader ready, load gapi.iframes. loadGapiIframe(); } else { // Create a new iframe callback when this is called so as not to overwrite // any previous defined callback. This happens if this method is called // multiple times in parallel and could result in the later callback // overwriting the previous one. This would end up with a iframe // timeout. const cbName = js._generateCallbackName('iframefcb'); // GApi loader not available, dynamically load platform.js. _window()[cbName] = () => { // GApi loader should be ready. if (!!gapi.load) { loadGapiIframe(); } else { // Gapi loader failed, throw error. reject(_createError(auth, AuthErrorCode.NETWORK_REQUEST_FAILED)); } }; // Load GApi loader. return js._loadJS(`https://apis.google.com/js/api.js?onload=${cbName}`); } }).catch(error => { // Reset cached promise to allow for retrial. cachedGApiLoader = null; throw error; }); } let cachedGApiLoader: Promise<gapi.iframes.Context> | null = null; export function _loadGapi(auth: AuthInternal): Promise<gapi.iframes.Context> { cachedGApiLoader = cachedGApiLoader || loadGapi(auth); return cachedGApiLoader; } export function _resetLoader(): void { cachedGApiLoader = null; }