crystelf-plugin/lib/config/configControl.js

234 lines
6.8 KiB
JavaScript

import Path, { defaultConfig } from '../../constants/path.js';
import path from 'path';
import fs from 'fs';
import fc from '../../components/json.js';
const fsp = fs.promises;
const pluginConfigPath = Path.defaultConfigPath;
const dataConfigPath = Path.config;
const configFile = path.join(dataConfigPath, 'config.json');
let configCache = {};
let watchers = [];
/**
* 初始化配置
*/
async function init() {
try {
// 确保数据配置目录存在
try {
await fsp.access(dataConfigPath);
} catch {
await fsp.mkdir(dataConfigPath, { recursive: true });
logger.mark(`[crystelf-plugin] 配置目录创建成功: ${dataConfigPath}`);
}
// 确保默认配置目录存在
try {
await fsp.access(pluginConfigPath);
} catch {
logger.warn(`[crystelf-plugin] 默认配置目录不存在: ${pluginConfigPath}`);
}
// 处理主配置文件
const pluginDefaultFile = path.join(pluginConfigPath, 'config.json');
try {
await fsp.access(configFile);
} catch {
try {
await fsp.copyFile(pluginDefaultFile, configFile);
logger.mark(`[crystelf-plugin] 默认配置复制成功: ${configFile}`);
} catch (copyError) {
logger.warn(`[crystelf-plugin] 复制默认配置失败,创建空配置: ${copyError}`);
await fc.writeJSON(configFile, {});
}
}
let pluginFiles = [];
try {
pluginFiles = (await fsp.readdir(pluginConfigPath)).filter((f) => f.endsWith('.json'));
} catch (error) {
logger.warn(`[crystelf-plugin] 读取默认配置目录失败: ${error}`);
}
// 复制缺失的配置文件
for (const file of pluginFiles) {
const pluginFilePath = path.join(pluginConfigPath, file);
const dataFilePath = path.join(dataConfigPath, file);
try {
await fsp.access(dataFilePath);
} catch {
try {
await fsp.copyFile(pluginFilePath, dataFilePath);
logger.mark(`[crystelf-plugin] 配置文件缺失,已复制: ${file}`);
} catch (copyError) {
logger.warn(`[crystelf-plugin] 复制配置文件失败 ${file}: ${copyError}`);
}
}
}
// 读取所有配置文件
const files = (await fsp.readdir(dataConfigPath)).filter((f) => f.endsWith('.json'));
configCache = {};
for (const file of files) {
const filePath = path.join(dataConfigPath, file);
const name = path.basename(file, '.json');
try {
let data = await fc.readJSON(filePath);
const pluginFilePath = path.join(pluginConfigPath, file);
try {
await fsp.access(pluginFilePath);
const pluginData = await fc.readJSON(pluginFilePath);
if (Array.isArray(data) && Array.isArray(pluginData)) {
// 合并数组类型配置
const strSet = new Set(data.map((x) => JSON.stringify(x)));
for (const item of pluginData) {
const str = JSON.stringify(item);
if (!strSet.has(str)) {
data.push(item);
strSet.add(str);
}
}
} else if (!Array.isArray(data) && !Array.isArray(pluginData)) {
// 合并对象类型配置
data = fc.mergeConfig(data, pluginData);
}
// 保存合并后的配置
await fc.writeJSON(filePath, data);
} catch (mergeError) {
logger.error('[crystelf-plugin]合并配置失败..');
logger.error(mergeError);
// 忽略合并错误,使用现有数据
}
configCache[name] = data;
} catch (e) {
logger.warn(`[crystelf-plugin] 读取配置文件 ${file} 失败:`, e);
}
}
if (configCache.debug) {
logger.info('[crystelf-plugin] 配置模块初始化成功..');
}
} catch (err) {
logger.warn('[crystelf-plugin] 配置初始化失败,使用空配置..', err);
configCache = {};
}
}
/**
* 配置文件热更新
*/
function watchConfigs() {
for (const w of watchers) {
w.close();
}
watchers = [];
fsp.readdir(dataConfigPath).then((files) => {
files
.filter((f) => f.endsWith('.json'))
.forEach((file) => {
const filePath = path.join(dataConfigPath, file);
const watcher = fs.watch(filePath, async (eventType) => {
if (eventType === 'change') {
try {
const data = await fc.readJSON(filePath);
const name = path.basename(file, '.json');
configCache[name] = data;
logger.info(`[crystelf-plugin] 配置热更新: ${file}`);
} catch (e) {
logger.warn(`[crystelf-plugin] 热更新读取失败 ${file}:`, e);
}
}
});
watchers.push(watcher);
});
});
}
const configControl = {
async init() {
await init();
watchConfigs();
},
get(key) {
return key ? configCache[key] : configCache;
},
async set(key, value) {
// 更新内存中的配置
configCache[key] = value;
const filePath = path.join(dataConfigPath, `${key}.json`);
try {
// 尝试访问文件,如果存在则直接写入
await fsp.access(filePath);
await fc.writeJSON(filePath, value);
} catch (error) {
// 文件不存在,创建新文件
try {
// 确保目录存在
await fsp.mkdir(dataConfigPath, { recursive: true });
// 直接写入新文件
await fc.writeJSON(filePath, value);
logger.mark(`[crystelf-plugin] 创建新配置文件: ${filePath}`);
} catch (writeError) {
logger.error(`[crystelf-plugin] 创建配置文件失败: ${writeError}`);
throw writeError;
}
}
},
/**
* 批量设置配置
* @param {Object} configs - 配置对象,键为配置名,值为配置数据
*/
async setMultiple(configs) {
// 确保目录存在
await fsp.mkdir(dataConfigPath, { recursive: true });
for (const [key, value] of Object.entries(configs)) {
try {
// 更新内存中的配置
configCache[key] = value;
const filePath = path.join(dataConfigPath, `${key}.json`);
// 写入配置文件
await fc.writeJSON(filePath, value);
} catch (error) {
logger.error(`[crystelf-plugin] 设置配置失败 ${key}: ${error}`);
throw error;
}
}
},
async save() {
// 确保目录存在
await fsp.mkdir(dataConfigPath, { recursive: true });
for (const [key, value] of Object.entries(configCache)) {
const filePath = path.join(dataConfigPath, `${key}.json`);
try {
// 直接写入配置文件
await fc.writeJSON(filePath, value);
} catch (error) {
logger.error(`[crystelf-plugin] 保存配置文件失败 ${filePath}: ${error}`);
throw error;
}
}
},
async reload() {
await init();
watchConfigs();
return true;
},
};
export default configControl;