const fs = require('fs'); const path = require('path'); /** * 配置文件生成器 * 根据应用实际安装路径生成Spring Boot配置文件 */ class ConfigGenerator { constructor() { // 开发环境:项目根目录 // 打包后:应用根目录(win-unpacked) const isDev = !process.resourcesPath; const baseDir = isDev ? path.join(__dirname, '..') : path.dirname(process.resourcesPath); // 开发环境:build/extraResources/java // 打包后:resources/extraResources/java this.javaPath = isDev ? path.join(baseDir, 'build', 'extraResources', 'java') : path.join(process.resourcesPath, 'extraResources', 'java'); this.templatePath = path.join(this.javaPath, 'application.yml.template'); this.configPath = path.join(this.javaPath, 'application.yml'); // 数据目录(使用应用所在盘符的根目录下的data文件夹) this.dataPath = this.getDataPath(baseDir); } /** * 获取数据目录路径 * @param {string} baseDir 应用基础目录 * @returns {string} 数据目录路径 */ getDataPath(baseDir) { // 数据目录设置在应用目录内的 NPQS9100_Data 文件夹 return path.join(baseDir, 'NPQS9100_Data'); } /** * 生成配置文件 * @param {object} options - 配置选项 * @param {number} options.mysqlPort - MySQL 端口 * @param {number} options.javaPort - Java 应用端口 * @param {number} options.websocketPort - WebSocket 端口 * @param {string} options.mysqlPassword - MySQL 密码 */ generateConfig(options = {}) { return new Promise((resolve, reject) => { try { // 读取模板文件 if (!fs.existsSync(this.templatePath)) { throw new Error(`Template file not found: ${this.templatePath}`); } let template = fs.readFileSync(this.templatePath, 'utf-8'); // 替换占位符 // Windows路径需要转义反斜杠 const dataPathEscaped = this.dataPath.replace(/\\/g, '\\\\'); template = template.replace(/\{\{APP_DATA_PATH\}\}/g, dataPathEscaped); // 替换MySQL密码 const mysqlPassword = options.mysqlPassword || 'njcnpqs'; template = template.replace(/\{\{MYSQL_PASSWORD\}\}/g, mysqlPassword); // 替换端口(如果提供) if (options.mysqlPort) { // 支持两种格式:localhost:3306 和 {{MYSQL_PORT}} template = template.replace(/\{\{MYSQL_PORT\}\}/g, options.mysqlPort); template = template.replace(/localhost:3306/g, `localhost:${options.mysqlPort}`); } if (options.javaPort) { template = template.replace(/port:\s*18092/g, `port: ${options.javaPort}`); } // 替换 WebSocket 端口 if (options.websocketPort) { template = template.replace(/port:\s*7777/g, `port: ${options.websocketPort}`); } // 写入配置文件 fs.writeFileSync(this.configPath, template, 'utf-8'); // 创建必要的目录 this.createDirectories(); console.log('[ConfigGenerator] Configuration file generated successfully'); console.log('[ConfigGenerator] Data path:', this.dataPath); console.log('[ConfigGenerator] MySQL port:', options.mysqlPort || 3306); console.log('[ConfigGenerator] MySQL password:', options.mysqlPassword || 'njcnpqs'); console.log('[ConfigGenerator] Java port:', options.javaPort || 18093); console.log('[ConfigGenerator] WebSocket port:', options.websocketPort || 7778); resolve({ configPath: this.configPath, dataPath: this.dataPath, mysqlPort: options.mysqlPort || 3306, javaPort: options.javaPort || 18093, websocketPort: options.websocketPort || 7778 }); } catch (error) { console.error('[ConfigGenerator] Failed to generate config:', error); reject(error); } }); } /** * 创建必要的目录 */ createDirectories() { const dirs = [ this.dataPath, path.join(this.dataPath, 'logs'), path.join(this.dataPath, 'template'), path.join(this.dataPath, 'report'), path.join(this.dataPath, 'data') ]; dirs.forEach(dir => { if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); console.log('[ConfigGenerator] Created directory:', dir); } }); // 复制内置的报告模板文件 this.copyBuiltInTemplates(); } /** * 复制内置的报告模板文件到用户数据目录 */ copyBuiltInTemplates() { try { const isDev = !process.resourcesPath; const baseDir = isDev ? path.join(__dirname, '..') : path.dirname(process.resourcesPath); // 内置模板源路径 const templateSource = isDev ? path.join(baseDir, 'build', 'extraResources', 'templates') : path.join(process.resourcesPath, 'extraResources', 'templates'); // 目标路径:用户数据目录/template/ const templateDest = path.join(this.dataPath, 'template'); // 检查源模板是否存在 if (!fs.existsSync(templateSource)) { console.log('[ConfigGenerator] Built-in templates not found, skipping copy'); return; } // 递归复制模板文件(只复制不存在的文件,不覆盖已有文件) this.copyTemplatesRecursive(templateSource, templateDest); console.log('[ConfigGenerator] Built-in templates copied successfully'); } catch (error) { console.error('[ConfigGenerator] Failed to copy templates:', error); } } /** * 递归复制模板文件(不覆盖已存在的文件) * @param {string} src 源目录 * @param {string} dest 目标目录 */ copyTemplatesRecursive(src, dest) { // 确保目标目录存在 if (!fs.existsSync(dest)) { fs.mkdirSync(dest, { recursive: true }); } // 读取源目录内容 const entries = fs.readdirSync(src, { withFileTypes: true }); entries.forEach(entry => { const srcPath = path.join(src, entry.name); const destPath = path.join(dest, entry.name); if (entry.isDirectory()) { // 递归复制子目录 this.copyTemplatesRecursive(srcPath, destPath); } else { // 只复制不存在的文件(不覆盖用户修改过的文件) if (!fs.existsSync(destPath)) { fs.copyFileSync(srcPath, destPath); console.log('[ConfigGenerator] Copied template:', destPath); } else { console.log('[ConfigGenerator] Template already exists, skipping:', destPath); } } }); } /** * 获取配置信息 */ getConfigInfo() { return { javaPath: this.javaPath, templatePath: this.templatePath, configPath: this.configPath, dataPath: this.dataPath }; } } module.exports = ConfigGenerator;