UNPKG

@itwin/core-backend

Version:
198 lines • 9.17 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.IModelTileRpcImpl = void 0; exports.cancelTileContentRequests = cancelTileContentRequests; const core_bentley_1 = require("@itwin/core-bentley"); const core_common_1 = require("@itwin/core-common"); const BackendLoggerCategory_1 = require("../BackendLoggerCategory"); const IModelDb_1 = require("../IModelDb"); const IModelHost_1 = require("../IModelHost"); const PromiseMemoizer_1 = require("../PromiseMemoizer"); const tracing_1 = require("../rpc/tracing"); const RpcBriefcaseUtility_1 = require("./RpcBriefcaseUtility"); const NativePlatform_1 = require("../internal/NativePlatform"); const Symbols_1 = require("../internal/Symbols"); function generateTileRequestKey(props) { const token = props.tokenProps; return `${JSON.stringify({ key: token.key, iTwinId: token.iTwinId, iModelId: token.iModelId, changesetId: token.changeset?.id, })}:${props.treeId}`; } class TileRequestMemoizer extends PromiseMemoizer_1.PromiseMemoizer { _loggerCategory = BackendLoggerCategory_1.BackendLoggerCategory.IModelTileRequestRpc; makeMetadata(props) { const meta = { ...props.tokenProps }; this.addMetadata(meta, props); return meta; } constructor(memoizeFn, generateKeyFn) { super(memoizeFn, generateKeyFn); } memoize(props) { return super.memoize(props); } deleteMemoized(props) { super.deleteMemoized(props); } log(status, props) { const descr = `${this._operationName}(${this.stringify(props)})`; core_bentley_1.Logger.logTrace(this._loggerCategory, `Backend ${status} ${descr}`, () => this.makeMetadata(props)); } async perform(props) { this.log("received", props); const tileQP = this.memoize(props); await core_bentley_1.BeDuration.race(this._timeoutMilliseconds, tileQP.promise).catch(() => { }); // Note: Rejections must be caught so that the memoization entry can be deleted if (tileQP.isPending) { this.log("issuing pending status for", props); throw new core_common_1.RpcPendingResponse(); // eslint-disable-line @typescript-eslint/only-throw-error } this.deleteMemoized(props); if (tileQP.isFulfilled) { this.log("completed", props); (0, core_bentley_1.assert)(undefined !== tileQP.result); return tileQP.result; } (0, core_bentley_1.assert)(tileQP.isRejected); this.log("rejected", props); throw tileQP.error; } } async function getTileTreeProps(props) { (0, core_bentley_1.assert)(undefined !== props.accessToken); const db = await RpcBriefcaseUtility_1.RpcBriefcaseUtility.findOpenIModel(props.accessToken, props.tokenProps); return db.tiles.requestTileTreeProps(props.treeId); } class RequestTileTreePropsMemoizer extends TileRequestMemoizer { get _timeoutMilliseconds() { return IModelHost_1.IModelHost.tileTreeRequestTimeout; } get _operationName() { return "requestTileTreeProps"; } stringify(props) { return props.treeId; } addMetadata(meta, props) { meta.treeId = props.treeId; } static _instance; constructor() { super(getTileTreeProps, generateTileRequestKey); IModelHost_1.IModelHost.onBeforeShutdown.addOnce(() => { this[Symbol.dispose](); RequestTileTreePropsMemoizer._instance = undefined; }); } static async perform(props) { if (undefined === this._instance) this._instance = new RequestTileTreePropsMemoizer(); return this._instance.perform(props); } } async function getTileContent(props) { (0, core_bentley_1.assert)(undefined !== props.accessToken); const db = await RpcBriefcaseUtility_1.RpcBriefcaseUtility.findOpenIModel(props.accessToken, props.tokenProps); const tile = await db.tiles.requestTileContent(props.treeId, props.contentId); // ###TODO: Verify the guid supplied by the front-end matches the guid stored in the model? if (IModelHost_1.IModelHost.usingExternalTileCache) { const tileMetadata = { backendName: IModelHost_1.IModelHost.applicationId, tileGenerationTime: tile.elapsedSeconds.toString(), tileSize: tile.content.byteLength.toString(), }; await IModelHost_1.IModelHost.tileStorage?.uploadTile(props.tokenProps.iModelId ?? db.iModelId, props.tokenProps.changeset?.id ?? db.changeset.id, props.treeId, props.contentId, tile.content, props.guid, tileMetadata); const { accessToken: _, ...safeProps } = props; core_bentley_1.Logger.logInfo(BackendLoggerCategory_1.BackendLoggerCategory.IModelTileRequestRpc, "Generated and uploaded tile", { tileMetadata, ...safeProps }); return core_common_1.TileContentSource.ExternalCache; } return core_common_1.TileContentSource.Backend; } function generateTileContentKey(props) { return `${generateTileRequestKey(props)}:${props.contentId}`; } class RequestTileContentMemoizer extends TileRequestMemoizer { get _timeoutMilliseconds() { return IModelHost_1.IModelHost.tileContentRequestTimeout; } get _operationName() { return "requestTileContent"; } stringify(props) { return `${props.treeId}:${props.contentId}`; } addMetadata(meta, props) { meta.treeId = props.treeId; meta.contentId = props.contentId; } static _instance; constructor() { super(getTileContent, generateTileContentKey); IModelHost_1.IModelHost.onBeforeShutdown.addOnce(() => { this[Symbol.dispose](); RequestTileContentMemoizer._instance = undefined; }); } static get instance() { if (undefined === this._instance) this._instance = new RequestTileContentMemoizer(); return this._instance; } static async perform(props) { return this.instance.perform(props); } } function currentActivity() { return tracing_1.RpcTrace.expectCurrentActivity; } /** @internal */ class IModelTileRpcImpl extends core_common_1.RpcInterface { static register() { core_common_1.RpcManager.registerImpl(core_common_1.IModelTileRpcInterface, IModelTileRpcImpl); } async requestTileTreeProps(tokenProps, treeId) { return RequestTileTreePropsMemoizer.perform({ accessToken: currentActivity().accessToken, tokenProps, treeId }); } async purgeTileTrees(tokenProps, modelIds) { // `undefined` gets forwarded as `null`... if (null === modelIds) modelIds = undefined; const db = await RpcBriefcaseUtility_1.RpcBriefcaseUtility.findOpenIModel(currentActivity().accessToken, tokenProps); if (!db.isOpen) { return; } return db[Symbols_1._nativeDb].purgeTileTrees(modelIds); } async generateTileContent(tokenProps, treeId, contentId, guid) { return RequestTileContentMemoizer.perform({ accessToken: currentActivity().accessToken, tokenProps, treeId, contentId, guid }); } async retrieveTileContent(tokenProps, key) { const db = await RpcBriefcaseUtility_1.RpcBriefcaseUtility.findOpenIModel(currentActivity().accessToken, tokenProps); return db.tiles.getTileContent(key.treeId, key.contentId); } async getTileCacheConfig(tokenProps) { if (IModelHost_1.IModelHost.tileStorage === undefined) return undefined; const iModelId = tokenProps.iModelId ?? (await RpcBriefcaseUtility_1.RpcBriefcaseUtility.findOpenIModel(currentActivity().accessToken, tokenProps)).iModelId; return IModelHost_1.IModelHost.tileStorage.getDownloadConfig(iModelId); } async queryVersionInfo() { return NativePlatform_1.IModelNative.platform.getTileVersionInfo(); } /** @internal */ async requestElementGraphics(rpcProps, request) { const iModel = await RpcBriefcaseUtility_1.RpcBriefcaseUtility.findOpenIModel(currentActivity().accessToken, rpcProps); return iModel.generateElementGraphics(request); } } exports.IModelTileRpcImpl = IModelTileRpcImpl; /** @internal */ async function cancelTileContentRequests(tokenProps, contentIds) { const iModel = IModelDb_1.IModelDb.findByKey(tokenProps.key); const props = { tokenProps, treeId: "", contentId: "" }; for (const entry of contentIds) { props.treeId = entry.treeId; for (const contentId of entry.contentIds) { props.contentId = contentId; RequestTileContentMemoizer.instance.deleteMemoized(props); } iModel[Symbols_1._nativeDb].cancelTileContentRequests(entry.treeId, entry.contentIds); } } //# sourceMappingURL=IModelTileRpcImpl.js.map