UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

241 lines (239 loc) 10.8 kB
import { forkJoin, of } from 'rxjs'; import { catchError, map, mergeMap } from 'rxjs/operators'; import { ErrorExtended } from '../data/error-extended'; import { NativeQ } from '../data/native-q'; import { LogLevel } from '../diagnostics/log-level'; import { Logging } from '../diagnostics/logging'; import { HostCoreManager, HostCoreTokenMode } from '../host/host-core-manager'; import { EnvironmentModule } from './environment-modules'; /** * The Manifest service class. * (Localized string cannot be used in this class due to initialization phase when the strings are not ready yet.) */ export class ManifestLoader { static logSourceName = 'ManifestLoader'; static gatewayUrl = 'gatewayUrl'; static manifestFile = 'manifest.json'; static deferred = NativeQ.defer(); static internalLoaded = ManifestLoader.deferred.promise; /** * Manifest loading promise. */ get loaded() { return ManifestLoader.internalLoaded; } /** * Load the manifest. */ static loadManifest() { const self = MsftSme.self(); const mode = self.Init ? self.Init.mode : 0 /* MsftSme.EnvironmentMode.NotUse */; const hostCoreManager = new HostCoreManager(); switch (mode) { case 0 /* MsftSme.EnvironmentMode.NotUse */: // Turn OFF iframe feature. ManifestLoader.deferred.reject('no iFrame'); break; case 1 /* MsftSme.EnvironmentMode.LoadEmbedded */: // JSON file posting by module iframe. const manifest = { name: self.Init.moduleName, version: self.Init.moduleVersion, signature: EnvironmentModule.defaultSignature, shell: { name: EnvironmentModule.nameOfShell, origin: self.Init.shellOrigin } }; // Turn ON module self-loading. ManifestLoader.load(hostCoreManager, manifest); break; case 2 /* MsftSme.EnvironmentMode.Load */: // Turn ON iframe feature by Shell and Module. ManifestLoader.load(hostCoreManager); break; } return ManifestLoader.internalLoaded; } /** * Load the manifest into the MsftSme.Environment. * * @param hostCoreManager the hostCoreManager object to load the manifest. * @param manifest the self loading manifest. * @return Promise<any> the promise object. */ static load(hostCoreManager, manifest) { if (manifest) { ManifestLoader.update(manifest, null); return ManifestLoader.internalLoaded; } const gatewayUrlParam = MsftSme.getLocationSearchParameter(ManifestLoader.gatewayUrl); let manifestUrl = ManifestLoader.manifestFile; if (gatewayUrlParam && MsftSme.self().Init.isProduction && Object.keys(MsftSme.sideLoad()).length === 0) { // use the gateway endpoint for manifest source. manifestUrl = `${gatewayUrlParam.value}/${ManifestLoader.manifestFile}`; } hostCoreManager.httpGet(manifestUrl) .pipe(mergeMap(result => ManifestLoader.mergeGatewayManifest(hostCoreManager, result.response)), mergeMap(shellManifest => { const response = shellManifest; if (response.modules) { return ManifestLoader.fetchSideloadManifests(hostCoreManager) .pipe(map(sideLoads => { const sideloadShellOrigins = []; sideLoads = sideLoads.filter(s => { if (MsftSme.isNullOrUndefined(s)) { return false; } const isShell = s.name === EnvironmentModule.nameOfShell; if (isShell) { sideloadShellOrigins.push(s.origin); } return !isShell; }); if (sideloadShellOrigins.length > 0) { Logging.log({ source: ManifestLoader.logSourceName, level: LogLevel.Warning, consoleGroupHeader: `Unable to sideload: "${sideloadShellOrigins}".`, message: `Cannot sideload ${EnvironmentModule.nameOfShell} from ${sideloadShellOrigins}. Did you mean to run ${EnvironmentModule.nameOfShell} locally?` }); } return { manifest: response, sideLoads: sideLoads }; })); } return of({ manifest: response, sideLoads: [] }); })) .subscribe({ next: result => { const manifestResult = result.manifest; const modules = manifestResult.modules; const selfInit = MsftSme.self().Init; selfInit.shellVersion = manifestResult.version; selfInit.gatewayApiVersion = manifestResult.gatewayApiVersion; selfInit.gatewayPlatform = manifestResult.gatewayPlatform; result.sideLoads.forEach(sideLoad => { if (sideLoad) { sideLoad.isSideLoaded = true; const foundIndex = modules.findIndex((item) => item.name === sideLoad.name); if (foundIndex >= 0) { modules.splice(foundIndex, 1, sideLoad); } else { modules.push(sideLoad); } } }); ManifestLoader.update(result.manifest, hostCoreManager.token); }, error: error => { // communicate main.ts for error message. const extendedError = error; if (hostCoreManager.tokenMode === HostCoreTokenMode.Aad) { extendedError.extendedSource = ErrorExtended.sources.aadSso; } ManifestLoader.deferred.reject(error); } }); return ManifestLoader.internalLoaded; } /** * Merges the GatewayUrl manifest with the passed in shell manifest * Merges modules only at this time with a preference for modules included in the shell */ static mergeGatewayManifest(hostCoreManager, shellManifest) { // it's production mode and no side-loading omits calling manifest.json again. if (MsftSme.self().Init.isProduction && Object.keys(MsftSme.sideLoad()).length === 0) { return of(shellManifest); } const gatewayUrlParam = MsftSme.getLocationSearchParameter(ManifestLoader.gatewayUrl); if (!gatewayUrlParam) { return of(shellManifest); } return hostCoreManager.getNoCache(`${gatewayUrlParam.value}/${ManifestLoader.manifestFile}`, false, 'json') .pipe(map(result => { const gatewayManifest = result.response; if (Array.isArray(gatewayManifest.modules)) { if (!Array.isArray(shellManifest.modules)) { shellManifest.modules = gatewayManifest.modules; } else { gatewayManifest.modules.forEach(mod => { mod.origin = gatewayUrlParam.value; const foundIndex = shellManifest.modules.findIndex((item) => item.name === mod.name); if (foundIndex === -1) { shellManifest.modules.push(mod); } }); } } return shellManifest; }), catchError(() => { // no localization Logging.log({ source: ManifestLoader.logSourceName, level: LogLevel.Warning, consoleGroupHeader: `Unable to load gateway manifest: "${gatewayUrlParam.value}".`, message: `Cannot load ${gatewayUrlParam.value}. Please make sure that a manifest.json is available at this location.` }); return of(shellManifest); })); } /** * retrieves all of the side loaded manifests. * * @return Observable<any[]> the manifests. */ static fetchSideloadManifests(hostCoreManager) { const sideLoadList = MsftSme.sideLoad(); if (Object.keys(sideLoadList).length === 0) { return of([]); } const sideLoadManifestAwaiters = []; MsftSme.forEachKey(sideLoadList, (key, sideLoad) => { sideLoadManifestAwaiters.push( // don't send credentials when debugging a side-loading module. hostCoreManager.getNoCache(`${sideLoad.origin}/${ManifestLoader.manifestFile}`, false, 'json', false) .pipe(map(result => { const manifest = result.response; manifest.origin = sideLoad.origin; return manifest; }), catchError(() => { // no localization Logging.log({ source: ManifestLoader.logSourceName, level: LogLevel.Warning, consoleGroupHeader: `Unable to sideload: "${sideLoad.origin}".`, message: `Cannot sideload ${sideLoad.origin}. Please make sure that an extension is running at this origin.` }); return of(null); }))); }); return forkJoin(sideLoadManifestAwaiters); } /** * Update the environment by the manifest. */ static update(manifest, token) { try { const self = MsftSme.self(); if (token) { // store the last token if exists. if (!manifest.configuration) { manifest.configuration = {}; } // passed the signOn objec to GatewayConnection object to configure into the SignOnManager. manifest.configuration.signOn = { signedHttpRequestToken: token }; } self.Environment = EnvironmentModule.createEnvironment(manifest, self.Resources.localeId); ManifestLoader.deferred.resolve(); } catch (e) { // no localization const message = 'Unable to load the manifest: {0}'.format(e); ManifestLoader.deferred.reject(message); throw new Error(message); } } } //# sourceMappingURL=manifest-loader.js.map