This commit is contained in:
Louis Lam
2023-02-05 17:45:36 +08:00
parent 33d9c1bbb1
commit dc4d2a77bb
9 changed files with 171 additions and 69 deletions

View File

@@ -6,6 +6,7 @@ const dayjs = require("dayjs");
const knex = require("knex");
const { PluginsManager } = require("./plugins-manager");
const path = require("path");
const { EmbeddedMariaDB } = require("./embedded-mariadb");
/**
* Database & App Data Folder
@@ -123,10 +124,20 @@ class Database {
let dbConfig;
try {
dbConfig = fs.readFileSync(path.join(Database.dataDir, "db-config.json"));
let dbConfigString = fs.readFileSync(path.join(Database.dataDir, "db-config.json")).toString("utf-8");
dbConfig = JSON.parse(dbConfigString);
if (typeof dbConfig !== "object") {
throw new Error("Invalid db-config.json, it must be an object");
}
if (typeof dbConfig.type !== "string") {
throw new Error("Invalid db-config.json, type must be a string");
}
} catch (_) {
dbConfig = {
type: "sqlite",
//type: "sqlite",
type: "embedded-mariadb",
};
}
@@ -151,19 +162,20 @@ class Database {
acquireTimeoutMillis: acquireConnectionTimeout,
}
};
} else if (dbConfig === "embedded-mariadb") {
} else if (dbConfig.type === "embedded-mariadb") {
let embeddedMariaDB = EmbeddedMariaDB.getInstance();
await embeddedMariaDB.start();
log.info("mariadb", "Embedded MariaDB started");
config = {
client: "mysql",
client: "mysql2",
connection: {
host: "127.0.0.1",
port: 3306,
user: "your_database_user",
password: "your_database_password",
socketPath: embeddedMariaDB.socketPath,
user: "node",
database: "kuma"
}
};
} else {
throw new Error("Unknown Database type");
throw new Error("Unknown Database type: " + dbConfig.type);
}
const knexInstance = knex(config);

View File

@@ -1,47 +1,131 @@
const { log } = require("../src/util");
const childProcess = require("child_process");
const fs = require("fs");
/**
* It is only used inside the docker container
*/
class EmbeddedMariaDB {
static childProcess = null;
static running = false;
static instance = null;
static init() {
exec = "mariadbd";
mariadbDataDir = "/app/data/mariadb";
runDir = "/app/data/run/mariadb";
socketPath = this.runDir + "/mysqld.sock";
childProcess = null;
running = false;
started = false;
/**
*
* @returns {EmbeddedMariaDB}
*/
static getInstance() {
if (!EmbeddedMariaDB.instance) {
EmbeddedMariaDB.instance = new EmbeddedMariaDB();
}
return EmbeddedMariaDB.instance;
}
static start() {
static hasInstance() {
return !!EmbeddedMariaDB.instance;
}
/**
*
*/
start() {
if (this.childProcess) {
log.log("mariadb", "Already started");
log.info("mariadb", "Already started");
return;
}
if (!fs.existsSync(this.mariadbDataDir)) {
log.info("mariadb", `Embedded MariaDB: ${this.mariadbDataDir} is not found, create one now.`);
fs.mkdirSync(this.mariadbDataDir, {
recursive: true,
});
let result = childProcess.spawnSync("mysql_install_db", [
"--user=node",
"--ldata=" + this.mariadbDataDir,
]);
if (result.status !== 0) {
let error = result.stderr.toString("utf-8");
log.error("mariadb", error);
return;
} else {
log.info("mariadb", "Embedded MariaDB: mysql_install_db done:" + result.stdout.toString("utf-8"));
}
}
if (!fs.existsSync(this.runDir)) {
log.info("mariadb", `Embedded MariaDB: ${this.runDir} is not found, create one now.`);
fs.mkdirSync(this.runDir, {
recursive: true,
});
}
this.running = true;
this.emitChange("Starting cloudflared");
this.childProcess = childProcess.spawn(this.cloudflaredPath, args);
this.childProcess.stdout.pipe(process.stdout);
this.childProcess.stderr.pipe(process.stderr);
log.info("mariadb", "Starting Embedded MariaDB");
this.childProcess = childProcess.spawn(this.exec, [
"--user=node",
"--datadir=" + this.mariadbDataDir,
`--socket=${this.socketPath}`,
`--pid-file=${this.runDir}/mysqld.pid`,
]);
this.childProcess.on("close", (code) => {
this.running = false;
this.childProcess = null;
this.emitChange("Stopped cloudflared", code);
this.started = false;
log.info("mariadb", "Stopped Embedded MariaDB: " + code);
if (code !== 0) {
log.info("mariadb", "Try to restart Embedded MariaDB as it is not stopped by user");
this.start();
}
});
this.childProcess.on("error", (err) => {
if (err.code === "ENOENT") {
this.emitError(`Cloudflared error: ${this.cloudflaredPath} is not found`);
log.error("mariadb", `Embedded MariaDB: ${this.exec} is not found`);
} else {
this.emitError(err);
log.error("mariadb", err);
}
});
this.childProcess.stderr.on("data", (data) => {
this.emitError(data.toString());
let handler = (data) => {
log.debug("mariadb", data.toString("utf-8"));
if (data.toString("utf-8").includes("ready for connections")) {
log.info("mariadb", "Embedded MariaDB is ready for connections");
this.started = true;
}
};
this.childProcess.stdout.on("data", handler);
this.childProcess.stderr.on("data", handler);
return new Promise((resolve) => {
let interval = setInterval(() => {
if (this.started) {
clearInterval(interval);
resolve();
} else {
log.info("mariadb", "Waiting for Embedded MariaDB to start...");
}
}, 1000);
});
}
static stop() {
stop() {
if (this.childProcess) {
this.childProcess.kill("SIGINT");
this.childProcess = null;
@@ -49,3 +133,7 @@ class EmbeddedMariaDB {
}
}
module.exports = {
EmbeddedMariaDB,
};