cangku/backend/src/services/systemDbConfig.js

228 lines
6.6 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const mysql = require('mysql2/promise');
const dotenv = require('dotenv');
dotenv.config();
dotenv.config({ path: path.resolve(__dirname, '../../.env') });
dotenv.config({ path: path.resolve(__dirname, '../.env') });
const DEFAULT_SYSTEM_DB_CONFIG = {
driver: 'mysql',
host: '',
port: 3306,
database: '',
username: '',
hasPassword: false,
};
const ENV_MAPPING = {
driver: 'LOCAL_DB_TYPE',
host: 'LOCAL_DB_HOST',
port: 'LOCAL_DB_PORT',
database: 'LOCAL_DB_NAME',
username: 'LOCAL_DB_USER',
password: 'LOCAL_DB_PASSWORD',
};
function getEnvFilePath() {
return path.resolve(process.cwd(), '.env');
}
function getStoredConfigFilePath() {
return path.resolve(process.cwd(), 'database', 'system-db.config.json');
}
function serializeEnvValue(value) {
const stringValue = String(value ?? '');
if (!stringValue) {
return '';
}
if (/[\s#"']/u.test(stringValue)) {
return JSON.stringify(stringValue);
}
return stringValue;
}
function parseConfigFromEnv(source) {
return {
driver: source[ENV_MAPPING.driver] || DEFAULT_SYSTEM_DB_CONFIG.driver,
host: source[ENV_MAPPING.host] || DEFAULT_SYSTEM_DB_CONFIG.host,
port: Number(source[ENV_MAPPING.port] || DEFAULT_SYSTEM_DB_CONFIG.port),
database: source[ENV_MAPPING.database] || DEFAULT_SYSTEM_DB_CONFIG.database,
username: source[ENV_MAPPING.username] || DEFAULT_SYSTEM_DB_CONFIG.username,
hasPassword: Boolean(source[ENV_MAPPING.password]),
};
}
function parseRuntimeConfig(source) {
return {
driver: source[ENV_MAPPING.driver] || DEFAULT_SYSTEM_DB_CONFIG.driver,
host: source[ENV_MAPPING.host] || DEFAULT_SYSTEM_DB_CONFIG.host,
port: Number(source[ENV_MAPPING.port] || DEFAULT_SYSTEM_DB_CONFIG.port),
database: source[ENV_MAPPING.database] || DEFAULT_SYSTEM_DB_CONFIG.database,
username: source[ENV_MAPPING.username] || DEFAULT_SYSTEM_DB_CONFIG.username,
password: source[ENV_MAPPING.password] || '',
};
}
function hasCompleteConfig(config) {
return Boolean(
config
&& String(config.host || '').trim()
&& String(config.database || '').trim()
&& String(config.username || '').trim()
);
}
function readStoredConfigFile() {
const filePath = getStoredConfigFilePath();
if (!fs.existsSync(filePath)) {
return null;
}
try {
const raw = fs.readFileSync(filePath, 'utf8');
const parsed = JSON.parse(raw);
return {
driver: parsed.driver || DEFAULT_SYSTEM_DB_CONFIG.driver,
host: parsed.host || '',
port: Number(parsed.port || DEFAULT_SYSTEM_DB_CONFIG.port),
database: parsed.database || '',
username: parsed.username || '',
password: parsed.password || '',
};
} catch (_error) {
return null;
}
}
function writeStoredConfigFile(input) {
const filePath = getStoredConfigFilePath();
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, JSON.stringify({
driver: input.driver || DEFAULT_SYSTEM_DB_CONFIG.driver,
host: input.host || '',
port: Number(input.port || DEFAULT_SYSTEM_DB_CONFIG.port),
database: input.database || '',
username: input.username || '',
password: input.password || '',
}, null, 2), 'utf8');
}
function getSystemDbRuntimeConfig() {
const envConfig = parseRuntimeConfig(process.env);
if (hasCompleteConfig(envConfig)) {
return envConfig;
}
const storedConfig = readStoredConfigFile();
if (hasCompleteConfig(storedConfig || {})) {
return storedConfig;
}
return envConfig;
}
function getSystemDbConfig() {
const runtimeConfig = getSystemDbRuntimeConfig();
return {
driver: runtimeConfig.driver || DEFAULT_SYSTEM_DB_CONFIG.driver,
host: runtimeConfig.host || DEFAULT_SYSTEM_DB_CONFIG.host,
port: Number(runtimeConfig.port || DEFAULT_SYSTEM_DB_CONFIG.port),
database: runtimeConfig.database || DEFAULT_SYSTEM_DB_CONFIG.database,
username: runtimeConfig.username || DEFAULT_SYSTEM_DB_CONFIG.username,
hasPassword: Boolean(runtimeConfig.password),
};
}
async function testSystemDbConnection(input) {
const connection = await mysql.createConnection({
host: input.host,
port: Number(input.port || 3306),
user: input.username,
password: input.password,
database: input.database,
charset: 'utf8mb4',
connectTimeout: 10000,
});
await connection.ping();
await connection.end();
}
async function saveSystemDbConfig(input) {
const envFilePath = getEnvFilePath();
const content = fs.existsSync(envFilePath) ? fs.readFileSync(envFilePath, 'utf8') : '';
const parsedEnv = dotenv.parse(content);
const nextEnv = {
...parsedEnv,
[ENV_MAPPING.driver]: input.driver || DEFAULT_SYSTEM_DB_CONFIG.driver,
[ENV_MAPPING.host]: input.host || '',
[ENV_MAPPING.port]: String(input.port || 3306),
[ENV_MAPPING.database]: input.database || '',
[ENV_MAPPING.username]: input.username || '',
};
if (input.password) {
nextEnv[ENV_MAPPING.password] = input.password;
} else if (!nextEnv[ENV_MAPPING.password]) {
nextEnv[ENV_MAPPING.password] = '';
}
const lines = content ? content.split(/\r?\n/) : [];
const handledKeys = new Set();
const nextLines = lines.map((line) => {
const match = line.match(/^([A-Z0-9_]+)=(.*)$/);
if (!match) {
return line;
}
const [, key] = match;
if (!Object.values(ENV_MAPPING).includes(key)) {
return line;
}
handledKeys.add(key);
return `${key}=${serializeEnvValue(nextEnv[key])}`;
});
for (const key of Object.values(ENV_MAPPING)) {
if (!handledKeys.has(key)) {
nextLines.push(`${key}=${serializeEnvValue(nextEnv[key])}`);
}
}
const nextContent = `${nextLines.filter((line, index, array) => !(line === '' && index === array.length - 1)).join('\n')}\n`;
fs.writeFileSync(envFilePath, nextContent, 'utf8');
process.env[ENV_MAPPING.driver] = nextEnv[ENV_MAPPING.driver];
process.env[ENV_MAPPING.host] = nextEnv[ENV_MAPPING.host];
process.env[ENV_MAPPING.port] = nextEnv[ENV_MAPPING.port];
process.env[ENV_MAPPING.database] = nextEnv[ENV_MAPPING.database];
process.env[ENV_MAPPING.username] = nextEnv[ENV_MAPPING.username];
if (input.password) {
process.env[ENV_MAPPING.password] = input.password;
}
writeStoredConfigFile({
driver: nextEnv[ENV_MAPPING.driver],
host: nextEnv[ENV_MAPPING.host],
port: nextEnv[ENV_MAPPING.port],
database: nextEnv[ENV_MAPPING.database],
username: nextEnv[ENV_MAPPING.username],
password: input.password || nextEnv[ENV_MAPPING.password] || '',
});
return getSystemDbConfig();
}
module.exports = {
getSystemDbConfig,
getSystemDbRuntimeConfig,
saveSystemDbConfig,
testSystemDbConnection,
};