zeroant-factory
Version:
Factory modules for zeroant
269 lines • 8.88 kB
JavaScript
import { createServer } from 'http';
import { InternalServerError } from 'zeroant-response/serverErrors/internalServerError.serverError';
import { ErrorCode, ErrorDescription } from 'zeroant-constant/response.enum';
import { ZeroantEvent } from 'zeroant-constant';
import { EventEmitter } from 'events';
export class ZeroantContext {
Config;
static PORT = 8080;
static HOSTNAME = '127.0.0.1';
_server;
_port;
_hostname;
#state = 'idle';
#store = new Map();
#workers = new Map();
#event = new EventEmitter();
#registry;
_servers = [];
constructor(Config) {
this.Config = Config;
}
delay = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
initWorkers(workers) {
for (const Worker of workers) {
const worker = new Worker(this);
this.#workers.set(worker.name, worker);
}
}
getWorkerByName(workerName) {
return this.#workers.get(workerName) ?? null;
}
getWorkerNames() {
return this.#workers.keys();
}
get workers() {
return {
get: (Worker) => this.getWorker(Worker)
};
}
getWorkers() {
const workers = [];
for (const worker of this.#workers.values()) {
workers.push(worker);
}
return workers;
}
getWorker(Worker) {
for (const worker of this.#workers.values()) {
if (worker instanceof Worker) {
return worker;
}
}
throw new InternalServerError(ErrorCode.UNIMPLEMENTED_EXCEPTION, ErrorDescription.UNIMPLEMENTED_EXCEPTION, `Worker ${Worker.name} not registered check common/registry.ts for more information`);
}
listen(callback) {
this.beforeStart();
const config = this.getConfig();
this._port = config.serverPort ?? ZeroantContext.PORT;
this._hostname = config.serverHostname ?? ZeroantContext.HOSTNAME;
const callbacks = this._servers.map((server) => server.callback());
this._server = createServer((req, res) => {
void (async (req, res) => {
for (const callback of callbacks) {
await callback(req, res);
}
})(req, res);
});
this._server.listen(this._port, this._hostname, () => {
this.onStart();
if (typeof callback === 'function') {
callback();
}
});
}
onStart() {
this.#event.emit(ZeroantEvent.START);
for (const plugin of this.plugin.values()) {
plugin.onStart();
}
for (const server of this._servers) {
server.onStart();
}
;
this.config.logging('info', () => {
console.info(new Date(), '[ZeroantContext]: Running On Port', this._port);
});
}
beforeStart() {
this.#event.emit(ZeroantEvent.BEFORE_START);
for (const plugin of this.plugin.values()) {
plugin.beforeStart();
}
for (const server of this._servers) {
server.beforeStart();
}
}
has(key) {
return this.#store.has(key);
}
#exiting = false;
async safeExit(code, signal, ts) {
this.#state = 'exiting';
if (this.#exiting) {
return;
}
this.#exiting = true;
if (signal !== undefined)
console.info(new Date(), '[ZeroantContext]:', `Received ${signal}.`);
await this.close(ts);
process.exit(code);
}
async close(ts) {
this.#state = 'closing';
this.#event.emit(ZeroantEvent.CLOSE);
const wait = [this.delay(ts ?? 0)];
for (const plugin of this.plugin.values()) {
wait.push(Promise.resolve().then(async () => {
await plugin.close();
}));
}
for (const server of this._servers) {
wait.push(Promise.resolve().then(async () => {
await server.close();
}));
}
wait.push(new Promise((resolve) => {
if (!this._server) {
resolve();
return;
}
this._server.close((err) => {
if (err != null) {
console.error(err.message);
}
resolve();
});
}));
await Promise.all(wait);
this.#state = 'closed';
this.config.logging('info', () => {
console.info(new Date(), '[ZeroantContext]: Stopped');
});
}
bootstrap(registry) {
if (this.hasRegistry) {
throw new InternalServerError(ErrorCode.SERVER_EXCEPTION, ErrorDescription.SERVER_EXCEPTION, `${new Date().toISOString()} Registry already bootstrap for zeroant and it can't be overridden`);
}
this.#registry = registry;
registry.bootstrap(this);
this.#event.emit(ZeroantEvent.BOOTSTRAP, this);
}
get hasRegistry() {
return ![null, undefined].includes(this.#registry);
}
get registry() {
if (!this.hasRegistry) {
throw new InternalServerError(ErrorCode.SERVER_EXCEPTION, ErrorDescription.SERVER_EXCEPTION, `${new Date().toISOString()} Registry not register for zeroant yet, please bootstrap before using registry`);
}
return this.#registry;
}
ready() {
this.#event.emit(ZeroantEvent.READY, this);
this.#registry.ready(this);
}
initServer(Server, registry) {
const server = new Server(this);
server.initialize(registry);
this._servers.push(server);
this.#store.set(`server:${Server.name}`, server);
}
getServer(Server) {
const server = this.#store.get(`server:${Server.name}`);
if (server === null || server === undefined) {
throw new InternalServerError(ErrorCode.SERVER_EXCEPTION, ErrorDescription.SERVER_EXCEPTION, `${Server.name} Server Not Init`);
}
return server;
}
async initPlugin(plugin) {
this.#store.set('plugin', plugin);
await plugin.initialize();
}
getPlugins() {
const plugin = this.#store.get('plugin');
if (plugin === null || plugin === undefined) {
throw new InternalServerError(ErrorCode.SERVER_EXCEPTION, ErrorDescription.SERVER_EXCEPTION, 'Plugin Not Init');
}
return plugin;
}
async initConfig(config) {
this.#store.set('config', config);
}
async initLogger(logger) {
this.#store.set('logger', logger);
}
get(name) {
const inst = this.#store.get(name);
if (inst === null || inst === undefined) {
throw new InternalServerError(ErrorCode.SERVER_EXCEPTION, ErrorDescription.SERVER_EXCEPTION, `Resources ${name} Not found`);
}
return inst;
}
set(name, value) {
if (this.has(name)) {
throw new InternalServerError(ErrorCode.SERVER_EXCEPTION, ErrorDescription.SERVER_EXCEPTION, `Can't Override Resources ${name}`);
}
this.#store.set(name, value);
return this;
}
getLogger() {
const logger = this.#store.get('logger');
if (logger === null || logger === undefined) {
throw new InternalServerError(ErrorCode.SERVER_EXCEPTION, ErrorDescription.SERVER_EXCEPTION, 'Logger Not Init');
}
return logger;
}
getConfig() {
const config = this.#store.get('config');
if (config === null || config === undefined) {
throw new InternalServerError(ErrorCode.SERVER_EXCEPTION, ErrorDescription.SERVER_EXCEPTION, 'Config Not Init');
}
return config;
}
getPlugin(addon) {
return this.plugin.get(addon);
}
get log() {
return this.getLogger();
}
get server() {
return this._server;
}
get state() {
return this.#state;
}
get plugin() {
return this.getPlugins();
}
get config() {
return this.getConfig();
}
on(eventName, listener) {
this.#event.on(eventName, listener);
return this;
}
once(eventName, listener) {
this.#event.once(eventName, listener);
return this;
}
off(eventName, listener) {
this.#event.off(eventName, listener);
return this;
}
removeListener(eventName, listener) {
this.#event.removeListener(eventName, listener);
return this;
}
removeAllListeners(eventName) {
this.#event.removeAllListeners(eventName);
return this;
}
rawListeners(eventName) {
this.#event.rawListeners(eventName);
return this;
}
emit(eventName, ...args) {
return this.#event.emit(eventName, ...args);
}
}
//# sourceMappingURL=zeroant.context.js.map