@ -0,0 +1,16 @@ | |||
{ | |||
"name": "@autoplex/microservice", | |||
"version": "0.0.0", | |||
"main": "dist/lib/index.js", | |||
"types": "dist/typings/index.d.ts", | |||
"license": "MIT", | |||
"scripts": { | |||
"build": "yarn run clean && tsc", | |||
"clean": "rimraf ./dist" | |||
}, | |||
"devDependencies": { | |||
"@types/node": "^15.0.1", | |||
"rimraf": "^3.0.2", | |||
"typescript": "^4.2.4" | |||
} | |||
} |
@ -0,0 +1,60 @@ | |||
import { Microservice } from "./Microservice"; | |||
/** | |||
* A generic service | |||
*/ | |||
export abstract class InternalService<T extends Microservice = Microservice> | |||
{ | |||
/** | |||
* The application instance | |||
*/ | |||
protected readonly app: T; | |||
/** | |||
* Enable/disable logging for this service | |||
*/ | |||
public logging: boolean = true; | |||
/** | |||
* Create a new service | |||
*/ | |||
public constructor(app: T) { | |||
this.app = app; | |||
} | |||
// Required Service Implementation ------------------------------------------------------------- | |||
/** | |||
* The service name | |||
*/ | |||
public abstract get name(): string; | |||
/** | |||
* Boot the service | |||
*/ | |||
public abstract boot(): Promise<void>; | |||
/** | |||
* Shut the application down | |||
*/ | |||
public abstract shutdown(): Promise<void>; | |||
// Miscellaneous ------------------------------------------------------------------------------ | |||
/** | |||
* Indicate the application is ready | |||
*/ | |||
public start() { | |||
// no-op | |||
}; | |||
/** | |||
* Service-specific logging | |||
*/ | |||
public log(...args: any[]) { | |||
if (!this.logging) { | |||
return; | |||
} | |||
console.log(`[${this.name}]:`, ...args); | |||
} | |||
} |
@ -0,0 +1,122 @@ | |||
import { InternalService } from "./InternalService"; | |||
import assert from "assert"; | |||
/** | |||
* Application InternalService map | |||
*/ | |||
interface InternalServiceMap { | |||
[name: string]: InternalService | |||
} | |||
/** | |||
* The InternalService constructor type | |||
*/ | |||
type InternalServiceConstructor<T extends Microservice = Microservice> = new (app: T) => InternalService<T>; | |||
/** | |||
* The main application class | |||
*/ | |||
export class Microservice | |||
{ | |||
/** | |||
* Maintain a static reference to the application instance | |||
*/ | |||
private static __instance: Microservice; | |||
/** | |||
* All available InternalServices | |||
*/ | |||
protected services: InternalServiceMap = {}; | |||
/** | |||
* Return the current application instance | |||
*/ | |||
public static instance() { | |||
return this.__instance; | |||
} | |||
/** | |||
* Create a new application instance | |||
*/ | |||
public constructor() { | |||
Microservice.__instance = this; | |||
} | |||
// Overridable -------------------------------------------------------------------------------- | |||
/** | |||
* Invoked when the application has finished booting | |||
*/ | |||
protected onStart(): void|Promise<void> {} | |||
// Application Management ---------------------------------------------------------------------- | |||
/** | |||
* Boot the application and all of the InternalServices | |||
*/ | |||
protected async boot() { | |||
let InternalServices = Object.values(this.services); | |||
return Promise.all(InternalServices.map(InternalService => InternalService.boot())); | |||
} | |||
/** | |||
* Shutdown the application | |||
*/ | |||
protected shutdown() { | |||
let InternalServices = Object.values(this.services); | |||
return Promise.all(InternalServices.map(InternalService => InternalService.shutdown())); | |||
} | |||
/** | |||
* Start the application | |||
*/ | |||
public async exec() { | |||
await this.boot(); | |||
await this.onStart(); | |||
for (let InternalService of Object.values(this.services)) { | |||
InternalService.start(); | |||
} | |||
} | |||
/** | |||
* Quit the application | |||
*/ | |||
public async quit(code: number = 0) { | |||
await this.shutdown(); | |||
process.exit(code); | |||
} | |||
// InternalService Management -------------------------------------------------------------------------- | |||
/** | |||
* Install InternalServices into the application | |||
*/ | |||
protected installServices<T extends Microservice>(this: T, InternalServices: InternalServiceConstructor<T>[]) { | |||
for (let InternalServiceClass of InternalServices) { | |||
this.installService(InternalServiceClass); | |||
} | |||
} | |||
/** | |||
* Install a InternalService into the application | |||
*/ | |||
protected installService<T extends Microservice>(this: T, InternalServiceClass: InternalServiceConstructor<T>) { | |||
let InternalService = new InternalServiceClass(this); | |||
this.services[InternalService.name] = InternalService; | |||
} | |||
/** | |||
* Get all available InternalServices | |||
*/ | |||
public serviceList() { | |||
return Object.keys(this.services); | |||
} | |||
/** | |||
* Get an application InternalService instance | |||
*/ | |||
public service<T extends InternalService<Microservice>>(InternalServiceName: string) { | |||
assert(InternalServiceName in this.services); | |||
return <T>this.services[InternalServiceName]; | |||
} | |||
} |
@ -0,0 +1,2 @@ | |||
export * from "./Microservice"; | |||
export * from "./InternalService"; |
@ -0,0 +1,7 @@ | |||
{ | |||
"extends": "../../tsconfig.package.json", | |||
"compilerOptions": { | |||
"outDir": "dist/lib", | |||
"declarationDir": "dist/typings" | |||
} | |||
} |
@ -0,0 +1,92 @@ | |||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. | |||
# yarn lockfile v1 | |||
"@types/node@^15.0.1": | |||
version "15.0.1" | |||
resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.1.tgz#ef34dea0881028d11398be5bf4e856743e3dc35a" | |||
integrity sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA== | |||
balanced-match@^1.0.0: | |||
version "1.0.2" | |||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" | |||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== | |||
brace-expansion@^1.1.7: | |||
version "1.1.11" | |||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" | |||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== | |||
dependencies: | |||
balanced-match "^1.0.0" | |||
concat-map "0.0.1" | |||
concat-map@0.0.1: | |||
version "0.0.1" | |||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" | |||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= | |||
fs.realpath@^1.0.0: | |||
version "1.0.0" | |||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" | |||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= | |||
glob@^7.1.3: | |||
version "7.1.6" | |||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" | |||
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== | |||
dependencies: | |||
fs.realpath "^1.0.0" | |||
inflight "^1.0.4" | |||
inherits "2" | |||
minimatch "^3.0.4" | |||
once "^1.3.0" | |||
path-is-absolute "^1.0.0" | |||
inflight@^1.0.4: | |||
version "1.0.6" | |||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" | |||
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= | |||
dependencies: | |||
once "^1.3.0" | |||
wrappy "1" | |||
inherits@2: | |||
version "2.0.4" | |||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" | |||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== | |||
minimatch@^3.0.4: | |||
version "3.0.4" | |||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" | |||
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== | |||
dependencies: | |||
brace-expansion "^1.1.7" | |||
once@^1.3.0: | |||
version "1.4.0" | |||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" | |||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= | |||
dependencies: | |||
wrappy "1" | |||
path-is-absolute@^1.0.0: | |||
version "1.0.1" | |||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" | |||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= | |||
rimraf@^3.0.2: | |||
version "3.0.2" | |||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" | |||
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== | |||
dependencies: | |||
glob "^7.1.3" | |||
typescript@^4.2.4: | |||
version "4.2.4" | |||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" | |||
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== | |||
wrappy@1: | |||
version "1.0.2" | |||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" | |||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= |