import setupLogger from '@/config/logger' ; import { IEntityAccessControlLoader } from '@/services/entity-acls/typings/entity-acls' ; import { EntityType } from '@/typings/enums' ; import { IEntityOwnership } from '@/typings/typings' ; import LRU from 'lru-cache' ; const logger = setupLogger ( module ) ; const TTL = 1000 * 60 * 2 ; export default class EntityAccessControlCache { private cache : LRU < string , IEntityOwnership | undefined > ; constructor ( readonly loader ) { this . cache = new LRU < string , IEntityOwnership > ( { maxAge : TTL , dispose : ( key , _n ) => { logger . info ( `*** disposing of ${ key } ***` ) ; } , noDisposeOnSet : true , } ) ; } /**
     * Refresh the entire cache (if supported by loader).
     */ public async refresh ( ) { logger . info ( 'performing full cache refresh' ) ; try { const entities = await this . loader . fetchAllEntities ( ) ; entities . forEach ( ( entity ) => { const key = this . buildKeyFromEntity ( entity ) ; this . cache . set ( key , entity ) ; } ) ; } catch ( err ) { logger . error ( 'Loader failed to fetch all entities.' , err ) ; } } param clusterName param env param type param entityName public async get ( clusterName , env , type , entityName ) { logger . info ( `fetching ${ EntityType [ type ] } "${ entityName }" from cache` ) ; const key = this . buildKey ( clusterName , env , type , entityName ) ; let value = this . cache . get ( key ) ; if ( value === undefined ) { logger . info ( `cache miss for ${ EntityType [ type ] } "${ entityName }"` ) ; try { value = await this . loader . fetchEntity ( clusterName , env , type , entityName ) ; logger . info ( `loaded cache ${ EntityType [ type ] } "${ entityName }"` ) ; this . cache . set ( key , value ) ; } catch ( err ) { logger . error ( `Loaded failed to fetch ${ EntityType [ type ] } "${ entityName }"` , err ) ; } } return value ; } param clusterName param env param type param entityName see refresh public async getIfPresent ( clusterName , env , type , entityName ) { const key = this . buildKey ( clusterName , env , type , entityName ) ; return this . cache . get ( key ) ; } /**
     * Returns all the values currently in the cache.
     */ public values ( ) { return this . cache . values ( ) . filter ( ( value ) => ! ! value ) as IEntityOwnership [ ] ; } param callbackFn public forEach ( callbackFn ) { return this . cache . forEach ( ( value , key ) => { if ( value ) { callbackFn ( value , key ) ; } } ) ; } private buildKeyFromEntity ( entity ) { return this . buildKey ( entity . clusterName , entity . env , EntityType [ entity . type as keyof typeof EntityType ] , entity . name ) ; } private buildKey ( clusterName , env , type , entityName ) { const typeString = EntityType [ type ] ; return `${ clusterName . toLowerCase ( ) }:::${ env . toLowerCase ( ) }:::${ typeString }:::${ entityName }` ; } }