UNPKG

@itwin/presentation-backend

Version:

Backend of iTwin.js Presentation library

151 lines 7.66 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 Core */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Presentation = void 0; const core_backend_1 = require("@itwin/core-backend"); const core_bentley_1 = require("@itwin/core-bentley"); const core_common_1 = require("@itwin/core-common"); const presentation_common_1 = require("@itwin/presentation-common"); const BackendLoggerCategory_js_1 = require("./BackendLoggerCategory.js"); const PresentationIpcHandler_js_1 = require("./PresentationIpcHandler.js"); const PresentationManager_js_1 = require("./PresentationManager.js"); const PresentationRpcImpl_js_1 = require("./PresentationRpcImpl.js"); const TemporaryStorage_js_1 = require("./TemporaryStorage.js"); const InternalSymbols_js_1 = require("./InternalSymbols.js"); /** * Static class used to statically set up Presentation library for the backend. * Basically what it does is: * - Register a RPC implementation * - Create a singleton [[PresentationManager]] instance * - Subscribe for [IModelHost.onBeforeShutdown]($core-backend) event and terminate * the presentation manager when that happens. * * @public */ class Presentation { static _initProps; static _clientsStorage; static _disposeIpcHandler; static _shutdownListener; static _disposeIModelOpenedListener; static _rpcImpl; /* c8 ignore next */ constructor() { } /** Properties used to initialize the presentation framework */ static get initProps() { return this._initProps; } /** * Initializes Presentation library for the backend. * * See [Setting up iTwin.js Presentation library documentation page]($docs/presentation/setup/index.md#backend) for an example. * * **Important:** The method should be called after a call to [IModelHost.startup]($core-backend) * * @param props Optional properties for [[PresentationManager]] */ static initialize(props) { this._initProps = props || {}; this._shutdownListener = core_backend_1.IModelHost.onBeforeShutdown.addListener(() => Presentation.terminate()); this._rpcImpl = new PresentationRpcImpl_js_1.PresentationRpcImpl({ requestTimeout: this._initProps.requestTimeout, }); core_common_1.RpcManager.registerImpl(presentation_common_1.PresentationRpcInterface, PresentationRpcImpl_js_1.PresentationRpcImpl); core_common_1.RpcManager.supplyImplInstance(presentation_common_1.PresentationRpcInterface, this._rpcImpl); if (core_backend_1.IpcHost.isValid) { this._disposeIpcHandler = PresentationIpcHandler_js_1.PresentationIpcHandler.register(); } this._clientsStorage = new TemporaryStorage_js_1.FactoryBasedTemporaryStorage({ factory: this.createClientManager.bind(this), cleanupHandler: (_id, storeItem) => this.disposeClientManager(_id, storeItem), // cleanup unused managers every minute cleanupInterval: 60 * 1000, // by default, manager is disposed after 1 hour of being unused unusedValueLifetime: this._initProps.unusedClientLifetime ?? 60 * 60 * 1000, // add some logging /* c8 ignore next 5 */ onDisposedSingle: (id) => core_bentley_1.Logger.logInfo(BackendLoggerCategory_js_1.PresentationBackendLoggerCategory.PresentationManager, `Disposed PresentationManager instance with ID: ${id}. Total instances: ${this._clientsStorage.values.length}.`), /* c8 ignore next */ onDisposedAll: () => core_bentley_1.Logger.logInfo(BackendLoggerCategory_js_1.PresentationBackendLoggerCategory.PresentationManager, `Disposed all PresentationManager instances.`), }); if (this._initProps.enableSchemasPreload) { this._disposeIModelOpenedListener = core_backend_1.BriefcaseDb.onOpened.addListener(this.onIModelOpened); } } /** * Terminates Presentation. Consumers don't need to call this as it's automatically * called on [IModelHost.onBeforeShutdown]($core-backend) event. */ static terminate() { if (this._clientsStorage) { this._clientsStorage[Symbol.dispose](); this._clientsStorage = undefined; } if (this._disposeIModelOpenedListener) { this._disposeIModelOpenedListener(); this._disposeIModelOpenedListener = undefined; } if (this._shutdownListener) { this._shutdownListener(); this._shutdownListener = undefined; } core_common_1.RpcManager.unregisterImpl(presentation_common_1.PresentationRpcInterface); if (this._rpcImpl) { this._rpcImpl[Symbol.dispose](); this._rpcImpl = undefined; } if (this._disposeIpcHandler) { this._disposeIpcHandler(); } this._initProps = undefined; } static createClientManager(clientId, onManagerUsed) { const manager = Presentation._initProps && Presentation._initProps.clientManagerFactory ? Presentation._initProps.clientManagerFactory(clientId, Presentation._initProps) : new PresentationManager_js_1.PresentationManager({ ...Presentation._initProps, // @ts-expect-error internal prop id: clientId, }); manager.onUsed.addListener(onManagerUsed); core_bentley_1.Logger.logInfo(BackendLoggerCategory_js_1.PresentationBackendLoggerCategory.PresentationManager, `Created a PresentationManager instance with ID: ${clientId}. Total instances: ${this._clientsStorage.values.length}.`); return { manager }; } static disposeClientManager(_id, storeItem) { storeItem.manager[Symbol.dispose](); } /** * Get an instance of [[PresentationManager]] for specific client * @param clientId ID of the client requesting presentation data. If no * ID is provided, the default [[PresentationManager]] is returned. */ static getManager(clientId) { if (this._clientsStorage) { return this._clientsStorage.getValue(clientId || "").manager; } throw new presentation_common_1.PresentationError(presentation_common_1.PresentationStatus.NotInitialized, "Presentation must be first initialized by calling Presentation.initialize"); } /** * Get the time in milliseconds that backend should respond in . */ static getRequestTimeout() { if (this._rpcImpl === undefined) { throw new presentation_common_1.PresentationError(presentation_common_1.PresentationStatus.NotInitialized, "Presentation must be first initialized by calling Presentation.initialize"); } return this._rpcImpl.requestTimeout; } static onIModelOpened = (imodel) => { const manager = this.getManager(); const imodelAddon = manager[InternalSymbols_js_1._presentation_manager_detail].getNativePlatform().getImodelAddon(imodel); // eslint-disable-next-line @typescript-eslint/no-floating-promises manager[InternalSymbols_js_1._presentation_manager_detail].getNativePlatform().forceLoadSchemas(imodelAddon); }; } exports.Presentation = Presentation; //# sourceMappingURL=Presentation.js.map