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, };