Add generic session interfaces; memory session; factories; kernel
This commit is contained in:
parent
b9f2f844f3
commit
878de025d8
@ -146,7 +146,7 @@ class Container {
|
|||||||
make(target: DependencyKey, ...parameters: any[]) {
|
make(target: DependencyKey, ...parameters: any[]) {
|
||||||
if ( this.has_key(target) )
|
if ( this.has_key(target) )
|
||||||
return this.resolve_and_create(target, ...parameters)
|
return this.resolve_and_create(target, ...parameters)
|
||||||
else if ( typeof target !== 'string' )
|
else if ( typeof target !== 'string' && isInstantiable(target) )
|
||||||
return this.produce_factory(new Factory(target), parameters)
|
return this.produce_factory(new Factory(target), parameters)
|
||||||
else
|
else
|
||||||
throw new TypeError(`Invalid or unknown make target: ${target}`)
|
throw new TypeError(`Invalid or unknown make target: ${target}`)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import Instantiable from './Instantiable.ts'
|
import Instantiable from './Instantiable.ts'
|
||||||
|
import {StaticClass} from './StaticClass.ts'
|
||||||
const DEPENDENCY_KEYS_METADATA_KEY = 'daton:di:dependencyKeys.ts'
|
const DEPENDENCY_KEYS_METADATA_KEY = 'daton:di:dependencyKeys.ts'
|
||||||
type DependencyKey = Instantiable<any> | string
|
type DependencyKey = Instantiable<any> | StaticClass<any> | string
|
||||||
export { DependencyKey, DEPENDENCY_KEYS_METADATA_KEY }
|
export { DependencyKey, DEPENDENCY_KEYS_METADATA_KEY }
|
||||||
|
5
di/src/type/StaticClass.ts
Normal file
5
di/src/type/StaticClass.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export type StaticClass<T> = Function & {prototype: T}
|
||||||
|
|
||||||
|
export function isStaticClass<T>(something: any): something is StaticClass<T> {
|
||||||
|
return typeof something === 'function' && typeof something.prototype !== 'undefined'
|
||||||
|
}
|
@ -10,6 +10,7 @@ export interface ModuleRegistrationFluency {
|
|||||||
after: (other?: Instantiable<Module>) => Kernel,
|
after: (other?: Instantiable<Module>) => Kernel,
|
||||||
first: () => Kernel,
|
first: () => Kernel,
|
||||||
last: () => Kernel,
|
last: () => Kernel,
|
||||||
|
core: () => Kernel,
|
||||||
}
|
}
|
||||||
|
|
||||||
export class KernelModuleNotFoundError extends Error {
|
export class KernelModuleNotFoundError extends Error {
|
||||||
@ -21,6 +22,7 @@ export class KernelModuleNotFoundError extends Error {
|
|||||||
@Service()
|
@Service()
|
||||||
export default class Kernel extends AppClass {
|
export default class Kernel extends AppClass {
|
||||||
protected preflight: Collection<Module> = new Collection<Module>()
|
protected preflight: Collection<Module> = new Collection<Module>()
|
||||||
|
protected inflight?: Module
|
||||||
protected postflight: Collection<Module> = new Collection<Module>()
|
protected postflight: Collection<Module> = new Collection<Module>()
|
||||||
|
|
||||||
public async handle(request: Request): Promise<Request> {
|
public async handle(request: Request): Promise<Request> {
|
||||||
@ -28,6 +30,10 @@ export default class Kernel extends AppClass {
|
|||||||
request = await module.apply(request)
|
request = await module.apply(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( this.inflight ) {
|
||||||
|
request = await this.inflight.apply(request)
|
||||||
|
}
|
||||||
|
|
||||||
for ( const module of this.postflight.toArray() ) {
|
for ( const module of this.postflight.toArray() ) {
|
||||||
request = await module.apply(request)
|
request = await module.apply(request)
|
||||||
}
|
}
|
||||||
@ -88,6 +94,10 @@ export default class Kernel extends AppClass {
|
|||||||
this.postflight = this.postflight.push(this.make(module))
|
this.postflight = this.postflight.push(this.make(module))
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
|
core: (): Kernel => {
|
||||||
|
this.inflight = this.make(module)
|
||||||
|
return this
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
32
lib/src/http/session/MemorySession.ts
Normal file
32
lib/src/http/session/MemorySession.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import Session, { SessionData } from './Session.ts'
|
||||||
|
|
||||||
|
export default class MemorySession extends Session {
|
||||||
|
private _key!: string
|
||||||
|
private _data: SessionData = {}
|
||||||
|
|
||||||
|
public get_key(): string {
|
||||||
|
return this._key
|
||||||
|
}
|
||||||
|
|
||||||
|
public set_key(key: string) {
|
||||||
|
this._key = key
|
||||||
|
}
|
||||||
|
|
||||||
|
public get_data(): SessionData {
|
||||||
|
return this._data
|
||||||
|
}
|
||||||
|
|
||||||
|
public set_data(data: SessionData) {
|
||||||
|
this._data = data
|
||||||
|
}
|
||||||
|
|
||||||
|
public get_attribute(key: string): any {
|
||||||
|
return this._data[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
public set_attribute(key: string, value: any) {
|
||||||
|
this._data[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
public async persist() {}
|
||||||
|
}
|
42
lib/src/http/session/MemorySessionManager.ts
Normal file
42
lib/src/http/session/MemorySessionManager.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { Service } from '../../../../di/src/decorator/Service.ts'
|
||||||
|
import {Collection} from '../../collection/Collection.ts'
|
||||||
|
import Session from './Session.ts'
|
||||||
|
import SessionManager, {InvalidSessionKeyError} from './SessionManager.ts'
|
||||||
|
import Utility from '../../service/utility/Utility.ts'
|
||||||
|
|
||||||
|
export type SessionRegistrant = { key: string, session: Session }
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class MemorySessionManager extends SessionManager {
|
||||||
|
private _sessions: Collection<SessionRegistrant> = new Collection<SessionRegistrant>()
|
||||||
|
|
||||||
|
public async has_session(key: string): Promise<boolean> {
|
||||||
|
return !!this._sessions.firstWhere('key', '=', key)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async get_session(key?: string): Promise<Session> {
|
||||||
|
if ( !key ) {
|
||||||
|
const utility: Utility = this.make(Utility)
|
||||||
|
const session_key: string = key || utility.uuid()
|
||||||
|
const session = this.make(Session)
|
||||||
|
|
||||||
|
session.set_key(session_key)
|
||||||
|
await session.persist()
|
||||||
|
this._sessions.push({ key: session_key, session })
|
||||||
|
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
const session = this._sessions.firstWhere('key', '=', key)
|
||||||
|
if ( !session ) throw new InvalidSessionKeyError(key)
|
||||||
|
return session.session
|
||||||
|
}
|
||||||
|
|
||||||
|
public async purge(key?: string) {
|
||||||
|
if ( key ) {
|
||||||
|
this._sessions = this._sessions.filter(session => session.key !== key)
|
||||||
|
} else {
|
||||||
|
this._sessions = new Collection<SessionRegistrant>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
lib/src/http/session/Session.ts
Normal file
13
lib/src/http/session/Session.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import AppClass from '../../lifecycle/AppClass.ts'
|
||||||
|
|
||||||
|
export type SessionData = { [key: string]: any }
|
||||||
|
|
||||||
|
export default abstract class Session extends AppClass {
|
||||||
|
public abstract get_key(): string
|
||||||
|
public abstract set_key(key: string): void
|
||||||
|
public abstract async persist(): Promise<void>
|
||||||
|
public abstract get_data(): SessionData
|
||||||
|
public abstract set_data(data: SessionData): void
|
||||||
|
public abstract get_attribute(key: string): any
|
||||||
|
public abstract set_attribute(key: string, value: any): void
|
||||||
|
}
|
25
lib/src/http/session/SessionFactory.ts
Normal file
25
lib/src/http/session/SessionFactory.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import AbstractFactory from '../../../../di/src/factory/AbstractFactory.ts'
|
||||||
|
import MemorySession from './MemorySession.ts'
|
||||||
|
import Session from './Session.ts'
|
||||||
|
import {DependencyRequirement} from '../../../../di/src/type/DependencyRequirement.ts'
|
||||||
|
import {Collection} from '../../collection/Collection.ts'
|
||||||
|
|
||||||
|
// TODO support configurable session backends
|
||||||
|
|
||||||
|
export default class SessionFactory extends AbstractFactory {
|
||||||
|
constructor() {
|
||||||
|
super({})
|
||||||
|
}
|
||||||
|
|
||||||
|
produce(dependencies: any[], parameters: any[]): any {
|
||||||
|
return new MemorySession()
|
||||||
|
}
|
||||||
|
|
||||||
|
match(something: any) {
|
||||||
|
return something === Session
|
||||||
|
}
|
||||||
|
|
||||||
|
get_dependency_keys(): Collection<DependencyRequirement> {
|
||||||
|
return new Collection<DependencyRequirement>()
|
||||||
|
}
|
||||||
|
}
|
16
lib/src/http/session/SessionManager.ts
Normal file
16
lib/src/http/session/SessionManager.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import AppClass from '../../lifecycle/AppClass.ts'
|
||||||
|
import Session from './Session.ts'
|
||||||
|
|
||||||
|
export class InvalidSessionKeyError extends Error {
|
||||||
|
constructor(key: any) {
|
||||||
|
super(`Invalid session key: ${key}. No session exists.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default abstract class SessionManager extends AppClass {
|
||||||
|
|
||||||
|
public abstract async get_session(key?: string): Promise<Session>
|
||||||
|
public abstract async has_session(key: string): Promise<boolean>
|
||||||
|
public abstract async purge(key?: string): Promise<void>
|
||||||
|
|
||||||
|
}
|
25
lib/src/http/session/SessionManagerFactory.ts
Normal file
25
lib/src/http/session/SessionManagerFactory.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import AbstractFactory from '../../../../di/src/factory/AbstractFactory.ts'
|
||||||
|
import {DependencyRequirement} from '../../../../di/src/type/DependencyRequirement.ts'
|
||||||
|
import {Collection} from '../../collection/Collection.ts'
|
||||||
|
import MemorySessionManager from './MemorySessionManager.ts'
|
||||||
|
import SessionManager from './SessionManager.ts'
|
||||||
|
|
||||||
|
// TODO support configurable session backends
|
||||||
|
|
||||||
|
export default class SessionManagerFactory extends AbstractFactory {
|
||||||
|
constructor() {
|
||||||
|
super({})
|
||||||
|
}
|
||||||
|
|
||||||
|
produce(dependencies: any[], parameters: any[]): any {
|
||||||
|
return new MemorySessionManager()
|
||||||
|
}
|
||||||
|
|
||||||
|
match(something: any) {
|
||||||
|
return something === SessionManager
|
||||||
|
}
|
||||||
|
|
||||||
|
get_dependency_keys(): Collection<DependencyRequirement> {
|
||||||
|
return new Collection<DependencyRequirement>()
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,9 @@ import { make } from '../../../di/src/global.ts'
|
|||||||
import 'https://deno.land/x/dotenv/load.ts'
|
import 'https://deno.land/x/dotenv/load.ts'
|
||||||
import { Container } from '../../../di/src/Container.ts'
|
import { Container } from '../../../di/src/Container.ts'
|
||||||
import { Inject } from '../../../di/src/decorator/Injection.ts'
|
import { Inject } from '../../../di/src/decorator/Injection.ts'
|
||||||
import CacheFactory from "../support/CacheFactory.ts";
|
import CacheFactory from '../support/CacheFactory.ts'
|
||||||
|
import SessionFactory from '../http/session/SessionFactory.ts'
|
||||||
|
import SessionManagerFactory from '../http/session/SessionManagerFactory.ts'
|
||||||
|
|
||||||
const env = (name: string, fallback?: any) => {
|
const env = (name: string, fallback?: any) => {
|
||||||
const scaffolding = make(Scaffolding)
|
const scaffolding = make(Scaffolding)
|
||||||
@ -31,9 +33,7 @@ export default class Scaffolding extends LifecycleUnit {
|
|||||||
|
|
||||||
public async up() {
|
public async up() {
|
||||||
this.setup_logging()
|
this.setup_logging()
|
||||||
|
this.register_factories()
|
||||||
this.logger.verbose('Adding the cache production factory to the container...')
|
|
||||||
this.injector.register_factory(new CacheFactory())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public setup_logging() {
|
public setup_logging() {
|
||||||
@ -52,4 +52,13 @@ export default class Scaffolding extends LifecycleUnit {
|
|||||||
|
|
||||||
this.logger.info('Logging initialized.', true)
|
this.logger.info('Logging initialized.', true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public register_factories() {
|
||||||
|
this.logger.verbose('Adding the cache production factory to the container...')
|
||||||
|
this.injector.register_factory(new CacheFactory())
|
||||||
|
|
||||||
|
this.logger.verbose('Adding the session production factories to the container...')
|
||||||
|
this.injector.register_factory(new SessionFactory())
|
||||||
|
this.injector.register_factory(new SessionManagerFactory())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user