UNPKG

@itwin/core-common

Version:

iTwin.js components common to frontend and backend

198 lines • 9.5 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module RpcInterface */ Object.defineProperty(exports, "__esModule", { value: true }); exports.RpcRegistry = exports.CURRENT_INVOCATION = exports.CURRENT_REQUEST = exports.INSTANCE = exports.POLICY = exports.OPERATION = exports.REGISTRY = void 0; const core_bentley_1 = require("@itwin/core-bentley"); const IModelError_1 = require("../../IModelError"); const RpcConfiguration_1 = require("./RpcConfiguration"); const RpcPendingQueue_1 = require("./RpcPendingQueue"); const RpcRequest_1 = require("./RpcRequest"); const RpcRoutingToken_1 = require("./RpcRoutingToken"); const RpcInterface_1 = require("../../RpcInterface"); const RpcControl_1 = require("./RpcControl"); const RpcOperation_1 = require("./RpcOperation"); /** @internal */ exports.REGISTRY = Symbol.for("@itwin/core-common/RpcRegistry"); /** @internal */ exports.OPERATION = Symbol.for("@itwin/core-common/RpcOperation"); /** @internal */ exports.POLICY = Symbol.for("@itwin/core-common/RpcOperationPolicy"); /** @internal */ exports.INSTANCE = Symbol.for("@itwin/core-common/RpcInterface/__instance__"); /** @internal */ exports.CURRENT_REQUEST = Symbol.for("@itwin/core-common/RpcRequest/__current__"); /** @internal */ exports.CURRENT_INVOCATION = Symbol.for("@itwin/core-common/RpcInvocation/__current__"); /** @internal */ class RpcRegistry { static _instance; constructor() { } static get instance() { if (!RpcRegistry._instance) { const globalObj = typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}; if (!globalObj[exports.REGISTRY]) globalObj[exports.REGISTRY] = new RpcRegistry(); RpcRegistry._instance = globalObj[exports.REGISTRY]; } return RpcRegistry._instance; } lookupInterfaceDefinition(name) { if (!this.definitionClasses.has(name)) throw new IModelError_1.IModelError(core_bentley_1.BentleyStatus.ERROR, `RPC interface "${name}" is not initialized.`); return this.definitionClasses.get(name); } async describeAvailableEndpoints() { const requests = []; for (const channel of RpcControl_1.RpcControlChannel.channels) { requests.push(channel.describeEndpoints()); } const responses = await Promise.all(requests); const endpoints = responses.reduce((a, b) => a.concat(b), []); for (const endpoint of endpoints) { const definition = this.definitionClasses.get(endpoint.interfaceName); endpoint.compatible = (definition && RpcInterface_1.RpcInterface.isVersionCompatible(endpoint.interfaceVersion, definition.interfaceVersion)) ? true : false; } return endpoints; } getClientForInterface(definition, routing = RpcRoutingToken_1.RpcRoutingToken.default) { let instance; const proxies = this.proxies.get(definition.interfaceName); if (proxies) { instance = proxies.get(routing.id); } if (!instance) instance = this.instantiateClient(definition, routing); return instance; } getImplForInterface(definition) { let instance = this.implementations.get(definition.interfaceName); if (!instance) instance = this.instantiateImpl(definition); return instance; } lookupImpl(interfaceName) { const definition = this.lookupInterfaceDefinition(interfaceName); return this.getImplForInterface(definition); } registerImpl(definition, implementation) { this.unregisterImpl(definition); this.implementationClasses.set(definition.interfaceName, implementation); } unregisterImpl(definition) { this.implementationClasses.delete(definition.interfaceName); const impl = this.implementations.get(definition.interfaceName); if (impl) { impl.configuration.onRpcImplTerminated(definition, impl); this.implementations.delete(definition.interfaceName); } } supplyImplInstance(definition, instance) { this.suppliedImplementations.set(definition.interfaceName, instance); } isRpcInterfaceInitialized(definition) { return this.definitionClasses.has(definition.interfaceName); } initializeRpcInterface(definition) { if (this.definitionClasses.has(definition.interfaceName)) { const existing = this.definitionClasses.get(definition.interfaceName); if (existing && definition.interfaceVersion === "CONTROL" && existing !== definition) { this.configureOperations(definition); // configs that differ only by routing still need the control ops initialized } return; } this.notifyInitialize(); this.definitionClasses.set(definition.interfaceName, definition); this.configureOperations(definition); } terminateRpcInterface(definition) { this.unregisterImpl(definition); this.purgeClient(definition); this.definitionClasses.delete(definition.interfaceName); } definitionClasses = new Map(); proxies = new Map(); implementations = new Map(); suppliedImplementations = new Map(); implementationClasses = new Map(); id = (() => { let i = 0; return () => ++i; })(); instantiateImpl(definition) { this.checkInitialized(definition); const registeredImplementation = this.implementationClasses.get(definition.interfaceName); if (!registeredImplementation) throw new IModelError_1.IModelError(core_bentley_1.BentleyStatus.ERROR, `An RPC interface implementation class for "${definition.interfaceName}" is not registered.`); if (definition.prototype.configurationSupplier) registeredImplementation.prototype.configurationSupplier = definition.prototype.configurationSupplier; const supplied = this.suppliedImplementations.get(definition.interfaceName); const implementation = supplied || new registeredImplementation(); if (!(implementation instanceof registeredImplementation)) throw new IModelError_1.IModelError(core_bentley_1.BentleyStatus.ERROR, `Invalid RPC interface implementation.`); if (supplied) { supplied.configuration = RpcConfiguration_1.RpcConfiguration.supply(supplied); } this.implementations.set(definition.interfaceName, implementation); implementation.configuration.onRpcImplInitialized(definition, implementation); return implementation; } instantiateClient(definition, routing = RpcRoutingToken_1.RpcRoutingToken.default) { this.checkInitialized(definition); const proxy = new definition(routing); if (!this.proxies.has(definition.interfaceName)) { this.proxies.set(definition.interfaceName, new Map()); } this.proxies.get(definition.interfaceName)?.set(routing.id, proxy); Object.getOwnPropertyNames(definition.prototype).forEach((operationName) => { if (operationName === "constructor" || operationName === "configurationSupplier") return; this.interceptOperation(proxy, operationName); }); proxy.configuration.onRpcClientInitialized(definition, proxy); return proxy; } interceptOperation(proxy, operation) { const clientFunction = proxy[operation]; proxy[operation] = function () { const args = Array.from(arguments); args.push(operation); return clientFunction.apply(proxy, args); }; } checkInitialized(definition) { if (!this.definitionClasses.has(definition.interfaceName)) throw new IModelError_1.IModelError(core_bentley_1.BentleyStatus.ERROR, `RPC interface "${definition.interfaceName}" is not initialized.`); } configureOperations(definition) { const proto = definition.prototype; Object.getOwnPropertyNames(proto).forEach((operationName) => { if (operationName === "constructor" || operationName === "configurationSupplier") return; const propertyName = RpcOperation_1.RpcOperation.computeOperationName(operationName); if (!proto[propertyName][exports.OPERATION]) { const policy = definition[exports.POLICY] || new RpcOperation_1.RpcOperationPolicy(); proto[propertyName][exports.OPERATION] = new RpcOperation_1.RpcOperation(definition, propertyName, policy); } }); } purgeClient(definition) { const proxies = this.proxies.get(definition.interfaceName); if (proxies) { proxies.forEach((proxy) => proxy.configuration.onRpcClientTerminated(definition, proxy)); this.proxies.delete(definition.interfaceName); } } notifyInitialize() { (0, RpcRequest_1.initializeRpcRequest)(); RpcPendingQueue_1.RpcPendingQueue.initialize(); } } exports.RpcRegistry = RpcRegistry; //# sourceMappingURL=RpcRegistry.js.map