import { AbstractFactory, Container, DependencyRequirement, PropertyDependency, isInstantiable, DEPENDENCY_KEYS_METADATA_KEY, StaticClass, Instantiable, getPropertyInjectionMetadata, } from '../../di' import {Collection, ErrorWithContext} from '../../util' import {Logging} from '../../service/Logging' import {Config} from '../../service/Config' import {Cache} from '../../util' import {MemoryCache} from './MemoryCache' /** * Dependency container factory that matches the abstract Cache token, but * produces an instance of whatever Cache driver is configured in the `server.cache.driver` config. */ export class CacheFactory extends AbstractFactory { protected readonly logging: Logging protected readonly config: Config /** true if we have printed the memory-based cache driver warning once. */ private static loggedMemoryCacheWarningOnce = false constructor() { super({}) this.logging = Container.getContainer().make(Logging) this.config = Container.getContainer().make(Config) } produce(): Cache { return new (this.getCacheClass())() } match(something: unknown): boolean { return something === Cache } getDependencyKeys(): Collection { const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getCacheClass()) if ( meta ) { return meta } return new Collection() } getInjectedProperties(): Collection { const meta = new Collection() let currentToken = this.getCacheClass() do { const loadedMeta = getPropertyInjectionMetadata(currentToken) if ( loadedMeta ) { meta.concat(loadedMeta) } currentToken = Object.getPrototypeOf(currentToken) } while (Object.getPrototypeOf(currentToken) !== Function.prototype && Object.getPrototypeOf(currentToken) !== Object.prototype) return meta } /** * Get the configured cache driver and return some Instantiable. * @protected */ protected getCacheClass(): StaticClass> { const CacheClass = this.config.get('server.cache.driver', MemoryCache) if ( CacheClass === MemoryCache && !CacheFactory.loggedMemoryCacheWarningOnce ) { this.logging.warn(`You are using the default memory-based cache driver. It is recommended you configure a persistent cache driver instead.`) CacheFactory.loggedMemoryCacheWarningOnce = true } if ( !isInstantiable(CacheClass) || !(CacheClass.prototype instanceof Cache) ) { const e = new ErrorWithContext('Provided session class does not extend from @extollo/lib.Cache') e.context = { configKey: 'server.cache.driver', class: CacheClass.toString(), } } return CacheClass } }