UNPKG

iopa

Version:

API-first, Internet of Things (IoT) stack for Typescript, official implementation of the Internet Open Protocols Alliance (IOPA) reference pattern

178 lines (164 loc) 4.95 kB
/* * Internet Open Protocol Abstraction (IOPA) * Copyright (c) 2016-2022 Internet Open Protocols Alliance * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import type { HandlerResult, IAppCapability, IContextCore, IContextIopaLegacy, ILogger, IopaApp, IRef, ITraceEvent, ITraceEvents } from '@iopa/types' import { ExtendableEventTarget } from '../util/events' import { VERSION } from './constants' import logger from './logging' import IopaMap from './map' /** Represents IOPA Context object for any State Flow or REST Request/Response */ export class ContextCore<C> extends IopaMap<IContextIopaLegacy<C & IAppCapability>> implements IContextCore<C> { public 'iopa.Version': string public dispose?: () => void public createChild: (urlPath?: string, defaults?: any) => this public log: ILogger public app: IopaApp<any, C & IAppCapability> /** Initialize blank IopaContext object; Generic properties common to all server types included */ public init(): this { const abortController = new AbortController() this.set('server.Timestamp', Date.now()) this.set('iopa.Events', new ExtendableEventTarget() as any) this.set('iopa.Version', VERSION) this.set('server.AbortController', abortController) this.set('server.AbortSignal', abortController.signal) this.set('server.CurrentMiddleware', '') this.set('log', logger) return this } public dispatchEventExtendable(event: ITraceEvent): Promise<boolean> { return this.get('iopa.Events').dispatchEventExtendable(event) } public addEventListener( type: keyof ITraceEvents, callback: (ev: ITraceEvent) => any, options?: boolean | AddEventListenerOptions ): void { return this.get('iopa.Events').addEventListener( type as any, callback, options ) } public dispatchEvent(event: ITraceEvent): boolean { return this.get('iopa.Events').dispatchEvent(event) } public removeEventListener( type: string, callback: (ev: ITraceEvent) => any, options?: boolean | EventListenerOptions ): void { return this.get('iopa.Events').removeEventListener( type as any, callback, options ) } public using(appFuncPromiseOrValue: Function | Promise<any>): Promise<void> { if (typeof appFuncPromiseOrValue === 'function') { return _using<C>({ context: this, p: appFuncPromiseOrValue(this) }) } return _using({ context: this as IContextCore<C>, p: appFuncPromiseOrValue }) } public capability<T>(keyOrRef: IRef<T>): T | undefined public capability<K extends keyof C>(keyOrRef: K): C[K] { if (typeof keyOrRef === 'string') { return this._capability(keyOrRef as keyof C) as any } else { return this._capability( (keyOrRef as unknown as IRef<any>).id as unknown as keyof C ) as any } } private _capability<K extends keyof C>(keyOrRef: K): C[K] { return this.get('server.Capabilities')[keyOrRef] } public setCapability<K extends keyof C>(keyOrRef: K, value: C[K]) public setCapability<T, I extends T>(keyOrRef: IRef<T>, value: I): void { if (typeof keyOrRef === 'string') { return this._setCapability(keyOrRef as keyof C, value) } else { return this._setCapability( (keyOrRef as unknown as IRef<any>).id as unknown as keyof C, value ) } } private _setCapability<K extends keyof C>(keyOrRef: K, value: any): void { this.get('server.Capabilities')[keyOrRef] = value } public respondWith(res: HandlerResult, status?: number): this { if (res || status) { throw new Error('responses Not Implemented in Core') } return this } } /* ES6 finally/dispose pattern for IOPA Context */ function _using<C>({ context, p }: { context: IContextCore<C> p?: Promise<any> | null }): Promise<void> { return new Promise<void>((resolve, reject) => { if (typeof p === 'undefined') { p = null } resolve(p) }).then( (value) => { return Promise.resolve( (() => { setTimeout(() => { if (context.dispose) { context.dispose() } }, 0) return value })() ) }, (err) => { console.error(err) setTimeout(() => { if (context.dispose) { context.dispose() } }, 0) throw err } ) }