{"version":3,"sources":["../../../packages/core/rpc/rpc-manager.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,mBAAmB,EAGnB,kBAAkB,EAElB,mBAAmB,EAEtB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EAAW,WAAW,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE5E;;GAEG;AACH,oBAAY,cAAc;IACtB,MAAM,IAAA;IACN,QAAQ,IAAA;CACX;AAED;;GAEG;AACH,qBAAa,UAAU;IACnB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAK;IAEnB,UAAU,EAAE,UAAU,CAAC;IAC9B,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,mBAAmB,CAAsB;IACjD,OAAO,CAAC,iBAAiB,CAAa;IACtC,OAAO,CAAC,kBAAkB,CAAc;IACxC,OAAO,CAAC,gBAAgB,CAAa;IAErC;;OAEG;;IAoBH;;OAEG;IACH,IAAW,UAAU,IAAI,UAAU,CAElC;IAED;;OAEG;IACH,IAAW,WAAW,IAAI,WAAW,CAEpC;IAED;;OAEG;IACH,IAAW,oBAAoB,IAAI,UAAU,CAE5C;IAED;;;;;OAKG;IACI,IAAI,CAAC,eAAe,CAAC,EAAE,kBAAkB,EAAE,gBAAgB,CAAC,EAAE,mBAAmB,GAAG,IAAI;IAyB/F;;;;;OAKG;IACI,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAKlF;;OAEG;IACI,cAAc,IAAI,IAAI;IAS7B;;;;;;;;OAQG;IACI,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAqBxG;;;;;;;OAOG;IACI,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,WAAW;IAUzF;;OAEG;IACI,qBAAqB,IAAI,IAAI;IAIpC;;;;OAIG;IACI,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW;IASpE;;;OAGG;IACI,qBAAqB,IAAI,WAAW,EAAE;IAI7C;;;;;;;;OAQG;IACI,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,cAAc,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;IAmBtH;;;;OAIG;IACI,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC;IA8B3D;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;CAe5B","file":"rpc-manager.d.ts","sourcesContent":["import { Strings } from '../generated/strings';\r\nimport { EnvironmentModule } from '../manifest/environment-modules';\r\nimport { PerformanceProfile } from '../performance/performance-profile';\r\nimport {\r\n    CommandCallBackType,\r\n    RpcBase,\r\n    RpcInboundCommands,\r\n    RpcInboundHandlers,\r\n    RpcOutboundCommands,\r\n    RpcOutboundHandlers,\r\n    RpcType\r\n} from './rpc-base';\r\nimport { RpcChannel } from './rpc-channel';\r\nimport { RpcInbound } from './rpc-inbound';\r\nimport { RpcOutbound } from './rpc-outbound';\r\nimport { RpcSeekClient } from './seek/rpc-seek-client';\r\nimport { RpcSeek, RpcSeekMode, RpcSeekResult } from './seek/rpc-seek-model';\r\n\r\n/**\r\n * The status of RPC remote that sent the message\r\n */\r\nexport enum RpcRemoteState {\r\n    Active,\r\n    Inactive\r\n}\r\n\r\n/**\r\n * RpcManager class.\r\n */\r\nexport class RpcManager {\r\n    private static serial = 0;\r\n\r\n    public rpcChannel: RpcChannel;\r\n    private rpcInboundHandlers: RpcInboundHandlers;\r\n    private rpcOutboundHandlers: RpcOutboundHandlers;\r\n    private currentRpcInbound: RpcInbound;\r\n    private currentRpcOutbound: RpcOutbound;\r\n    private parentRpcInbound: RpcInbound;\r\n\r\n    /**\r\n     * Initializes a new instance of the RpcManager class.\r\n     */\r\n    constructor() {\r\n        const inboundHandlers: any = {};\r\n        const outboundHandlers: any = {};\r\n        const inboundCommands = Object.keys(RpcInboundCommands);\r\n        const outboundCommands = Object.keys(RpcOutboundCommands);\r\n\r\n        inboundCommands.forEach((command) => {\r\n            const handlerName = RpcBase.commandToHandlerName(command);\r\n            inboundHandlers[handlerName] = _ => Promise.resolve();\r\n        });\r\n        outboundCommands.forEach((command) => {\r\n            const handlerName = RpcBase.commandToHandlerName(command);\r\n            outboundHandlers[handlerName] = _ => Promise.resolve();\r\n        });\r\n\r\n        this.rpcInboundHandlers = inboundHandlers;\r\n        this.rpcOutboundHandlers = outboundHandlers;\r\n    }\r\n\r\n    /**\r\n     * Gets last rpc to-shell.\r\n     */\r\n    public get rpcInbound(): RpcInbound {\r\n        return this.currentRpcInbound;\r\n    }\r\n\r\n    /**\r\n     * Gets last rpc to-module.\r\n     */\r\n    public get rpcOutbound(): RpcOutbound {\r\n        return this.currentRpcOutbound;\r\n    }\r\n\r\n    /**\r\n     * Gets rpc inbound for report data.\r\n     */\r\n    public get rpcReportDataInbound(): RpcInbound {\r\n        return this.parentRpcInbound || this.currentRpcInbound;\r\n    }\r\n\r\n    /**\r\n     * Initialize the rpc communication channel based on manifest.\r\n     *\r\n     * @param inboundHandlers the set of rpc inbound handlers.\r\n     * @param outboundHandlers the set of rpc outbound handlers.\r\n     */\r\n    public init(inboundHandlers?: RpcInboundHandlers, outboundHandlers?: RpcOutboundHandlers): void {\r\n        // extend module and shell handlers\r\n        if (inboundHandlers) {\r\n            this.rpcInboundHandlers = Object.assign(this.rpcInboundHandlers, inboundHandlers);\r\n        }\r\n\r\n        if (outboundHandlers) {\r\n            this.rpcOutboundHandlers = Object.assign(this.rpcOutboundHandlers, outboundHandlers);\r\n        }\r\n\r\n        // read environment and create rpc self instance.\r\n        const global: any = window;\r\n        const { name, origin, signature } = global.MsftSme.Environment;\r\n        this.rpcChannel = new RpcChannel(name, origin, signature);\r\n        this.rpcChannel.subName = '##';\r\n        this.rpcChannel.rpcInboundHandlers = this.rpcInboundHandlers;\r\n\r\n        // for module configure shell access.\r\n        this.initRpcInbound();\r\n\r\n        // start rpc response.\r\n        this.rpcChannel.start();\r\n\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    }\r\n\r\n    /**\r\n     * Configure Rpc as parent frame.\r\n     */\r\n    public initRpcInbound(): void {\r\n        // accept initial ping query for any parent.\r\n        const rpcInbound = new RpcInbound(this.rpcChannel, '*', '*');\r\n        rpcInbound.subName = '*';\r\n        this.rpcChannel.registerRpc(rpcInbound, RpcType.Inbound);\r\n        this.currentRpcInbound = rpcInbound;\r\n        rpcInbound.registerAll(this.rpcOutboundHandlers);\r\n    }\r\n\r\n    /**\r\n     * Connect Rpc module.\r\n     *\r\n     * @param name the name of module.\r\n     * @param path the entry point to open for this module.\r\n     * @param iframe the iframe object.\r\n     * @param primary the primary iframe to support report data response.\r\n     * @return Promise<string> The promise with the sub name of outbound connection.\r\n     */\r\n    public connectRpcOutbound(name: string, path: string, iFrame: Window, primary: boolean): Promise<string> {\r\n        // making all instance to be unique at any order of connection.\r\n        const subName = '{0}#{1}+{2}'.format(path, Date.now(), RpcManager.serial++);\r\n        const rpcOutbound = this.createRpcOutbound(name, subName, iFrame);\r\n\r\n        rpcOutbound.registerAll(this.rpcInboundHandlers);\r\n\r\n        // pinging to establish connection to the module.\r\n        const start = Date.now();\r\n        return rpcOutbound.ping({ name: 'ping' }).then(_ => {\r\n            // regressed, moved after ping was succeeded.\r\n            // Primary check removed to support new connection functionality...\r\n            if (primary) {\r\n                this.currentRpcOutbound = rpcOutbound;\r\n            }\r\n\r\n            PerformanceProfile.logRouteNavigation('RpcManager', start, Date.now(), '[rpcPing]', name);\r\n            return subName;\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Reconnect Rpc module.\r\n     *\r\n     * @param name the name of module.\r\n     * @param subName the sub name.\r\n     * @param primary the primary iframe to support report data response.\r\n     * @return RpcOutbound the rpc outbound object.\r\n     */\r\n    public reconnectRpcOutbound(name: string, subName: string, primary: boolean): RpcOutbound {\r\n        const rpcOutbound = this.rpcChannel.getRpc<RpcOutbound>(name, subName, RpcType.Outbound);\r\n\r\n        if (primary) {\r\n            this.currentRpcOutbound = rpcOutbound;\r\n        }\r\n\r\n        return rpcOutbound;\r\n    }\r\n\r\n    /**\r\n     * Disconnect Rpc module.\r\n     */\r\n    public disconnectRpcOutbound(): void {\r\n        this.currentRpcOutbound = null;\r\n    }\r\n\r\n    /**\r\n     * Remove RpcOutbound.\r\n     *\r\n     * @param module the environment module to remove.\r\n     */\r\n    public removeRpcOutbound(name: string, subName: string): RpcOutbound {\r\n        const rpcOutbound = this.rpcChannel.unregisterRpc<RpcOutbound>(name, subName, RpcType.Outbound);\r\n        if (this.currentRpcOutbound === rpcOutbound) {\r\n            this.disconnectRpcOutbound();\r\n        }\r\n\r\n        return rpcOutbound;\r\n    }\r\n\r\n    /**\r\n     * Get current live outbound rpc.\r\n     *  - these set could be changed if it's handled async.\r\n     */\r\n    public getCurrentRpcOutbound(): RpcOutbound[] {\r\n        return this.rpcChannel.getAllRpc<RpcOutbound>(RpcType.Outbound);\r\n    }\r\n\r\n    /**\r\n     * Get the remote status of a given module name\r\n     *\r\n     * @param name The name of the RPC remote endpoint to get the status from\r\n     * @param subName The sub name of the remote iframe instance.\r\n     * @returns The state of the remote. Active if it's the current channel\r\n     * for communication or Inactive if the channel is not the currently active channel in this\r\n     * manager\r\n     */\r\n    public getSourceStatus(name: string, subName: string): { status: RpcRemoteState, subName: string, entryPoint: string } {\r\n        if (!this.currentRpcOutbound\r\n            || this.currentRpcOutbound.name !== name\r\n            || this.currentRpcOutbound.subName !== subName) {\r\n            return {\r\n                status: RpcRemoteState.Inactive,\r\n                subName: subName,\r\n                entryPoint: null\r\n            };\r\n        }\r\n\r\n        const segments = subName.split('#');\r\n        return {\r\n            status: RpcRemoteState.Active,\r\n            subName: subName,\r\n            entryPoint: segments && segments.length > 0 ? segments[0] : ''\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Seek shell or parent frame.\r\n     *\r\n     * @param Promise<any> the promise object.\r\n     */\r\n    public seekShell(mode: RpcSeekMode): Promise<RpcSeekResult> {\r\n        if (this.currentRpcInbound.name === EnvironmentModule.nameOfShell) {\r\n            return Promise.resolve<RpcSeekResult>({ name: this.currentRpcInbound.name, subName: this.currentRpcInbound.subName });\r\n        }\r\n\r\n        let depth = this.rpcChannel.depth;\r\n        let current = window.self as Window;\r\n        while (--depth >= 0 && current !== current.parent) {\r\n            current = current.parent;\r\n        }\r\n\r\n        const rpcInbound = new RpcInbound(this.rpcChannel, EnvironmentModule.nameOfShell, '*');\r\n        rpcInbound.window = current;\r\n        rpcInbound.subName = '##';\r\n        rpcInbound.depth = 0;\r\n        this.rpcChannel.registerRpc(rpcInbound, RpcType.Inbound);\r\n        rpcInbound.registerAll(this.rpcOutboundHandlers);\r\n        this.currentRpcInbound = rpcInbound;\r\n        return RpcSeekClient.seek(this, <RpcSeek>{ mode: mode }).then(\r\n            result => {\r\n                this.parentRpcInbound = this.currentRpcInbound;\r\n                this.currentRpcInbound = rpcInbound;\r\n                return result;\r\n            },\r\n            error => {\r\n                this.rpcChannel.unregisterRpc(rpcInbound.name, rpcInbound.subName, RpcType.Inbound);\r\n                return error;\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Create and add RpcOutbound object.\r\n     *\r\n     * @param name the name of module.\r\n     * @param subName the sub name.\r\n     * @param module the environment module to remove.\r\n     */\r\n    private createRpcOutbound(name: string, subName: string, iFrame: Window): RpcOutbound {\r\n        const global: MsftSme.SMEWindow = <any>window;\r\n        const { modules } = global.MsftSme.Environment;\r\n        const module = modules.find((value) => value.name === name);\r\n        if (!module) {\r\n            const message = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcFailedFindModuleManifest.message;\r\n            throw new Error(message.format(name));\r\n        }\r\n\r\n        const rpc = new RpcOutbound(this.rpcChannel, module.name, module.origin);\r\n        rpc.subName = subName;\r\n        rpc.window = iFrame;\r\n        this.rpcChannel.registerRpc(rpc, RpcType.Outbound);\r\n        return rpc;\r\n    }\r\n}\r\n"]}