import { AbstractFactory, Container, DependencyRequirement, PropertyDependency, isInstantiable, DEPENDENCY_KEYS_METADATA_KEY, DEPENDENCY_KEYS_PROPERTY_METADATA_KEY, Instantiable, } from '../../di' import {Collection, ErrorWithContext} from '../../util' import {MemorySession} from './MemorySession' import {Session} from './Session' import {Logging} from '../../service/Logging' import {Config} from '../../service/Config' /** * A dependency injection factory that matches the abstract Session class * and produces an instance of the configured session driver implementation. */ export class SessionFactory extends AbstractFactory { protected readonly logging: Logging protected readonly config: Config /** True if we have printed the memory session warning at least once. */ private static loggedMemorySessionWarningOnce = false constructor() { super({}) this.logging = Container.getContainer().make(Logging) this.config = Container.getContainer().make(Config) } produce(): Session { return new (this.getSessionClass())() } match(something: unknown): boolean { return something === Session } getDependencyKeys(): Collection { const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getSessionClass()) if ( meta ) { return meta } return new Collection() } getInjectedProperties(): Collection { const meta = new Collection() let currentToken = this.getSessionClass() do { const loadedMeta = Reflect.getMetadata(DEPENDENCY_KEYS_PROPERTY_METADATA_KEY, currentToken) if ( loadedMeta ) { meta.concat(loadedMeta) } currentToken = Object.getPrototypeOf(currentToken) } while (Object.getPrototypeOf(currentToken) !== Function.prototype && Object.getPrototypeOf(currentToken) !== Object.prototype) return meta } /** * Return the instantiable class of the configured session backend. * @protected * @return Instantiable */ protected getSessionClass(): Instantiable { const SessionClass = this.config.get('server.session.driver', MemorySession) if ( SessionClass === MemorySession && !SessionFactory.loggedMemorySessionWarningOnce ) { this.logging.warn(`You are using the default memory-based session driver. It is recommended you configure a persistent session driver instead.`) SessionFactory.loggedMemorySessionWarningOnce = true } if ( !isInstantiable(SessionClass) || !(SessionClass.prototype instanceof Session) ) { const e = new ErrorWithContext('Provided session class does not extend from @extollo/lib.Session') e.context = { configKey: 'server.session.driver', class: SessionClass.toString(), } } return SessionClass } }