Skip to content

Commit

Permalink
Merge pull request #348 from mStirner/dev
Browse files Browse the repository at this point in the history
Split startup phases
  • Loading branch information
mStirner committed Nov 16, 2023
2 parents 2f73884 + d5ead04 commit d1edd64
Show file tree
Hide file tree
Showing 5 changed files with 289 additions and 283 deletions.
285 changes: 3 additions & 282 deletions index.js
Original file line number Diff line number Diff line change
@@ -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({
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -544,9 +268,6 @@ const starter = new Promise((resolve) => {

process.once("SIGINT", () => {
logger.warn("Shuting down...");
setTimeout(() => {
process.exit();
}, 1000);
});

});
2 changes: 1 addition & 1 deletion system/component/class.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
77 changes: 77 additions & 0 deletions system/init/init.components.js
Original file line number Diff line number Diff line change
@@ -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);

}
});

});
};
};
Loading

0 comments on commit d1edd64

Please sign in to comment.