import { ITelemetryLogger } from "@fluidframework/common-definitions" ; import { IFluidObject , IFluidConfiguration , IRequest , IResponse , IFluidCodeDetails , IFluidCodeDetailsComparer , IProvideFluidCodeDetailsComparer , FluidObject , } from "@fluidframework/core-interfaces" ; import { IAudience , IContainerContext , IDeltaManager , ILoader , IRuntime , ICriticalContainerError , ContainerWarning , AttachState , ILoaderOptions , IRuntimeFactory , ICodeLoader , IProvideRuntimeFactory , } from "@fluidframework/container-definitions" ; import { IDocumentStorageService } from "@fluidframework/driver-definitions" ; import { IClientConfiguration , IClientDetails , IDocumentMessage , IQuorum , ISequencedDocumentMessage , ISignalMessage , ISnapshotTree , ITree , MessageType , ISummaryTree , IVersion , } from "@fluidframework/protocol-definitions" ; import { PerformanceEvent } from "@fluidframework/telemetry-utils" ; import { assert , LazyPromise } from "@fluidframework/common-utils" ; import { Container } from "./container" ; import { ICodeDetailsLoader , IFluidModuleWithDetails } from "./loader" ; const PackageNotFactoryError = "Code package does not implement IRuntimeFactory" ; export class ContainerContext implements IContainerContext { public static async createOrLoad ( container , scope , codeLoader , codeDetails , baseSnapshot , deltaManager , quorum , loader , raiseContainerWarning , submitFn , submitSignalFn , closeFn , version , updateDirtyContainerState , existing , pendingLocalState ? ) { const context = new ContainerContext ( container , scope , codeLoader , codeDetails , baseSnapshot , deltaManager , quorum , loader , raiseContainerWarning , submitFn , submitSignalFn , closeFn , version , updateDirtyContainerState , existing , pendingLocalState ) ; await context . instantiateRuntime ( existing ) ; return context ; } public readonly taggedLogger : ITelemetryLogger ; /**
     * Subtlety: returns this.taggedLogger since vanilla this.logger is now deprecated. See IContainerContext for more
     * details.
    */ deprecated public get logger ( ) : ITelemetryLogger { return this . taggedLogger ; } public get id ( ) : string { return this . container . id ; } public get clientId ( ) : string | undefined { return this . container . clientId ; } public get clientDetails ( ) : IClientDetails { return this . container . clientDetails ; } public get connected ( ) : boolean { return this . container . connected ; } public get canSummarize ( ) : boolean { return "summarize" in this . runtime ; } public get serviceConfiguration ( ) : IClientConfiguration | undefined { return this . container . serviceConfiguration ; } public get audience ( ) : IAudience { return this . container . audience ; } public get options ( ) : ILoaderOptions { return this . container . options ; } deprecated public get configuration ( ) : IFluidConfiguration { const config = { scopes : this . container . scopes } ; return config as IFluidConfiguration ; } public get baseSnapshot ( ) { return this . _baseSnapshot ; } public get storage ( ) : IDocumentStorageService { return this . container . storage ; } private _runtime : IRuntime | undefined ; private get runtime ( ) { if ( this . _runtime === undefined ) { throw new Error ( "Attempted to access runtime before it was defined" ) ; } return this . _runtime ; } private _disposed = false ; public get disposed ( ) { return this . _disposed ; } public get codeDetails ( ) { return this . _codeDetails ; } private readonly _quorum : IQuorum ; public get quorum ( ) : IQuorum { return this . _quorum ; } private readonly _fluidModuleP : Promise < IFluidModuleWithDetails > ; constructor ( private readonly container , public readonly scope , private readonly codeLoader , private readonly _codeDetails , private readonly _baseSnapshot , public readonly deltaManager , quorum , public readonly loader , public readonly raiseContainerWarning , public readonly submitFn , public readonly submitSignalFn , public readonly closeFn , public readonly version , public readonly updateDirtyContainerState , public readonly existing , public readonly pendingLocalState ? ) { this . _quorum = quorum ; this . taggedLogger = container . subLogger ; this . _fluidModuleP = new LazyPromise < IFluidModuleWithDetails > ( async ( ) => this . loadCodeModule ( _codeDetails ) ) ; this . attachListener ( ) ; } public getSpecifiedCodeDetails ( ) { return ( this . _quorum . get ( "code" ) ?? this . _quorum . get ( "code2" ) ) as IFluidCodeDetails | undefined ; } public dispose ( error ? ) { if ( this . _disposed ) { return ; } this . _disposed = true ; this . runtime . dispose ( error ) ; this . _quorum . dispose ( ) ; this . deltaManager . dispose ( ) ; } public async snapshot ( tagMessage = "" , fullTree = false ) { return this . runtime . snapshot ( tagMessage , fullTree ) ; } public getLoadedFromVersion ( ) { return this . container . loadedFromVersion ; } public get attachState ( ) : AttachState { return this . container . attachState ; } param blobRedirectTable public createSummary ( blobRedirectTable ? ) { return this . runtime . createSummary ( blobRedirectTable ) ; } public setConnectionState ( connected , clientId ? ) { const runtime = this . runtime ; assert ( connected === this . connected , 0x0de ) ; runtime . setConnectionState ( connected , clientId ) ; } public process ( message , local , context ) { this . runtime . process ( message , local , context ) ; } public processSignal ( message , local ) { this . runtime . processSignal ( message , local ) ; } public async request ( path ) { return this . runtime . request ( path ) ; } public async getAbsoluteUrl ( relativeUrl ) { return this . container . getAbsoluteUrl ( relativeUrl ) ; } public getPendingLocalState ( ) { return this . runtime . getPendingLocalState ( ) ; } /**
     * Determines if the current code details of the context
     * satisfy the incoming constraint code details
     */ public async satisfies ( constraintCodeDetails ) { const comparers = [ ] ; const maybeCompareCodeLoader = this . codeLoader ; if ( maybeCompareCodeLoader . IFluidCodeDetailsComparer !== undefined ) { comparers . push ( maybeCompareCodeLoader . IFluidCodeDetailsComparer ) ; } const moduleWithDetails = await this . _fluidModuleP ; const maybeCompareExport = moduleWithDetails . module ?. fluidExport ; if ( maybeCompareExport ?. IFluidCodeDetailsComparer !== undefined ) { comparers . push ( maybeCompareExport . IFluidCodeDetailsComparer ) ; } if ( comparers . length === 0 ) { return false ; } for ( const comparer of comparers ) { const satisfies = await comparer . satisfies ( moduleWithDetails . details , constraintCodeDetails ) ; if ( satisfies === false ) { return false ; } } return true ; } public notifyAttaching ( ) { this . runtime . setAttachState ( AttachState . Attaching ) ; } private async getRuntimeFactory ( ) { const fluidExport = ( await this . _fluidModuleP ) . module ?. fluidExport ; const runtimeFactory = fluidExport ?. IRuntimeFactory ; if ( runtimeFactory === undefined ) { throw new Error ( PackageNotFactoryError ) ; } return runtimeFactory ; } private async instantiateRuntime ( existing ) { const runtimeFactory = await this . getRuntimeFactory ( ) ; this . _runtime = await runtimeFactory . instantiateRuntime ( this , existing ) ; } private attachListener ( ) { this . container . once ( "attached" , ( ) => { this . runtime . setAttachState ( AttachState . Attached ) ; } ) ; } private async loadCodeModule ( codeDetails ) { const loadCodeResult = await PerformanceEvent . timedExecAsync ( this . taggedLogger , { eventName : "CodeLoad" } , async ( ) => this . codeLoader . load ( codeDetails ) ) ; if ( "module" in loadCodeResult ) { const { module , details } = loadCodeResult ; return { module , details : details ?? codeDetails } ; } else { return { module : loadCodeResult , details : codeDetails } ; } } }