From bad9712b14d641c06e3f2de8c442b6ef587ae0b8 Mon Sep 17 00:00:00 2001 From: mStirner Date: Thu, 16 Nov 2023 21:24:14 +0100 Subject: [PATCH] fix #87 --- index.js | 285 +--------------------------- system/component/class.component.js | 2 +- system/init/init.components.js | 77 ++++++++ system/init/init.database.js | 90 +++++++++ system/init/init.http-server.js | 118 ++++++++++++ 5 files changed, 289 insertions(+), 283 deletions(-) create mode 100644 system/init/init.components.js create mode 100644 system/init/init.database.js create mode 100644 system/init/init.http-server.js diff --git a/index.js b/index.js index 619c383..ce61883 100644 --- a/index.js +++ b/index.js @@ -1,13 +1,9 @@ const path = require("path"); -const http = require("http"); -const fs = require("fs"); const readline = require("readline"); const process = require("process"); -const mongodb = require("mongodb"); const pkg = require("./package.json"); const { exec } = require("child_process"); const uuid = require("uuid"); -const { URL } = require("url"); const env = require("dotenv").config({ @@ -141,281 +137,9 @@ if (process.env.GC_INTERVAL !== null && global.gc) { } -const init_db = () => { - return new Promise((resolve, reject) => { - - logger.debug("Init Database..."); - - let url = new URL(`mongodb://${process.env.DATABASE_HOST}:${process.env.DATABASE_PORT}/${process.env.DATABASE_NAME}`); - - if (process.env.DATABASE_AUTH_USERNAME) { - url.username = process.env.DATABASE_AUTH_USERNAME; - } - - if (process.env.DATABASE_AUTH_USERNAME) { - url.password = process.env.DATABASE_AUTH_PASSWORD; - } - - if (process.env.DATABASE_URL) { - console.log("OVerride DATBAASE_URL"); - Object.assign(url, new URL(process.env.DATABASE_URL)); - } - - // feedback - logger.verbose(`Connecting to "%s"...`, url.toString()); - - - mongodb.MongoClient.connect(url.toString(), { - useUnifiedTopology: true, - useNewUrlParser: true, - //connectTimeoutMS: Number(process.env.DATABASE_TIMEOUT) * 1000, // #9 - //socketTimeoutMS: Number(process.env.DATABASE_TIMEOUT) * 1000 // #9 - }, async (err, client) => { - - if (err) { - logger.error(err, "Could not connect to database"); - return reject(err); - } - - // monky patch db instance - // use this instance in other files - //mongodb.client = client.db(process.env.DATABASE_NAME); - mongodb.connection = client; - mongodb.client = client.db(); - - - client.on("error", (err) => { - logger.error(err, "Could not connecto to databse: %s", err.message); - }); - - client.on("close", () => { - process.exit(1000); - }); - - - try { - - // test authenticiation - // throws a error is auth is noc successfull - await mongodb.client.stats(); - - // feedback - logger.info(`Connected to "mongodb://${url.hostname}:${url.port}${url.pathname}"`); - - process.once("SIGINT", () => { - mongodb.connection.close(() => { - logger.info(`Connection closed from "mongodb://${url.hostname}:${url.port}${url.pathname}"`); - }); - }); - - resolve(); - - } catch (err) { - - if (err?.code == 13) { - logger.error("Invalid database credentials!"); - } - - client.emit("error", err); - reject(err); - - } - - - }); - - }); -}; - - -const init_components = () => { - return new Promise((resolve) => { - - logger.debug("Init components..."); - - const componentNames = [ - "devices", - "endpoints", - "plugins", - "rooms", - "ssdp", - "store", - "users", - "vault", - "webhooks", - "mqtt", - "mdns", - "scenes" - ].sort(() => { - - // pseudo randomize start/init of components - // https://stackoverflow.com/a/18650169/5781499 - return 0.5 - Math.random(); - - }); - - let componentConter = 0; - //let counter = componentNames.length; - - - // map over array - // create from each promise - // use Promise.all() ? - // better/quicker start? - componentNames.forEach((name) => { - try { - - // this should be trace method - logger.verbose(`Starting component "${name}"`); - - let component = require(`./components/${name}/index.js`); - - component.events.on("ready", () => { - - componentConter += 1; - - logger.debug(`Component "${name}" ready to use. (${componentConter}/${componentNames.length})`); - - if (componentConter === componentNames.length) { - logger.info(`All ${componentNames.length} Components ready`); - resolve(); - } - - }); - - // see issue #53, this should fire: - // the procces should not exit with a "unhandled execption" - // the try/catch block is for unhandled exception, not for startup errors - component.events.on("error", (err) => { - logger.error(err, `Component "${name}" error!`); - process.exit(1); // fix #53 - }); - - } catch (err) { - - console.error(err, "Component error"); - process.exit(800); - - } - }); - - }); -}; - - -const init_http = () => { - return new Promise((resolve, reject) => { - - logger.debug("Init http server..."); - - const servers = [ - - // http server for ip/port - new Promise((resolve, reject) => { - if (process.env.HTTP_ADDRESS !== "") { - - let server = http.createServer(); - - server.on("error", (err) => { - logger.error(err, `Could not start http server: ${err.message}`); - reject(err); - }); - - server.on("listening", () => { - - let addr = server.address(); - logger.info(`HTTP Server listening on http://${addr.address}:${addr.port}`); - - resolve(server); - - }); - - server.on("close", () => { - logger.info(`HTTP Server closed on http://${process.env.HTTP_ADDRESS}:${process.env.HTTP_PORT}`); - }); - - require("./routes")(server); - - // bind/start http server - server.listen(Number(process.env.HTTP_PORT), process.env.HTTP_ADDRESS); - - } else { - resolve(); - } - }), - - // http server fo unix socket - new Promise((resolve, reject) => { - if (process.env.HTTP_SOCKET !== "") { - - let server = http.createServer(); - - server.on("error", (err) => { - - logger.error(err, `Could not start http server: ${err.message}`); - reject(err); - - }); - - server.on("listening", () => { - - logger.info(`HTTP Server listening on ${process.env.HTTP_SOCKET}`); - - resolve(server); - - }); - - server.on("close", () => { - logger.info(`HTTP Server closed on ${process.env.HTTP_SOCKET}`); - }); - - require("./routes")(server); - - try { - - // cleanup - fs.unlinkSync(process.env.HTTP_SOCKET); - - } catch (err) { - if (err.code !== "ENOENT") { - - reject(err); - - } - } finally { - - // bind/start http server - server.listen(process.env.HTTP_SOCKET); - - } - - } else { - resolve(); - } - }) - - ]; - - Promise.all(servers).then((servers) => { - - process.once("SIGINT", () => { - servers.forEach((server) => { - server.close(); - }); - }); - - resolve(); - - }).catch((err) => { - - logger.error(err, "Could not start http server(s)", err); - - reject(err); - - }); - - }); -}; +const init_db = require("./system/init/init.database.js")(logger); +const init_components = require("./system/init/init.components.js")(logger); +const init_http = require("./system/init/init.http-server.js")(logger); // NOTE: Could/should be removed @@ -544,9 +268,6 @@ const starter = new Promise((resolve) => { process.once("SIGINT", () => { logger.warn("Shuting down..."); - setTimeout(() => { - process.exit(); - }, 1000); }); }); diff --git a/system/component/class.component.js b/system/component/class.component.js index 5abc169..b640008 100644 --- a/system/component/class.component.js +++ b/system/component/class.component.js @@ -47,7 +47,7 @@ module.exports = class COMPONENT extends COMMON { constructor(name, schema, parent) { if (parent) { - require("../prevent_cross_load")(parent); + //require("../prevent_cross_load")(parent); } super(require("../../system/logger").create(name)); diff --git a/system/init/init.components.js b/system/init/init.components.js new file mode 100644 index 0000000..513e018 --- /dev/null +++ b/system/init/init.components.js @@ -0,0 +1,77 @@ +const path = require("path"); + +module.exports = (logger) => { + return () => { + return new Promise((resolve) => { + + logger.debug("Init components..."); + + const componentNames = [ + "devices", + "endpoints", + "plugins", + "rooms", + "ssdp", + "store", + "users", + "vault", + "webhooks", + "mqtt", + "mdns", + "scenes" + ].sort(() => { + + // pseudo randomize start/init of components + // https://stackoverflow.com/a/18650169/5781499 + return 0.5 - Math.random(); + + }); + + let componentConter = 0; + //let counter = componentNames.length; + + + // map over array + // create from each promise + // use Promise.all() ? + // better/quicker start? + componentNames.forEach((name) => { + try { + + // this should be trace method + logger.verbose(`Starting component "${name}"`); + + let component = require(path.resolve(process.cwd(), `components/${name}/index.js`)); + + component.events.on("ready", () => { + + componentConter += 1; + + logger.debug(`Component "${name}" ready to use. (${componentConter}/${componentNames.length})`); + + if (componentConter === componentNames.length) { + logger.info(`All ${componentNames.length} Components ready`); + resolve(); + } + + }); + + // see issue #53, this should fire: + // the procces should not exit with a "unhandled execption" + // the try/catch block is for unhandled exception, not for startup errors + component.events.on("error", (err) => { + logger.error(err, `Component "${name}" error!`); + process.exit(1); // fix #53 + }); + + } catch (err) { + + console.error(err, "Component error"); + process.exit(800); + + } + }); + + }); + }; +}; \ No newline at end of file diff --git a/system/init/init.database.js b/system/init/init.database.js new file mode 100644 index 0000000..a77a96f --- /dev/null +++ b/system/init/init.database.js @@ -0,0 +1,90 @@ +const mongodb = require("mongodb"); +const { URL } = require("url"); + +module.exports = (logger) => { + return () => { + return new Promise((resolve, reject) => { + + logger.debug("Init Database..."); + + let url = new URL(`mongodb://${process.env.DATABASE_HOST}:${process.env.DATABASE_PORT}/${process.env.DATABASE_NAME}`); + + if (process.env.DATABASE_AUTH_USERNAME) { + url.username = process.env.DATABASE_AUTH_USERNAME; + } + + if (process.env.DATABASE_AUTH_USERNAME) { + url.password = process.env.DATABASE_AUTH_PASSWORD; + } + + if (process.env.DATABASE_URL) { + console.log("OVerride DATBAASE_URL"); + Object.assign(url, new URL(process.env.DATABASE_URL)); + } + + // feedback + logger.verbose(`Connecting to "mongodb://${url.hostname}:${url.port}${url.pathname}"...`); + + + mongodb.MongoClient.connect(url.toString(), { + useUnifiedTopology: true, + useNewUrlParser: true, + //connectTimeoutMS: Number(process.env.DATABASE_TIMEOUT) * 1000, // #9 + //socketTimeoutMS: Number(process.env.DATABASE_TIMEOUT) * 1000 // #9 + }, async (err, client) => { + + if (err) { + logger.error(err, "Could not connect to database"); + return reject(err); + } + + // monky patch db instance + // use this instance in other files + //mongodb.client = client.db(process.env.DATABASE_NAME); + mongodb.connection = client; + mongodb.client = client.db(); + + + client.on("error", (err) => { + logger.error(err, "Could not connecto to databse: %s", err.message); + }); + + client.on("close", () => { + process.exit(1000); + }); + + + try { + + // test authenticiation + // throws a error is auth is noc successfull + await mongodb.client.stats(); + + // feedback + logger.info(`Connected to "mongodb://${url.hostname}:${url.port}${url.pathname}"`); + + process.once("SIGINT", () => { + mongodb.connection.close(() => { + logger.info(`Connection closed from "mongodb://${url.hostname}:${url.port}${url.pathname}"`); + }); + }); + + resolve(); + + } catch (err) { + + if (err?.code == 13) { + logger.error("Invalid database credentials!"); + } + + client.emit("error", err); + reject(err); + + } + + + }); + + }); + }; +}; \ No newline at end of file diff --git a/system/init/init.http-server.js b/system/init/init.http-server.js new file mode 100644 index 0000000..b6f8daf --- /dev/null +++ b/system/init/init.http-server.js @@ -0,0 +1,118 @@ +const http = require("http"); +const fs = require("fs"); + +module.exports = (logger) => { + return () => { + return new Promise((resolve, reject) => { + + logger.debug("Init http server..."); + + const servers = [ + + // http server for ip/port + new Promise((resolve, reject) => { + if (process.env.HTTP_ADDRESS !== "") { + + let server = http.createServer(); + + server.on("error", (err) => { + logger.error(err, `Could not start http server: ${err.message}`); + reject(err); + }); + + server.on("listening", () => { + + let addr = server.address(); + logger.info(`HTTP Server listening on http://${addr.address}:${addr.port}`); + + resolve(server); + + }); + + server.on("close", () => { + logger.info(`HTTP Server closed on http://${process.env.HTTP_ADDRESS}:${process.env.HTTP_PORT}`); + }); + + require("../../routes/index.js")(server); + + // bind/start http server + server.listen(Number(process.env.HTTP_PORT), process.env.HTTP_ADDRESS); + + } else { + resolve(); + } + }), + + // http server for unix socket + new Promise((resolve, reject) => { + if (process.env.HTTP_SOCKET !== "") { + + let server = http.createServer(); + + server.on("error", (err) => { + + logger.error(err, `Could not start http server: ${err.message}`); + reject(err); + + }); + + server.on("listening", () => { + + logger.info(`HTTP Server listening on ${process.env.HTTP_SOCKET}`); + + resolve(server); + + }); + + server.on("close", () => { + logger.info(`HTTP Server closed on ${process.env.HTTP_SOCKET}`); + }); + + require("../../routes/index.js")(server); + + try { + + // cleanup + fs.unlinkSync(process.env.HTTP_SOCKET); + + } catch (err) { + if (err.code !== "ENOENT") { + + reject(err); + + } + } finally { + + // bind/start http server + server.listen(process.env.HTTP_SOCKET); + + } + + } else { + resolve(); + } + }) + + ]; + + Promise.all(servers).then((servers) => { + + process.once("SIGINT", () => { + servers.forEach((server) => { + server.close(); + }); + }); + + resolve(); + + }).catch((err) => { + + logger.error(err, "Could not start http server(s)", err); + + reject(err); + + }); + + }); + }; +}; \ No newline at end of file