UNPKG

@itwin/core-frontend

Version:
173 lines 7.07 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module Tiles */ import { IpcApp } from "../IpcApp"; import { IModelTileRequestChannels, TileRequestChannel, TileRequestChannelStatistics, } from "./internal"; /** For an [[IpcApp]], allows backend element graphics requests in progress to be canceled. */ class ElementGraphicsChannel extends TileRequestChannel { _canceled = new Map(); onActiveRequestCanceled(request) { const imodel = request.tile.tree.iModel; let ids = this._canceled.get(imodel); if (!ids) this._canceled.set(imodel, ids = []); ids.push(request.tile.contentId); } processCancellations() { for (const [imodel, requestIds] of this._canceled) { // eslint-disable-next-line @typescript-eslint/no-floating-promises IpcApp.appFunctionIpc.cancelElementGraphicsRequests(imodel.key, requestIds); this._statistics.totalAbortedRequests += requestIds.length; } this._canceled.clear(); } onIModelClosed(imodel) { this._canceled.delete(imodel); } } /** A set of named [[TileRequestChannel]]s via which content for [[Tile]]s can be requested. * @see [[TileAdmin.channels]] for the channels configured for use with the iTwin.js display system. * @see [[TileRequestChannels.getForHttp]] for the most typical way of obtaining or registering a channel. * @public * @extensions */ export class TileRequestChannels { /** @internal */ iModelChannels; /** The channel over which [[TileAdmin.requestElementGraphics]] executes. If you implement a [[TiledGraphicsProvider]] or [[TileTree]] that obtains its * content from `requestElementGraphics`, use this channel. */ elementGraphicsRpc; /** The maximum number of active requests for a channel that uses HTTP to request content. */ httpConcurrency = 6; _rpcConcurrency; _channels = new Map(); /** `rpcConcurrency` is defined if [[IpcApp.isValid]]; otherwise RPC requests are made over HTTP and use the same limits. * @internal */ constructor(rpcConcurrency, cacheMetadata) { this._rpcConcurrency = rpcConcurrency ?? this.httpConcurrency; const elementGraphicsChannelName = "itwinjs-elem-rpc"; if (undefined !== rpcConcurrency) this.elementGraphicsRpc = new ElementGraphicsChannel(elementGraphicsChannelName, rpcConcurrency); else this.elementGraphicsRpc = new TileRequestChannel(elementGraphicsChannelName, this.rpcConcurrency); this.add(this.elementGraphicsRpc); this.iModelChannels = new IModelTileRequestChannels({ concurrency: this.rpcConcurrency, usesHttp: undefined === rpcConcurrency, cacheMetadata, cacheConcurrency: this.httpConcurrency, }); for (const channel of this.iModelChannels) this.add(channel); } /** The number of registered channels. */ get size() { return this._channels.size; } /** Look up a registered channel by its name. */ get(name) { return this._channels.get(name); } /** Return whether the specified channel has been registered. Primarily for debugging. */ has(channel) { const existing = this.get(channel.name); return existing !== undefined && existing === channel; } /** Add a new channel. * @throws Error if a channel by the same name has already been registered. */ add(channel) { if (this.get(channel.name)) throw new Error(`Tile request channel ${channel.name} is already registered.`); this._channels.set(channel.name, channel); } /** Extract the host name from a URL for use as the name of the corresponding [[TileRequestChannel]]. * @throws TypeError if `url` is a string and does not represent a valid URL. * @see [[getForHttp]] to obtain or register a channel for the host name. */ static getNameFromUrl(url) { if (typeof url === "string") url = new URL(url); return url.hostname; } /** Obtain a channel that requests content over HTTP using HTTP 1.1 limits on simultaneous connections. * If a channel with the specified name does not already exist, it will be created and registered. * @see [[getNameFromUrl]] to obtain a channel name corresponding to a hostname. */ getForHttp(name) { let channel = this.get(name); if (!channel) this.add(channel = new TileRequestChannel(name, this.httpConcurrency)); return channel; } /** Iterator over all of the channels. */ [Symbol.iterator]() { return this._channels.values()[Symbol.iterator](); } /** The maximum number of active requests for a channel that uses an RpcInterface to satisfy its requests. * For web-based applications, this is the same as [[httpConcurrency]], but for [[IpcApp]]s it is determined by the number of workers threads allocated by the backend. */ get rpcConcurrency() { return this._rpcConcurrency; } /** @internal */ getIModelTileChannel(tile) { return this.iModelChannels.getChannelForTile(tile); } /** Chiefly for debugging. * @internal */ setRpcConcurrency(concurrency) { this._rpcConcurrency = concurrency; this.iModelChannels.setRpcConcurrency(concurrency); this.elementGraphicsRpc.concurrency = concurrency; } /** Statistics intended primarily for debugging. */ get statistics() { const stats = new TileRequestChannelStatistics(); for (const channel of this) channel.statistics.addTo(stats); return stats; } /** Reset all [[statistics]] to zero. */ resetStatistics() { for (const channel of this) channel.resetStatistics(); } /** Invoked by [[TileAdmin.processQueue]] when it is about to start enqueuing new requests. * @internal */ swapPending() { for (const channel of this) channel.swapPending(); } /** Invoked by [[TileAdmin.processQueue]] when it is about to start enqueuing new requests. * @internal */ process() { for (const channel of this) channel.process(); } /** Invoked by [[TileAdmin.onIModelClosed]]. * @internal */ onIModelClosed(iModel) { for (const channel of this) channel.onIModelClosed(iModel); } /** Invoked by [[TileAdmin.onShutDown]]. * @internal */ onShutDown() { for (const channel of this) channel.cancelAndClearAll(); this._channels.clear(); } } //# sourceMappingURL=TileRequestChannels.js.map