feat: 配置文件机制修改,优化WebUI日志排列

This commit is contained in:
foxhui
2025-12-23 03:14:02 +08:00
Unverified
parent ce72c5f9ec
commit d75c84f4c5
27 changed files with 275 additions and 426 deletions
+63 -9
View File
@@ -13,11 +13,65 @@ import yaml from 'yaml';
import { logger } from '../utils/logger.js';
const CONFIG_PATH = path.join(process.cwd(), 'config.yaml');
// --- 配置文件路径常量 ---
const DATA_DIR = path.join(process.cwd(), 'data');
const DATA_CONFIG_PATH = path.join(DATA_DIR, 'config.yaml');
const ROOT_CONFIG_PATH = path.join(process.cwd(), 'config.yaml');
const EXAMPLE_CONFIG_PATH = path.join(process.cwd(), 'config.example.yaml');
// 模块级缓存:确保配置只从磁盘读取一次
let cachedConfig = null;
// 实际使用的配置文件路径
let activeConfigPath = null;
/**
* 解析配置文件路径(优先级:data/config.yaml > config.yaml > 从 config.example.yaml 复制)
* 自动迁移:如果只有根目录 config.yaml,会自动移动到 data/config.yaml
* @returns {string} 配置文件路径
*/
function resolveConfigPath() {
// 1. 优先使用 data/config.yaml
if (fs.existsSync(DATA_CONFIG_PATH)) {
return DATA_CONFIG_PATH;
}
// 2. 根目录有 config.yaml,自动迁移到 data/config.yaml
if (fs.existsSync(ROOT_CONFIG_PATH)) {
// 确保 data 目录存在
if (!fs.existsSync(DATA_DIR)) {
fs.mkdirSync(DATA_DIR, { recursive: true });
}
// 移动文件到 data 目录
fs.renameSync(ROOT_CONFIG_PATH, DATA_CONFIG_PATH);
logger.info('配置器', `已将 ${ROOT_CONFIG_PATH} 迁移到 ${DATA_CONFIG_PATH}`);
return DATA_CONFIG_PATH;
}
// 3. 两个都没有,从 config.example.yaml 复制到 data/config.yaml
if (fs.existsSync(EXAMPLE_CONFIG_PATH)) {
// 确保 data 目录存在
if (!fs.existsSync(DATA_DIR)) {
fs.mkdirSync(DATA_DIR, { recursive: true });
}
fs.copyFileSync(EXAMPLE_CONFIG_PATH, DATA_CONFIG_PATH);
logger.info('配置器', `已从 ${EXAMPLE_CONFIG_PATH} 复制配置到 ${DATA_CONFIG_PATH}`);
return DATA_CONFIG_PATH;
}
// 4. 都没有,返回 data/config.yaml 路径(后续会抛出错误)
return DATA_CONFIG_PATH;
}
/**
* 获取当前使用的配置文件路径
* @returns {string} 配置文件路径
*/
export function getConfigPath() {
if (!activeConfigPath) {
activeConfigPath = resolveConfigPath();
}
return activeConfigPath;
}
/**
* 解析用户数据目录路径
@@ -147,17 +201,17 @@ export function loadConfig() {
// 如果已有缓存,直接返回
if (cachedConfig) return cachedConfig;
if (!fs.existsSync(CONFIG_PATH)) {
const hint = fs.existsSync(EXAMPLE_CONFIG_PATH)
? `请复制 ${EXAMPLE_CONFIG_PATH}${CONFIG_PATH}`
: `请创建 ${CONFIG_PATH}(仓库根目录通常提供 config.example.yaml 作为模板)`;
throw new Error(`未找到配置文件: ${CONFIG_PATH}${hint}`);
// 解析配置文件路径(带优先级和自动复制逻辑)
const configPath = getConfigPath();
if (!fs.existsSync(configPath)) {
throw new Error(`未找到配置文件: ${configPath}请确保 data/config.yaml、config.yaml 或 config.example.yaml 存在。`);
}
const configFile = fs.readFileSync(CONFIG_PATH, 'utf8');
const configFile = fs.readFileSync(configPath, 'utf8');
let config = yaml.parse(configFile);
if (!config || typeof config !== 'object') {
throw new Error(`配置文件解析失败: ${CONFIG_PATH}`);
throw new Error(`配置文件解析失败: ${configPath}`);
}
// Docker 路径兼容处理
@@ -265,7 +319,7 @@ export function loadConfig() {
}
// 日志输出
logger.debug('配置器', '已加载 config.yaml');
logger.debug('配置器', `已加载配置文件: ${configPath}`);
logger.debug('配置器', `Instances: ${config.backend.pool.instances.length}, Workers: ${config.backend.pool.workers.length}`);
logger.debug('配置器', `调度策略: ${config.backend.pool.strategy}`);
logger.debug('配置器', `流式心跳模式: ${config.server.keepalive.mode}`);
+7 -6
View File
@@ -7,18 +7,18 @@ import fs from 'fs';
import path from 'path';
import yaml from 'yaml';
import { logger } from '../utils/logger.js';
const CONFIG_PATH = path.join(process.cwd(), 'config.yaml');
import { getConfigPath } from './index.js';
/**
* 读取原始配置(不带缓存,直接从磁盘读取)
* @returns {object} 原始配置对象
*/
function readRawConfig() {
if (!fs.existsSync(CONFIG_PATH)) {
const configPath = getConfigPath();
if (!fs.existsSync(configPath)) {
throw new Error('配置文件不存在');
}
const content = fs.readFileSync(CONFIG_PATH, 'utf8');
const content = fs.readFileSync(configPath, 'utf8');
return yaml.parse(content);
}
@@ -27,13 +27,14 @@ function readRawConfig() {
* @param {object} config - 完整配置对象
*/
function writeConfig(config) {
const configPath = getConfigPath();
// 使用 yaml 库的默认序列化(会丢失注释,但结构正确)
const content = yaml.stringify(config, {
indent: 2,
lineWidth: 0 // 不自动换行
});
fs.writeFileSync(CONFIG_PATH, content, 'utf8');
logger.info('管理器', '配置已保存到 config.yaml');
fs.writeFileSync(configPath, content, 'utf8');
logger.info('管理器', `配置已保存到 ${configPath}`);
}
/**
@@ -7,7 +7,7 @@ import fs from 'fs';
import path from 'path';
import os from 'os';
import crypto from 'crypto';
import { logger } from './logger.js';
import { logger } from '../utils/logger.js';
const PROJECT_ROOT = process.cwd();
+1 -1
View File
@@ -18,7 +18,7 @@
import http from 'http';
// ==================== 启动前自检 ====================
import { runPreflight } from '../utils/preflight.js';
import { runPreflight } from './preflight.js';
runPreflight();
// ==================== 加载其他依赖 ====================
const { getBackend } = await import('../backend/index.js');
+4 -1
View File
@@ -118,7 +118,10 @@ export function log(level, mod, msg, meta = {}) {
const ts = formatTime();
const levelMap = { debug: 'DBUG', info: 'INFO', warn: 'WARN', error: 'ERRO' };
const levelTag = levelMap[level.toLowerCase()] || level.toUpperCase().slice(0, 4);
const base = `${ts} [${levelTag}] [${mod}] ${msg}`;
// 将消息中的换行符替换为 ↵ 符号,保持日志为单行
const sanitizedMsg = msg.replace(/\r?\n/g, ' ↵ ');
const base = `${ts} [${levelTag}] [${mod}] ${sanitizedMsg}`;
const metaStr = Object.keys(meta).length
? ' | ' + Object.entries(meta).map(([k, v]) => {