Modify GlobalRegistry to use async local storage to support multiple "global" containers
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing

This commit is contained in:
Garrett Mills 2021-11-27 10:43:26 -06:00
parent 463076d182
commit 9204a02450

View File

@ -1,18 +1,30 @@
import {Collection} from '../collection/Collection' import {Collection} from '../collection/Collection'
import {uuid4} from './data' import {uuid4} from './data'
import {AsyncLocalStorage} from 'async_hooks'
/** /**
* Type structure for a single item in the global registry. * Type structure for a single item in the global registry.
*/ */
export type GlobalRegistrant = { key: string | symbol, value: any } export type GlobalRegistrant = { key: string | symbol, value: any }
export class AccessGlobalRegistryOutsideAsyncLifecycleError extends Error {
constructor() {
super('Attempted to access global registry outside of an async context.')
}
}
/** /**
* A convenient class to manage global variables. * A convenient class to manage global variables.
*/ */
export class GlobalRegistry extends Collection<GlobalRegistrant> { export class GlobalRegistry {
constructor() { protected readonly storage: AsyncLocalStorage<Collection<GlobalRegistrant>> = new AsyncLocalStorage<Collection<GlobalRegistrant>>()
super()
this.setGlobal('registry_uuid', uuid4()) /** Run a closure with a global registry. */
public run<T>(closure: () => T): T {
return this.storage.run(new Collection<GlobalRegistrant>(), (): T => {
this.setGlobal('registry_uuid', uuid4())
return closure()
})
} }
/** /**
@ -21,11 +33,11 @@ export class GlobalRegistry extends Collection<GlobalRegistrant> {
* @param value * @param value
*/ */
public setGlobal(key: string | symbol, value: unknown): this { public setGlobal(key: string | symbol, value: unknown): this {
const existing = this.firstWhere('key', '=', key) const existing = this.getCollection().firstWhere('key', '=', key)
if ( existing ) { if ( existing ) {
existing.value = value existing.value = value
} else { } else {
this.push({ this.getCollection().push({
key, key,
value, value,
}) })
@ -39,7 +51,17 @@ export class GlobalRegistry extends Collection<GlobalRegistrant> {
* @param key * @param key
*/ */
public getGlobal(key: string | symbol): any { public getGlobal(key: string | symbol): any {
return this.firstWhere('key', '=', key)?.value return this.getCollection().firstWhere('key', '=', key)?.value
}
/** Get the globals collection or throw an error if outside async context. */
protected getCollection(): Collection<GlobalRegistrant> {
const coll = this.storage.getStore()
if ( !coll ) {
throw new AccessGlobalRegistryOutsideAsyncLifecycleError()
}
return coll
} }
} }