import { PromiseCache } from "@fluidframework/common-utils" ; import { IOdspResolvedUrl , IFileEntry , IEntry , IPersistedCache , ICacheEntry , } from "@fluidframework/odsp-driver-definitions" ; import { ISocketStorageDiscovery } from "./contracts" ; /**
 * Similar to IPersistedCache, but exposes cache interface for single file
 */ export interface IPersistedFileCache { get ( entry ) : Promise < any > ; put ( entry , value ) : Promise < void > ; removeEntries ( ) : Promise < void > ; } /**
 * Handles garbage collection of expiring cache entries.
 * Not exported.
 * (Based off of the same class in promiseCache.ts, could be consolidated)
 */ class GarbageCollector < TKey > { private readonly gcTimeouts = new Map < TKey , ReturnType < typeof setTimeout > > ( ) ; constructor ( private readonly cleanup ) { } /**
     * Schedule GC for the given key, as applicable
     */ public schedule ( key , durationMs ) { this . gcTimeouts . set ( key , setTimeout ( ( ) => { this . cleanup ( key ) ; this . cancel ( key ) ; } , durationMs ) ) ; } /**
     * Cancel any pending GC for the given key
     */ public cancel ( key ) { const timeout = this . gcTimeouts . get ( key ) ; if ( timeout !== undefined ) { clearTimeout ( timeout ) ; this . gcTimeouts . delete ( key ) ; } } } /**
 * Default local-only implementation of IPersistedCache,
 * used if no persisted cache is provided by the host
 */ export class LocalPersistentCache implements IPersistedCache { private readonly cache = new Map < string , any > ( ) ; private readonly gc = new GarbageCollector < string > ( ( key ) => this . cache . delete ( key ) ) ; public constructor ( private readonly snapshotExpiryPolicy = 30 * 1000 ) { } async get ( entry ) { const key = this . keyFromEntry ( entry ) ; return this . cache . get ( key ) ; } async put ( entry , value ) { const key = this . keyFromEntry ( entry ) ; this . cache . set ( key , value ) ; this . gc . cancel ( key ) ; this . gc . schedule ( key , this . snapshotExpiryPolicy ) ; } async removeEntries ( file ) { Array . from ( this . cache ) . filter ( ( [ cachekey ] ) => { const docIdFromKey = cachekey . split ( "_" ) ; if ( docIdFromKey [ 0 ] === file . docId ) { return true ; } } ) . map ( ( [ cachekey ] ) => { this . cache . delete ( cachekey ) ; } ) ; } private keyFromEntry ( entry ) { return `${ entry . file . docId }_${ entry . type }_${ entry . key }` ; } } export class PromiseCacheWithOneHourSlidingExpiry < T > extends PromiseCache < string , T > { constructor ( removeOnError ? ) { super ( { expiry : { policy : "sliding" , durationMs : 3600000 } , removeOnError } ) ; } } /**
 * Internal cache interface used within driver only
 */ export interface INonPersistentCache { /**
     * Cache of joined/joining session info
     * This cache will use a one hour sliding expiration window.
     */ readonly sessionJoinCache : PromiseCacheWithOneHourSlidingExpiry < ISocketStorageDiscovery > ; /**
     * Cache of resolved/resolving file URLs
     */ readonly fileUrlCache : PromiseCache < string , IOdspResolvedUrl > ; } /**
 * Internal cache interface used within driver only
 */ export interface IOdspCache extends INonPersistentCache { /**
     * Persisted cache - only serializable content is allowed
     */ readonly persistedCache : IPersistedFileCache ; } export class NonPersistentCache implements INonPersistentCache { public readonly sessionJoinCache = new PromiseCacheWithOneHourSlidingExpiry < ISocketStorageDiscovery > ( ) ; public readonly fileUrlCache = new PromiseCache < string , IOdspResolvedUrl > ( ) ; }