@softvisio/core
Version:
Softisio core
253 lines (187 loc) • 5.57 kB
JavaScript
import fs from "node:fs";
import { readConfigSync } from "#lib/config";
import { mergeObjects } from "#lib/utils";
export default class Component {
#components;
#id;
#location;
#required;
#dependencies;
#optionalDependencies;
#config;
#instance;
#destroyLock;
constructor ( { components, id, location, required, dependencies, optionalDependencies, config } ) {
this.#components = components;
this.#id = id;
this.#location = location;
this.#required = required;
this.#dependencies = dependencies || [];
this.#optionalDependencies = optionalDependencies || [];
this.#config = config;
}
// properties
get components () {
return this.#components;
}
get id () {
return this.#id;
}
get location () {
return this.#location;
}
get isRequired () {
return this.#required;
}
get dependencies () {
return this.#dependencies;
}
get optionalDependencies () {
return this.#optionalDependencies;
}
get app () {
return this.#components?.app;
}
get config () {
return this.#config;
}
get instance () {
return this.#instance;
}
get aclConfig () {
return null;
}
get notificationsConfig () {
return null;
}
get storageLocationsConfig () {
return null;
}
// public
applySubConfig () {
return this._applySubConfig();
}
applySubSchema ( schema ) {
return this._applySubSchema( schema );
}
async checkEnabled () {
return this._checkEnabled();
}
async install () {
try {
// component id conflict
if ( this.id in this.app ) {
return result( [ 400, `Component "${ this.id }" is conflicts with the already exists app property` ] );
}
this.#instance = await this._install();
Object.defineProperty( this.app, this.id, {
"configurable": false,
"enumerable": false,
"writable": false,
"value": this.#instance,
} );
// lock destroy
if ( this._destroy ) this.#destroyLock = process.destroyController.lock( this.#id );
return result( 200 );
}
catch ( e ) {
return result.catch( e );
}
}
async configure () {
return this._configure();
}
async init () {
return this._init();
}
async start () {
var res;
res = await this._start();
if ( !res.ok ) return res;
return result( 200 );
}
async afterAppStarted () {
var res;
res = await this._afterAppStarted();
if ( !res.ok ) return res;
return result( 200 );
}
async destroy () {
if ( !this.#destroyLock || this.#destroyLock.isDone ) return;
console.info( `Destroying component: ${ this.id }` );
await this._destroy();
this.#destroyLock?.done();
}
async checkHealth () {
return this._checkHealth();
}
// protected
_applySubConfig () {}
_applySubSchema ( schema ) {
return schema;
}
async _checkEnabled () {
// optional deps are removed
return this.isRequired;
}
async _install () {
return true;
}
async _configure () {
return result( 200 );
}
async _init () {
return result( 200 );
}
async _start () {
return result( 200 );
}
async _afterAppStarted () {
return result( 200 );
}
async _checkHealth () {
return result( 200 );
}
_mergeSubConfig ( location ) {
const path = new URL( "sub-config.yaml", location );
if ( !fs.existsSync( path ) ) return;
const subConfig = readConfigSync( path );
if ( subConfig ) mergeObjects( this.config, subConfig );
}
_mergeSubSchema ( schema, location ) {
const path = new URL( "sub-config.schema.yaml", location );
if ( !fs.existsSync( path ) ) return schema;
var subSchema = readConfigSync( path );
if ( !subSchema?.length ) return schema;
subSchema = subSchema.reduce( ( index, schema ) => {
index[ schema[ "$id" ] ] = schema;
delete schema[ "$id" ];
return index;
}, {} );
schema = ( schema || [] ).reduce( ( index, schema ) => {
index[ schema[ "$id" ] ] = schema;
delete schema[ "$id" ];
return index;
}, {} );
if ( subSchema[ "public-config" ] ) {
if ( schema[ "public-config" ] ) {
schema[ "public-config" ] = { "allOf": [ schema[ "public-config" ], subSchema[ "public-config" ] ] };
}
else {
schema[ "public-config" ] = subSchema[ "public-config" ];
}
}
if ( subSchema[ "config" ] ) {
const required = schema[ "config" ]?.required || [];
schema[ "config" ] = mergeObjects( schema[ "config" ], subSchema[ "config" ] );
schema[ "config" ].required ||= [];
schema[ "config" ].required = [ ...schema[ "config" ].required, ...required ];
}
return Object.entries( schema ).map( ( [ id, schema ] ) => {
return {
[ "$id" ]: id,
...schema,
};
} );
}
}