{"version":3,"sources":["../../../packages/core/rpc/rpc.ts"],"names":[],"mappings":"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","file":"rpc.d.ts","sourcesContent":["import { Observable, Subject } from 'rxjs';\r\nimport { CoreEnvironment } from '../data/core-environment';\r\nimport { NativeDeferred, NativeQ } from '../data/native-q';\r\nimport { LogLevel } from '../diagnostics/log-level';\r\nimport { Logging } from '../diagnostics/logging';\r\nimport { SmeWebTelemetry } from '../diagnostics/sme-web-telemetry';\r\nimport { Strings } from '../generated/strings';\r\nimport { EnvironmentModuleEntryPoint } from '../manifest/environment-modules';\r\nimport {\r\n    CommandCallBackType,\r\n    RpcActivateDataInternal,\r\n    RpcBase,\r\n    RpcBaseData,\r\n    RpcDeactivateResult,\r\n    RpcInboundCommands,\r\n    RpcInboundHandlers,\r\n    RpcInitData,\r\n    RpcInitDataInternal,\r\n    RpcInitResult,\r\n    RpcMode,\r\n    RpcOpenDataInternal,\r\n    RpcOpenResult,\r\n    RpcOutboundCommands,\r\n    RpcOutboundHandlers,\r\n    RpcPingResult,\r\n    RpcShutdownData,\r\n    RpcShutdownResult,\r\n    RpcType,\r\n    rpcVersion\r\n} from './rpc-base';\r\nimport { RpcManager } from './rpc-manager';\r\nimport { RpcOutbound } from './rpc-outbound';\r\nimport { RpcSeek, RpcSeekMode, RpcSeekResult } from './seek/rpc-seek-model';\r\n\r\n/**\r\n * Deferred data object.\r\n */\r\nexport interface DeferredData<TData, TResult> {\r\n    deferred: NativeDeferred<TResult>;\r\n    data: TData;\r\n}\r\n\r\n/**\r\n * The Rpc class.\r\n */\r\nexport class Rpc {\r\n    // RPC timeout 10 seconds.\r\n    private static rpcTimeout = 10 * 1000;\r\n\r\n    /**\r\n     * This subject is updated whenever there's new reported data\r\n     */\r\n    private rpcSubjects: { [index: string]: Subject<DeferredData<any, any>> };\r\n\r\n    /**\r\n     * Deferred response collection.\r\n     */\r\n    private deferredCollection = new Map<RpcOutboundCommands, DeferredData<any, any>>();\r\n\r\n    /**\r\n     * Active status of rpc by Observable.\r\n     */\r\n    private stateChangedInternal: Subject<boolean> = new Subject<boolean>();\r\n\r\n    /**\r\n     * Active status of rpc.\r\n     */\r\n    private stateActiveInternal = false;\r\n\r\n    /**\r\n     * Inbound module handlers to process when rpc is called.\r\n     *  - called from Module to Shell.\r\n     */\r\n    private rpcInboundHandlers: RpcInboundHandlers = {\r\n        FailedHandler: (data: RpcBaseData) => {\r\n            return this.processNextForSubject<RpcBaseData, void>(RpcInboundCommands.Failed, data);\r\n        },\r\n        SeekHandler: (data: RpcSeek) => {\r\n            return Promise.resolve(<RpcSeekResult>{ name: data.sourceName, subName: data.sourceSubName });\r\n        }\r\n    };\r\n\r\n    /**\r\n     * Outbound shell handlers to process when rpc is called.\r\n     *  - called from Shell to Module.\r\n     *  - if code reached a handler, module is not ready yet.\r\n     *    set timeout for RPC call.\r\n     */\r\n    private rpcOutboundHandlers: RpcOutboundHandlers = {\r\n        InitHandler: (data: RpcInitDataInternal) =>\r\n            this.createTimerPromise<RpcInitDataInternal, RpcInitResult>(\r\n                RpcOutboundCommands.Init, Rpc.rpcTimeout,\r\n                <RpcInitDataInternal>{ locale: data.locale }),\r\n        OpenHandler: (rpcOpenData: RpcOpenDataInternal) =>\r\n            this.createTimerPromise<RpcOpenDataInternal, RpcOpenResult>(RpcOutboundCommands.Open, Rpc.rpcTimeout, rpcOpenData),\r\n        ActivateHandler: (data: RpcActivateDataInternal) =>\r\n            this.createTimerPromise<RpcBaseData, void>(RpcOutboundCommands.Activate, Rpc.rpcTimeout, data),\r\n        Deactivate2Handler: (data: RpcBaseData) =>\r\n            this.createTimerPromise<RpcBaseData, RpcDeactivateResult>(RpcOutboundCommands.Deactivate2, Rpc.rpcTimeout, data),\r\n        ShutdownHandler: (data: RpcShutdownData) =>\r\n            this.createTimerPromise<RpcShutdownData, RpcShutdownResult>(RpcOutboundCommands.Shutdown, Rpc.rpcTimeout, data),\r\n        PingHandler: () => {\r\n            this.changeActiveState(true);\r\n            return Promise.resolve(<RpcPingResult>{ name: 'pong' });\r\n        }\r\n    };\r\n\r\n    /**\r\n     * Rpc manager object.\r\n     */\r\n    public rpcManager: RpcManager = new RpcManager();\r\n\r\n    /**\r\n     * Initializes a new instance of the Rpc class.\r\n     *\r\n     * @param http the Http class instance injected.\r\n     */\r\n    constructor() {\r\n        this.rpcSubjects = {};\r\n        const commands = Object.keys(RpcInboundCommands);\r\n        commands.forEach((value) => {\r\n            this.rpcSubjects[RpcInboundCommands[value]] = new Subject<any>();\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Gets observable to watch the state change.\r\n     */\r\n    public get stateChanged(): Observable<boolean> {\r\n        this.stateChangedInternal.next(this.stateActiveInternal);\r\n        return this.stateChangedInternal.asObservable();\r\n    }\r\n\r\n    /**\r\n     * Gets the state of rpc.\r\n     */\r\n    public get stateActive(): boolean {\r\n        return this.stateActiveInternal;\r\n    }\r\n\r\n    /**\r\n     * Gets whether rpc is running on the shell.\r\n     */\r\n    public get isShell(): boolean {\r\n        if (this.rpcManager.rpcChannel == null) {\r\n            const message = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcNotInitialized.message;\r\n            throw new Error(message);\r\n        }\r\n\r\n        return this.rpcManager.rpcChannel.rpcMode === RpcMode.Shell;\r\n    }\r\n\r\n    /**\r\n     * Register inbound command handler.\r\n     *\r\n     * @param command The command name.\r\n     * @param handler The command handler.\r\n     */\r\n    public registerInboundHandler(command: string, handler: CommandCallBackType): void {\r\n        const handlerName = RpcBase.commandToHandlerName(command);\r\n        this.rpcInboundHandlers[handlerName] = handler;\r\n        this.rpcManager.registerInboundHandler(command, handler);\r\n    }\r\n\r\n    /**\r\n     * Register outbound command handler.\r\n     *\r\n     * @param command The command name.\r\n     * @param handler The command handler.\r\n     */\r\n    public registerOutboundHandler(command: string, handler: CommandCallBackType): void {\r\n        const handlerName = RpcBase.commandToHandlerName(command);\r\n        this.rpcOutboundHandlers[handlerName] = handler;\r\n    }\r\n\r\n    /**\r\n     * Initializes Rpc configuration\r\n     */\r\n    public init(): void {\r\n        this.rpcManager.init(this.rpcInboundHandlers, this.rpcOutboundHandlers);\r\n        if (this.isShell) {\r\n            this.changeActiveState(true);\r\n        }\r\n    }\r\n\r\n    /***************************************************************\r\n     * Section for Shell usage.\r\n     ***************************************************************/\r\n\r\n    /**\r\n     * This updates its value every time there's a reported data from the rpc channel\r\n     */\r\n    public moduleSubjects<T>(commandType: RpcInboundCommands): Observable<DeferredData<T, any>> {\r\n        return <Observable<DeferredData<T, any>>>this.rpcSubjects[RpcInboundCommands[commandType]];\r\n    }\r\n\r\n    /**\r\n     * Connect a module with name and iframe.\r\n     * - start pinging to iframe to wait for response.\r\n     *\r\n     * @param name the name of the module.\r\n     * @param path the path to open the module the module name.\r\n     * @param iframe the iframe window object.\r\n     * @param primary the primary window to affect router url.\r\n     * @return Promise<string> the promise with subName created for the window.\r\n     */\r\n    public moduleConnect(name: string, path: string, iframe: Window, primary: boolean): Promise<string> {\r\n        return this.rpcManager.connectRpcOutbound(name, path, iframe, primary);\r\n    }\r\n\r\n    /**\r\n     * Init the module.\r\n     *\r\n     * @param name the name of module.\r\n     * @param subName the sub name of rpc channel.\r\n     * @param entryPointType the entry point type.\r\n     * @return Promise<void> the promise object of init result.\r\n     */\r\n    public moduleInit(name: string, subName: string, entryPoint: EnvironmentModuleEntryPoint): Promise<RpcInitResult> {\r\n        const rpc = this.rpcManager.rpcChannel.getRpc<RpcOutbound>(name, subName, RpcType.Outbound);\r\n        const self = MsftSme.self();\r\n        const data: RpcInitData = {\r\n            entryPointType: entryPoint.entryPointType,\r\n            entryPointName: entryPoint.name,\r\n            theme: self.Resources.theme,\r\n            assets: self.Resources.assets,\r\n            moduleAssets: self.Resources.moduleAssets,\r\n            locale: self.Resources.localeId,\r\n            localeRegional: self.Resources.localeRegionalId,\r\n            lib: self.Resources.lib,\r\n            sessionId: self.Init.sessionId,\r\n            modules: self.Environment.modules,\r\n            accessibilityMode: self.Resources.accessibilityMode,\r\n            sessionExpiration: self.Init.sessionExpiration,\r\n            performanceProfile: MsftSme.getPerformanceProfile(),\r\n            connectivityLevel: self.Init.connectivityLevel,\r\n            consoleDebug: MsftSme.consoleDebug(),\r\n            sideLoad: MsftSme.sideLoad(),\r\n            experiments: MsftSme.experiments(),\r\n            shellVersion: self.Init.shellVersion,\r\n            gatewayApiVersion: self.Init.gatewayApiVersion,\r\n            gatewayPlatform: self.Init.gatewayPlatform\r\n        };\r\n        return rpc.init(data).then(result => {\r\n            const strings = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Rpc;\r\n            // copy the version string of remote module.\r\n            if (result && result.version) {\r\n                rpc.version = result.version;\r\n                Logging.log({\r\n                    level: LogLevel.Verbose,\r\n                    message: strings.Version.message.format(rpcVersion, name, rpc.version),\r\n                    source: 'rpc.moduleInit'\r\n                });\r\n            } else {\r\n                const message = strings.MissingVersion.message.format(name);\r\n                Logging.log({\r\n                    level: LogLevel.Critical,\r\n                    message,\r\n                    source: 'rpc.moduleInit'\r\n                });\r\n                throw new Error(message);\r\n            }\r\n\r\n            this.changeActiveState(true);\r\n            return result;\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Open the module by specifying the path and parameters.\r\n     *\r\n     * @param name the name of module.\r\n     * @param subName the sub name of rpc channel.\r\n     * @param path the open path.\r\n     * @return Promise<RpcOpenResult> the promise object of RpcOpenResult.\r\n     */\r\n    public moduleOpen(name: string, subName: string, path: string): Promise<RpcOpenResult> {\r\n        const rpc = <RpcOutbound>this.rpcManager.rpcChannel.getRpc(name, subName, RpcType.Outbound);\r\n        return rpc.open({ path }).then(result => {\r\n            this.changeActiveState(true);\r\n            return result;\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Activate the module to start receiving data.\r\n     *\r\n     * @param name the module name.\r\n     * @param subName the sub name of rpc channel.\r\n     * @param primary the primary window to affect router url.\r\n     * @param url the inner url to open.\r\n     * @return Promise<void> the promise of activation result.\r\n     */\r\n    public moduleActivate(name: string, subName: string, primary: boolean, url: string): Promise<void> {\r\n        const rpc = this.rpcManager.reconnectRpcOutbound(name, subName, primary);\r\n        return rpc.activate({ url })\r\n            .then(data => {\r\n                this.changeActiveState(true);\r\n                return data;\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Deactivate 2 the module to stop receiving data.\r\n     *\r\n     * @param name the module name.\r\n     * @param subName the sub name of rpc channel.\r\n     * @return Promise<void> the promise of deactivation result.\r\n     */\r\n    public moduleDeactivate2(name: string, subName: string): Promise<RpcDeactivateResult> {\r\n        this.changeActiveState(false);\r\n        const rpc = this.rpcManager.rpcChannel.getRpc<RpcOutbound>(name, subName, RpcType.Outbound);\r\n        return rpc.deactivate2({});\r\n    }\r\n\r\n    /**\r\n     * Request to shutdown the module.\r\n     *\r\n     * @param name the module name.\r\n     * @param subName the sub name of rpc channel.\r\n     * @param primary the primary window to affect router url.\r\n     * @param force the forcible state.\r\n     * @return Promise<RpcShutdownResult> the promise object of result.\r\n     */\r\n    public moduleShutdown(name: string, subName: string, primary: boolean, force: boolean): Promise<RpcShutdownResult> {\r\n        const rpc = this.rpcManager.reconnectRpcOutbound(name, subName, primary);\r\n        return rpc.shutdown({ force: force });\r\n    }\r\n\r\n    /**\r\n     * Remove the module from the rpc channel.\r\n     *\r\n     * @param name the module name.\r\n     * @param subName the sub name of rpc channel.\r\n     */\r\n    public moduleRemove(name: string, subName: string): void {\r\n        this.rpcManager.removeRpcOutbound(name, subName);\r\n    }\r\n\r\n    /**\r\n     * Get module version string.\r\n     *\r\n     * @param name the name of module.\r\n     * @param subName the sub name of rpc channel.\r\n     * @return string the RPC version of module.\r\n     */\r\n    public moduleVersion(name: string, subName: string): string {\r\n        const rpc = <RpcOutbound>this.rpcManager.rpcChannel.getRpc(name, subName, RpcType.Outbound);\r\n        return rpc && rpc.version;\r\n    }\r\n\r\n    /***************************************************************\r\n     * Section for Module usage.\r\n     ***************************************************************/\r\n\r\n    /**\r\n     * Register outbound handler. It accepts delay register in case of loading/initialization took a time for module.\r\n     *\r\n     * @param command the name of RPC Shell command.\r\n     * @param handler the handler to handle Shell request.\r\n     */\r\n    public register(command: string, handler: (data: any) => Promise<any>): void;\r\n\r\n    /**\r\n     * Register outbound handler. It accepts delay register in case of loading/initialization took a time for module.\r\n     *\r\n     * @param command the enum ID of RPC Shell command.\r\n     * @param handler the handler to handle Shell request.\r\n     */\r\n    public register(command: RpcOutboundCommands, handler: (data: any) => Promise<any>): void;\r\n    public register(command: RpcOutboundCommands | string, handler: (data: any) => Promise<any>): void {\r\n        if (typeof command === 'string') {\r\n            const commandName: string = command;\r\n            this.rpcManager.rpcInbound.register(commandName, handler);\r\n            return;\r\n        }\r\n\r\n        const deferredData = <DeferredData<any, any>>this.deferredCollection[command];\r\n        if (deferredData) {\r\n            delete this.deferredCollection[command];\r\n            handler(deferredData.data).then(deferredData.deferred.resolve, deferredData.deferred.reject);\r\n            return;\r\n        }\r\n\r\n        if (command === RpcOutboundCommands.Init) {\r\n            const modifiedHandler = (data: RpcInitDataInternal) => {\r\n                // node context is used before passing request to handler.\r\n                this.changeActiveState(true);\r\n                const self = MsftSme.self();\r\n                self.Init.entryPointType = data.entryPointType;\r\n                self.Init.entryPointName = data.entryPointName;\r\n                self.Init.sessionId = data.sessionId;\r\n                self.Init.sessionExpiration = data.sessionExpiration;\r\n                self.Init.performanceProfile = data.performanceProfile;\r\n                self.Init.shellVersion = data.shellVersion;\r\n\r\n                // default is 1.0.0 and Windows which indicate it's running legacy GW.\r\n                self.Init.gatewayApiVersion = data.gatewayApiVersion ?? '1.0.0',\r\n                self.Init.gatewayPlatform = data.gatewayPlatform ?? 'Windows';\r\n                self.Environment.modules = data.modules;\r\n                self.Init.connectivityLevel = data.connectivityLevel;\r\n                self.Resources.lib = data.lib;\r\n                self.Resources.moduleAssets = data.moduleAssets;\r\n\r\n                if (!MsftSme.isNullOrUndefined(self.Resources.accessibilityMode)\r\n                    && !MsftSme.isNullOrUndefined(data.accessibilityMode)\r\n                    && CoreEnvironment.accessibilityManager) {\r\n                    self.Resources.accessibilityMode = data.accessibilityMode;\r\n                    CoreEnvironment.accessibilityManager.changeAccessibilityMode(self.Resources.accessibilityMode);\r\n                }\r\n\r\n                // ensure that global environment settings persist across origins\r\n                if (!MsftSme.isNullOrUndefined(data.consoleDebug) && MsftSme.consoleDebug() !== data.consoleDebug) {\r\n                    MsftSme.consoleDebug(data.consoleDebug);\r\n                }\r\n\r\n                if (!MsftSme.isNullOrUndefined(data.sideLoad)) {\r\n                    const sideLoadKeys = Object.keys(MsftSme.sideLoad() || {});\r\n                    const dataSideLoadKeys = Object.keys(data.sideLoad || {});\r\n\r\n                    if (sideLoadKeys.length !== dataSideLoadKeys.length || sideLoadKeys.some(key => !!data.sideLoad[key])) {\r\n                        MsftSme.sideLoadReset();\r\n                        dataSideLoadKeys.forEach(k => MsftSme.sideLoad(k));\r\n                    }\r\n                }\r\n\r\n                if (!MsftSme.isNullOrUndefined(data.experiments)) {\r\n                    const experiments = MsftSme.experiments();\r\n                    if (experiments.length !== data.experiments.length || experiments.some((v, i) => v !== data.experiments[i])) {\r\n                        MsftSme.experiments(data.experiments);\r\n                    }\r\n                }\r\n\r\n                if (CoreEnvironment.assetManager && data.theme && data.assets) {\r\n                    CoreEnvironment.assetManager.loadAssets(data.theme, data.assets);\r\n                }\r\n\r\n                for (const item of data.modules) {\r\n                    // NOTES: the next 'if' block code can be removed only if all extensions adapted newer shell. (after 1.1114.0)\r\n                    if (!self.Init.shellVersion && item.name === 'msft.sme.shell-extensions') {\r\n                        // look for shell version if missing from older MSI/ShellUI.\r\n                        self.Init.shellVersion = item.version;\r\n                    }\r\n\r\n                    if (item.name === self.Init.moduleName) {\r\n                        self.Environment.version = item.version || self.Environment.version;\r\n                    }\r\n                }\r\n\r\n                const localeLoader = CoreEnvironment.moduleLoadLocale({ id: data.localeRegional || data.locale, neutral: data.locale });\r\n                const passingData = <RpcInitData>{\r\n                    locale: data.locale,\r\n                    localeRegional: data.localeRegional,\r\n                    sessionId: data.sessionId\r\n                };\r\n\r\n                // update metaTags so sessionId is properly updated in telemetry\r\n                SmeWebTelemetry.updateFromRpcInit({ 'wac-session-id': data.sessionId, 'wac-extension-version': self.Environment.version });\r\n\r\n                return localeLoader\r\n                    .then(() => this.seekShell(RpcSeekMode.Create))\r\n                    .then(() => handler(passingData))\r\n                    .then(() => ({ version: rpcVersion }));\r\n            };\r\n            this.rpcManager.rpcInbound.register(RpcOutboundCommands[command], modifiedHandler);\r\n        } else {\r\n            this.rpcManager.rpcInbound.register(RpcOutboundCommands[command], handler);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Module report a failure.\r\n     */\r\n    public failed(data: any): Promise<void> {\r\n        const rpc = this.rpcManager.rpcInbound;\r\n        return rpc.failed(data);\r\n    }\r\n\r\n    /**\r\n     * Seek shell frame.\r\n     *\r\n     * @param Promise<any> the promise object.\r\n     */\r\n    public seekShell(mode: RpcSeekMode): Promise<RpcSeekResult> {\r\n        return this.rpcManager.seekShell(mode);\r\n    }\r\n\r\n    /**\r\n     * Validate existing outbound connection and remove if it doesn't live anymore.\r\n     *\r\n     * @return number the count of removed outbound.\r\n     */\r\n    public validate(): number {\r\n        let count = 0;\r\n        const collection = this.rpcManager.getCurrentRpcOutbound();\r\n        collection.forEach((rpc) => {\r\n            if (!this.rpcManager.rpcChannel.validate(rpc)) {\r\n                count++;\r\n            }\r\n        });\r\n\r\n        return count;\r\n    }\r\n\r\n    /**\r\n     * Change the active status of rpc.\r\n     */\r\n    public changeActiveState(state: boolean): void {\r\n        this.stateActiveInternal = state;\r\n        this.stateChangedInternal.next(state);\r\n    }\r\n\r\n    /**\r\n     * Create auto-failed timer promise.\r\n     *\r\n     * @param command the outbound command type.\r\n     * @param timeoutMs the timeout milliseconds.\r\n     * @param data the data context.\r\n     * @return Promise<any> the promise.\r\n     */\r\n    private createTimerPromise<TData, TResult>(command: RpcOutboundCommands, timeoutMs: number, data: TData): Promise<TResult> {\r\n        const deferred = NativeQ.defer<TResult>();\r\n        this.deferredCollection[command] = <DeferredData<TData, TResult>>{ deferred: deferred, data: data };\r\n        setTimeout(\r\n            () => {\r\n                const deferredData: DeferredData<TData, TResult> = this.deferredCollection[command];\r\n                if (deferredData) {\r\n                    const message = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcTimeout.message;\r\n                    deferredData.deferred.reject(message);\r\n                    delete this.deferredCollection[command];\r\n                }\r\n            },\r\n            timeoutMs);\r\n        return deferred.promise;\r\n    }\r\n\r\n    /**\r\n    * Create promise that does not timeout.\r\n    *\r\n    * @param command the outbound type.\r\n    * @param data the data context.\r\n    * @return Promise<any> the promise.\r\n    */\r\n    private createPromise<TData, TResult>(command: RpcOutboundCommands, data: TData): Promise<any> {\r\n        const deferred = NativeQ.defer<TResult>();\r\n        this.deferredCollection[command] = <DeferredData<TData, TResult>>{ deferred: deferred, data: data };\r\n        return deferred.promise;\r\n    }\r\n\r\n    /**\r\n     * Process data pushing into next call of subject with deferred data type.\r\n     *\r\n     * @param command the inbound command type.\r\n     * @param data the rpc data came from a module/iframe.\r\n     * @return Promise the promise which receiver must settle within fixed waiting time (10 seconds)\r\n     */\r\n    private processNextForSubject<TData, TResult>(command: RpcInboundCommands, data: TData): Promise<TResult> {\r\n        const subject = this.rpcSubjects[RpcInboundCommands[command]];\r\n        if (subject.closed) {\r\n            const message = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcSubjectClosed.message;\r\n            throw new Error(message.format(RpcInboundCommands[command]));\r\n        }\r\n\r\n        const deferredData = <DeferredData<TData, TResult>>{\r\n            data: data,\r\n            deferred: NativeQ.defer<TResult>()\r\n        };\r\n        subject.next(deferredData);\r\n        return deferredData.deferred.promise;\r\n    }\r\n}\r\n"]}