UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

256 lines (254 loc) 9.46 kB
import { EnvironmentModule } from '../manifest/environment-modules'; import { PerformanceProfile } from '../performance/performance-profile'; import { RpcBase, RpcInboundCommands, RpcOutboundCommands, RpcType } from './rpc-base'; import { RpcChannel } from './rpc-channel'; import { RpcInbound } from './rpc-inbound'; import { RpcOutbound } from './rpc-outbound'; import { RpcSeekClient } from './seek/rpc-seek-client'; /** * The status of RPC remote that sent the message */ export var RpcRemoteState; (function (RpcRemoteState) { RpcRemoteState[RpcRemoteState["Active"] = 0] = "Active"; RpcRemoteState[RpcRemoteState["Inactive"] = 1] = "Inactive"; })(RpcRemoteState || (RpcRemoteState = {})); /** * RpcManager class. */ export class RpcManager { static serial = 0; rpcChannel; rpcInboundHandlers; rpcOutboundHandlers; currentRpcInbound; currentRpcOutbound; parentRpcInbound; /** * Initializes a new instance of the RpcManager class. */ constructor() { const inboundHandlers = {}; const outboundHandlers = {}; const inboundCommands = Object.keys(RpcInboundCommands); const outboundCommands = Object.keys(RpcOutboundCommands); inboundCommands.forEach((command) => { const handlerName = RpcBase.commandToHandlerName(command); inboundHandlers[handlerName] = _ => Promise.resolve(); }); outboundCommands.forEach((command) => { const handlerName = RpcBase.commandToHandlerName(command); outboundHandlers[handlerName] = _ => Promise.resolve(); }); this.rpcInboundHandlers = inboundHandlers; this.rpcOutboundHandlers = outboundHandlers; } /** * Gets last rpc to-shell. */ get rpcInbound() { return this.currentRpcInbound; } /** * Gets last rpc to-module. */ get rpcOutbound() { return this.currentRpcOutbound; } /** * Gets rpc inbound for report data. */ get rpcReportDataInbound() { return this.parentRpcInbound || this.currentRpcInbound; } /** * Initialize the rpc communication channel based on manifest. * * @param inboundHandlers the set of rpc inbound handlers. * @param outboundHandlers the set of rpc outbound handlers. */ init(inboundHandlers, outboundHandlers) { // extend module and shell handlers if (inboundHandlers) { this.rpcInboundHandlers = Object.assign(this.rpcInboundHandlers, inboundHandlers); } if (outboundHandlers) { this.rpcOutboundHandlers = Object.assign(this.rpcOutboundHandlers, outboundHandlers); } // read environment and create rpc self instance. const global = window; const { name, origin, signature } = global.MsftSme.Environment; this.rpcChannel = new RpcChannel(name, origin, signature); this.rpcChannel.subName = '##'; this.rpcChannel.rpcInboundHandlers = this.rpcInboundHandlers; // for module configure shell access. this.initRpcInbound(); // start rpc response. this.rpcChannel.start(); } /** * Register inbound command handler. * * @param command The command name. * @param handler The command handler. */ registerInboundHandler(command, handler) { const handlerName = RpcBase.commandToHandlerName(command); this.rpcInboundHandlers[handlerName] = handler; } /** * Configure Rpc as parent frame. */ initRpcInbound() { // accept initial ping query for any parent. const rpcInbound = new RpcInbound(this.rpcChannel, '*', '*'); rpcInbound.subName = '*'; this.rpcChannel.registerRpc(rpcInbound, RpcType.Inbound); this.currentRpcInbound = rpcInbound; rpcInbound.registerAll(this.rpcOutboundHandlers); } /** * Connect Rpc module. * * @param name the name of module. * @param path the entry point to open for this module. * @param iframe the iframe object. * @param primary the primary iframe to support report data response. * @return Promise<string> The promise with the sub name of outbound connection. */ connectRpcOutbound(name, path, iFrame, primary) { // making all instance to be unique at any order of connection. const subName = '{0}#{1}+{2}'.format(path, Date.now(), RpcManager.serial++); const rpcOutbound = this.createRpcOutbound(name, subName, iFrame); rpcOutbound.registerAll(this.rpcInboundHandlers); // pinging to establish connection to the module. const start = Date.now(); return rpcOutbound.ping({ name: 'ping' }).then(_ => { // regressed, moved after ping was succeeded. // Primary check removed to support new connection functionality... if (primary) { this.currentRpcOutbound = rpcOutbound; } PerformanceProfile.logRouteNavigation('RpcManager', start, Date.now(), '[rpcPing]', name); return subName; }); } /** * Reconnect Rpc module. * * @param name the name of module. * @param subName the sub name. * @param primary the primary iframe to support report data response. * @return RpcOutbound the rpc outbound object. */ reconnectRpcOutbound(name, subName, primary) { const rpcOutbound = this.rpcChannel.getRpc(name, subName, RpcType.Outbound); if (primary) { this.currentRpcOutbound = rpcOutbound; } return rpcOutbound; } /** * Disconnect Rpc module. */ disconnectRpcOutbound() { this.currentRpcOutbound = null; } /** * Remove RpcOutbound. * * @param module the environment module to remove. */ removeRpcOutbound(name, subName) { const rpcOutbound = this.rpcChannel.unregisterRpc(name, subName, RpcType.Outbound); if (this.currentRpcOutbound === rpcOutbound) { this.disconnectRpcOutbound(); } return rpcOutbound; } /** * Get current live outbound rpc. * - these set could be changed if it's handled async. */ getCurrentRpcOutbound() { return this.rpcChannel.getAllRpc(RpcType.Outbound); } /** * Get the remote status of a given module name * * @param name The name of the RPC remote endpoint to get the status from * @param subName The sub name of the remote iframe instance. * @returns The state of the remote. Active if it's the current channel * for communication or Inactive if the channel is not the currently active channel in this * manager */ getSourceStatus(name, subName) { if (!this.currentRpcOutbound || this.currentRpcOutbound.name !== name || this.currentRpcOutbound.subName !== subName) { return { status: RpcRemoteState.Inactive, subName: subName, entryPoint: null }; } const segments = subName.split('#'); return { status: RpcRemoteState.Active, subName: subName, entryPoint: segments && segments.length > 0 ? segments[0] : '' }; } /** * Seek shell or parent frame. * * @param Promise<any> the promise object. */ seekShell(mode) { if (this.currentRpcInbound.name === EnvironmentModule.nameOfShell) { return Promise.resolve({ name: this.currentRpcInbound.name, subName: this.currentRpcInbound.subName }); } let depth = this.rpcChannel.depth; let current = window.self; while (--depth >= 0 && current !== current.parent) { current = current.parent; } const rpcInbound = new RpcInbound(this.rpcChannel, EnvironmentModule.nameOfShell, '*'); rpcInbound.window = current; rpcInbound.subName = '##'; rpcInbound.depth = 0; this.rpcChannel.registerRpc(rpcInbound, RpcType.Inbound); rpcInbound.registerAll(this.rpcOutboundHandlers); this.currentRpcInbound = rpcInbound; return RpcSeekClient.seek(this, { mode: mode }).then(result => { this.parentRpcInbound = this.currentRpcInbound; this.currentRpcInbound = rpcInbound; return result; }, error => { this.rpcChannel.unregisterRpc(rpcInbound.name, rpcInbound.subName, RpcType.Inbound); return error; }); } /** * Create and add RpcOutbound object. * * @param name the name of module. * @param subName the sub name. * @param module the environment module to remove. */ createRpcOutbound(name, subName, iFrame) { const global = window; const { modules } = global.MsftSme.Environment; const module = modules.find((value) => value.name === name); if (!module) { const message = MsftSme.getStrings().MsftSmeShell.Core.Error.RpcFailedFindModuleManifest.message; throw new Error(message.format(name)); } const rpc = new RpcOutbound(this.rpcChannel, module.name, module.origin); rpc.subName = subName; rpc.window = iFrame; this.rpcChannel.registerRpc(rpc, RpcType.Outbound); return rpc; } } //# sourceMappingURL=rpc-manager.js.map