UNPKG

@aws-amplify/xr

Version:
389 lines (340 loc) • 13.2 kB
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { ConsoleLogger as Logger, Signer, Credentials, Constants, } from '@aws-amplify/core'; import { AbstractXRProvider } from './XRProvider'; import { ProviderOptions, SceneOptions } from '../types'; import { XRNoSceneConfiguredError, XRSceneNotFoundError, XRSceneNotLoadedError, XRNoDomElement, XRSceneLoadFailure, } from '../Errors'; type SumerianSceneOptions = SceneOptions & { progressCallback: Function }; const SUMERIAN_SERVICE_NAME = 'sumerian'; const SUMERIAN_DEPRECATION_MESSAGE = 'The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function and as a result, will no longer be available.'; const logger = new Logger('SumerianProvider'); /** * @deprecated The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be * available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function * and as a result, will no longer be available. */ export class SumerianProvider extends AbstractXRProvider { /** * @deprecated The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be * available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function * and as a result, will no longer be available. */ constructor(options: ProviderOptions = {}) { super(options); } getProviderName() { return 'SumerianProvider'; } private async loadScript(url) { return new Promise((resolve, reject) => { const scriptElement = document.createElement('script'); scriptElement.src = url; scriptElement.addEventListener('load', event => { resolve(); }); scriptElement.addEventListener('error', event => { reject(new Error(`Failed to load script: ${url}`)); }); document.head.appendChild(scriptElement); }); } /** * @deprecated The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be * available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function * and as a result, will no longer be available. */ public async loadScene( sceneName: string, domElementId: string, sceneOptions: SumerianSceneOptions ) { if (!sceneName) { const errorMsg = 'No scene name passed into loadScene'; logger.error(errorMsg); throw new XRSceneLoadFailure(errorMsg); } if (!domElementId) { const errorMsg = 'No dom element id passed into loadScene'; logger.error(errorMsg); throw new XRNoDomElement(errorMsg); } const element = document.getElementById(domElementId); if (!element) { const errorMsg = `DOM element id, ${domElementId} not found`; logger.error(errorMsg); throw new XRNoDomElement(errorMsg); } const scene = this.getScene(sceneName); if (!scene.sceneConfig) { const errorMsg = `No scene config configured for scene: ${sceneName}`; logger.error(errorMsg); throw new XRSceneLoadFailure(errorMsg); } const sceneUrl = scene.sceneConfig.url; const sceneId = scene.sceneConfig.sceneId; let sceneRegion; if (scene.sceneConfig.hasOwnProperty('region')) { // Use the scene region on the Sumerian scene configuration sceneRegion = scene.sceneConfig.region; } else if (this.options.hasOwnProperty('region')) { // Use the scene region on the XR category configuration sceneRegion = this.options.region; } else { const errorMsg = `No region configured for scene: ${sceneName}`; logger.error(errorMsg); throw new XRSceneLoadFailure(errorMsg); } const awsSDKConfigOverride = { region: sceneRegion, // This is passed to the AWS clients created in // Sumerian's AwsSystem // This helps other services(like Lex and Polly) to track // traffic coming from Sumerian scenes embedded with Amplify customUserAgent: `${Constants.userAgent}-SumerianScene`, }; // We are signing the requests to Sumerian ourselves instead of using the AWS SDK // We want to set the user agent header const fetchOptions = { headers: { // This sets the AWS user agent string // So the Sumerian service knows this request is // from Amplify 'X-Amz-User-Agent': Constants.userAgent, }, }; let url = sceneUrl; try { // Get credentials from Auth and sign the request const credentials = await Credentials.get(); awsSDKConfigOverride['credentials'] = credentials; const accessInfo = { secret_key: credentials.secretAccessKey, access_key: credentials.accessKeyId, session_token: credentials.sessionToken, }; const serviceInfo = { region: sceneRegion, service: SUMERIAN_SERVICE_NAME, }; const request = Signer.sign( { method: 'GET', url: sceneUrl }, accessInfo, serviceInfo ); fetchOptions.headers = { ...fetchOptions.headers, ...request.headers }; url = request.url; } catch (e) { logger.debug('No credentials available, the request will be unsigned'); } let apiResponse; try { apiResponse = await fetch(url, fetchOptions); } catch (e) { throw new XRSceneLoadFailure(SUMERIAN_DEPRECATION_MESSAGE); } const apiResponseJson = await apiResponse.json(); if (apiResponse.status === 404) { throw new XRSceneLoadFailure(SUMERIAN_DEPRECATION_MESSAGE); } if (apiResponse.status === 403) { if (apiResponseJson.message) { logger.error( `Failure to authenticate user: ${apiResponseJson.message}` ); throw new XRSceneLoadFailure( `Failure to authenticate user: ${apiResponseJson.message}` ); } else { logger.error(`Failure to authenticate user`); throw new XRSceneLoadFailure(`Failure to authenticate user`); } } // Get bundle data from scene api response const sceneBundleData = apiResponseJson.bundleData[sceneId]; const sceneBundle = await fetch(sceneBundleData.url, { headers: sceneBundleData.headers, }); const sceneBundleJson = await sceneBundle.json(); try { // Load the Sumerian bootstrapper script into the DOM await this.loadScript(sceneBundleJson[sceneId].bootstrapperUrl); } catch (error) { logger.error(error); throw new XRSceneLoadFailure(error); } const progressCallback = sceneOptions.progressCallback ? sceneOptions.progressCallback : undefined; const publishParamOverrides = scene.publishParamOverrides ? scene.publishParamOverrides : undefined; const sceneLoadParams = { element, sceneId, sceneBundle: sceneBundleJson, apiResponse: apiResponseJson, progressCallback, publishParamOverrides, awsSDKConfigOverride, }; // Load the scene into the dom and set the scene controller const sceneController = await (<any>window).SumerianBootstrapper.loadScene( sceneLoadParams ); scene.sceneController = sceneController; scene.isLoaded = true; // Log scene warnings for (const warning of sceneController.sceneLoadWarnings) { logger.warn(`loadScene warning: ${warning}`); } } /** * @deprecated The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be * available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function * and as a result, will no longer be available. */ public isSceneLoaded(sceneName: string) { const scene = this.getScene(sceneName); return scene.isLoaded || false; } private getScene(sceneName: string) { if (!this.options.scenes) { const errorMsg = 'No scenes were defined in the configuration'; logger.error(errorMsg); throw new XRNoSceneConfiguredError(errorMsg); } if (!sceneName) { const errorMsg = 'No scene name was passed'; logger.error(errorMsg); throw new XRSceneNotFoundError(errorMsg); } if (!this.options.scenes[sceneName]) { const errorMsg = `Scene '${sceneName}' is not configured`; logger.error(errorMsg); throw new XRSceneNotFoundError(errorMsg); } return this.options.scenes[sceneName]; } /** * @deprecated The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be * available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function * and as a result, will no longer be available. */ public getSceneController(sceneName: string) { if (!this.options.scenes) { const errorMsg = 'No scenes were defined in the configuration'; logger.error(errorMsg); throw new XRNoSceneConfiguredError(errorMsg); } const scene = this.options.scenes[sceneName]; if (!scene) { const errorMsg = `Scene '${sceneName}' is not configured`; logger.error(errorMsg); throw new XRSceneNotFoundError(errorMsg); } const sceneController = scene.sceneController; if (!sceneController) { const errorMsg = `Scene controller for '${sceneName}' has not been loaded`; logger.error(errorMsg); throw new XRSceneNotLoadedError(errorMsg); } return sceneController; } /** * @deprecated The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be * available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function * and as a result, will no longer be available. */ public isVRCapable(sceneName: string): boolean { const sceneController = this.getSceneController(sceneName); return sceneController.vrCapable; } /** * @deprecated The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be * available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function * and as a result, will no longer be available. */ public isVRPresentationActive(sceneName: string): boolean { const sceneController = this.getSceneController(sceneName); return sceneController.vrPresentationActive; } /** * @deprecated The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be * available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function * and as a result, will no longer be available. */ public start(sceneName: string) { const sceneController = this.getSceneController(sceneName); sceneController.start(); } /** * @deprecated The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be * available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function * and as a result, will no longer be available. */ public enterVR(sceneName: string) { const sceneController = this.getSceneController(sceneName); sceneController.enterVR(); } /** * @deprecated The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be * available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function * and as a result, will no longer be available. */ public exitVR(sceneName: string) { const sceneController = this.getSceneController(sceneName); sceneController.exitVR(); } /** * @deprecated The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be * available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function * and as a result, will no longer be available. */ public isMuted(sceneName: string): boolean { const sceneController = this.getSceneController(sceneName); return sceneController.muted; } /** * @deprecated The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be * available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function * and as a result, will no longer be available. */ public setMuted(sceneName: string, muted: boolean) { const sceneController = this.getSceneController(sceneName); sceneController.muted = muted; } /** * @deprecated The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be * available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function * and as a result, will no longer be available. */ public onSceneEvent( sceneName: string, eventName: string, eventHandler: Function ) { const sceneController = this.getSceneController(sceneName); sceneController.on(eventName, eventHandler); } /** * @deprecated The Amazon Sumerian service is no longer accepting new customers. Existing customer scenes will not be * available after February 21, 2023. The AWS Amplify XR features depend on the Amazon Sumerian service to function * and as a result, will no longer be available. */ public enableAudio(sceneName: string) { const sceneController = this.getSceneController(sceneName); sceneController.enableAudio(); } }