packageDocumentation module import { AccessToken , GuidString , Logger } from "@itwin/core-bentley" ; import { request , RequestOptions } from "../itwin-client/Request" ; import { ECJsonTypeMap , WsgInstance } from "../wsg/ECJsonTypeMap" ; import { Base64 } from "js-base64" ; import { IModelHubClientLoggerCategory } from "../IModelHubClientLoggerCategories" ; import { IModelBaseHandler } from "./BaseHandler" ; import { ArgumentCheck } from "./Errors" ; import { InstanceIdQuery } from "./HubQuery" ; const loggerCategory = IModelHubClientLoggerCategory . IModelHub ; public export type ThumbnailSize = "Small" | "Large" ; internal export abstract class Thumbnail extends WsgInstance { @ ECJsonTypeMap . propertyToJson ( "wsg" , "instanceId" ) public id ? : GuidString ; } internal @ ECJsonTypeMap . classToJson ( "wsg" , "iModelScope.SmallThumbnail" , { schemaPropertyName : "schemaName" , classPropertyName : "className" } ) export class SmallThumbnail extends Thumbnail { } internal @ ECJsonTypeMap . classToJson ( "wsg" , "iModelScope.LargeThumbnail" , { schemaPropertyName : "schemaName" , classPropertyName : "className" } ) export class LargeThumbnail extends Thumbnail { } public export interface TipThumbnail { /** Id of the iModel's parent iTwin. */ iTwinId : string ; /** Size of the [[Thumbnail]]. */ size : ThumbnailSize ; } internal export class ThumbnailQuery extends InstanceIdQuery { param versionId returns throws internal deprecated public byVersionId ( versionId ) { ArgumentCheck . validGuid ( "versionId" , versionId ) ; this . addFilter ( `HasThumbnail-backward-Version.Id+eq+'${ versionId }'` ) ; return this ; } } internal export class ThumbnailHandler { private _handler : IModelBaseHandler ; param handler internal constructor ( handler ) { this . _handler = handler ; } param iTwinId param iModelId param size private getRelativeContextUrl ( iTwinId , iModelId , size ) { return `/Repositories/Context--${ this . _handler . formatITwinIdForUrl ( iTwinId ) }/ContextScope/${ size }Thumbnail/${ iModelId . toString ( ) }/$file` ; } param iModelId param size param thumbnailId private getRelativeUrl ( iModelId , size , thumbnailId ? ) { return `/Repositories/iModel--${ iModelId }/iModelScope/${ size }Thumbnail/${ thumbnailId || "" }` ; } param thumbnail private isTipThumbnail ( thumbnail ) { return ( thumbnail as TipThumbnail ) . iTwinId !== undefined ; } param url return private async downloadThumbnail ( accessToken , url ) { const options = { method : "GET" , headers : { authorization : accessToken } , responseType : "arraybuffer" , agent : this . _handler . getAgent ( ) } ; const response = await request ( url , options ) ; const byteArray = new Uint8Array ( response . body ) ; if ( ! byteArray || byteArray . length === 0 ) { throw new Error ( "Expected an image to be returned from the query" ) ; } const base64Data = Base64 . btoa ( byteArray . reduce ( ( acc , byte ) => acc + String . fromCharCode ( byte ) , "" ) ) ; return `data:image/png;base64,${ base64Data }` ; } param iTwinId param iModelId param size return private async downloadTipThumbnail ( accessToken , iTwinId , iModelId , size ) { Logger . logInfo ( loggerCategory , `Downloading tip ${ size }Thumbnail` , ( ) => ( { iModelId } ) ) ; ArgumentCheck . validGuid ( "iTwinId" , iTwinId ) ; ArgumentCheck . validGuid ( "iModelId" , iModelId ) ; const url = await this . _handler . getUrl ( ) + this . getRelativeContextUrl ( iTwinId , iModelId , size ) ; const pngImage = await this . downloadThumbnail ( accessToken , url ) ; Logger . logTrace ( loggerCategory , `Downloaded tip ${ size }Thumbnail` , ( ) => ( { iModelId } ) ) ; return pngImage ; } param iModelId param size param query return throws public async get ( accessToken , iModelId , size , query = new ThumbnailQuery ( ) ) { Logger . logInfo ( loggerCategory , "Querying iModel thumbnails" , ( ) => ( { iModelId } ) ) ; ArgumentCheck . validGuid ( "iModelId" , iModelId ) ; let thumbnails = [ ] ; if ( size === "Small" ) thumbnails = await this . _handler . getInstances < SmallThumbnail > ( accessToken , SmallThumbnail , this . getRelativeUrl ( iModelId , size , query . getId ( ) ) , query . getQueryOptions ( ) ) ; else thumbnails = await this . _handler . getInstances < LargeThumbnail > ( accessToken , LargeThumbnail , this . getRelativeUrl ( iModelId , size , query . getId ( ) ) , query . getQueryOptions ( ) ) ; Logger . logTrace ( loggerCategory , "Queried iModel thumbnails" , ( ) => ( { iModelId } ) ) ; return thumbnails ; } param iModelId param thumbnail return throws throws throws public async download ( accessToken , iModelId , thumbnail ) { ArgumentCheck . validGuid ( "iModelId" , iModelId ) ; if ( this . isTipThumbnail ( thumbnail ) ) { return this . downloadTipThumbnail ( accessToken , thumbnail . iTwinId , iModelId , thumbnail . size ) ; } const size = thumbnail instanceof SmallThumbnail ? "Small" : "Large" ; const thumbnailId = thumbnail . id ! ; Logger . logInfo ( loggerCategory , `Downloading ${ size }Thumbnail ${ thumbnailId } for iModel` , ( ) => ( { iModelId } ) ) ; const url = `${ await this . _handler . getUrl ( ) + this . getRelativeUrl ( iModelId , size , thumbnailId ) }/$file` ; const pngImage = await this . downloadThumbnail ( accessToken , url ) ; Logger . logTrace ( loggerCategory , `Downloaded ${ size }Thumbnail ${ thumbnailId } for iModel` , ( ) => ( { iModelId } ) ) ; return pngImage ; } }