import {NoSessionKeyError, Session, SessionData, SessionNotLoadedError} from './Session' import {Inject, Injectable} from '../../di' import {Cache, Maybe} from '../../util' import {Config} from '../../service/Config' /** * A Session implementation that uses the configured Cache driver for persistence. */ @Injectable() export class CacheSession extends Session { @Inject() protected readonly cache!: Cache @Inject() protected readonly config!: Config protected key?: string protected data?: SessionData protected dirty = false forget(key: string): void { if ( !this.data ) { throw new SessionNotLoadedError() } delete this.data[key] this.dirty = true } get(key: string, fallback?: unknown): any { if ( !this.data ) { throw new SessionNotLoadedError() } return this.data[key] ?? fallback } getData(): SessionData { if ( !this.data ) { throw new SessionNotLoadedError() } return {...this.data} } getKey(): string { if ( !this.key ) { throw new NoSessionKeyError() } return this.key } async load(): Promise { const json = await this.cache.fetch(this.formatKey()) if ( json ) { this.data = JSON.parse(json) } else { this.data = {} } this.dirty = false } async persist(): Promise { if ( !this.dirty ) { return } const json = JSON.stringify(this.data) await this.cache.put(this.formatKey(), json, this.getExpiration()) this.dirty = false } private getExpiration(): Maybe { // Get the session expiration. By default, this is 4 hours. const durationMins = this.config.safe('server.session.durationMins') .or(4 * 60) .integer() if ( durationMins !== 0 ) { const date = new Date() date.setMinutes(date.getMinutes() + durationMins) return date } } private formatKey(): string { if ( !this.key ) { throw new NoSessionKeyError() } const prefix = this.config.safe('app.name') .or('Extollo') .string() return `${prefix}_session_${this.key}` } set(key: string, value: unknown): void { if ( !this.data ) { throw new SessionNotLoadedError() } this.data[key] = value this.dirty = true } setData(data: SessionData): void { this.data = {...data} this.dirty = true } setKey(key: string): void { this.key = key } }