@nexe/config-manager
Version:
Nexe Config Manager - A flexible configuration management solution with multiple sources and hot reload support
163 lines • 4.96 kB
JavaScript
import { __decorate, __metadata } from "tslib";
import { createLogger } from '@nexe/logger';
import * as fs from 'fs';
import { readFile } from 'fs/promises';
import * as path from 'path';
import { injectable } from 'tsyringe';
import * as YAML from 'yaml';
const logger = createLogger('YamlConfigSource');
/**
* YAML配置文件源
*/
let YamlConfigSource = class YamlConfigSource {
/**
* @param filePath 配置文件路径
* @param watchChanges 是否监听文件变化
*/
constructor(filePath, watchChanges = false) {
this.watchChanges = watchChanges;
this.cache = {};
this.watcher = null;
this.callbacks = new Map();
this.filePath = path.resolve(filePath);
if (this.watchChanges) {
this.setupWatcher();
}
}
/**
* 从YAML文件加载配置
*/
async load(key, _pathPrefix) {
try {
if (Object.keys(this.cache).length === 0) {
await this.loadFile();
}
if (!key) {
return this.cache;
}
return this.getNestedValue(this.cache, key);
}
catch (error) {
logger.error('从YAML加载配置失败', error);
return undefined;
}
}
/**
* 获取配置源名称
*/
getName() {
return `YamlConfigSource(${this.filePath})`;
}
/**
* 是否支持热更新
*/
supportsHotReload() {
return this.watchChanges;
}
/**
* 订阅配置变更
*/
subscribe(key, callback) {
if (!this.supportsHotReload()) {
logger.warn('此配置源未启用热更新,无法订阅变更');
return;
}
const callbacks = this.callbacks.get(key) ?? [];
callbacks.push(callback);
this.callbacks.set(key, callbacks);
}
/**
* 取消订阅配置变更
*/
unsubscribe(key) {
this.callbacks.delete(key);
}
/**
* 设置文件变更监听器
*/
setupWatcher() {
try {
// 先确保文件存在
if (!fs.existsSync(this.filePath)) {
logger.warn(`配置文件不存在: ${this.filePath}`);
return;
}
logger.info(`开始监听文件变更: ${this.filePath}`);
// 监听文件变更 - 使用更强大的选项
this.watcher = fs.watch(this.filePath, {
persistent: true,
encoding: 'utf8',
recursive: false,
}, (eventType, filename) => {
logger.info(`检测到文件变更: ${filename ?? this.filePath}, 事件类型: ${eventType}`);
// 文件变更后等待一小段时间再读取,确保写入完成
setTimeout(() => {
this.handleFileChange().catch(error => {
logger.error(`处理文件变更时出错: ${error instanceof Error ? error.message : String(error)}`);
});
}, 100);
});
}
catch (error) {
logger.error(`设置文件监听失败: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* 处理文件变更
*/
async handleFileChange() {
const oldCache = { ...this.cache };
await this.loadFile();
// 通知所有订阅者
this.callbacks.forEach((callbacks, key) => {
const newValue = this.getNestedValue(this.cache, key);
const oldValue = this.getNestedValue(oldCache, key);
if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
callbacks.forEach(callback => callback(newValue));
}
});
}
/**
* 加载文件到缓存
*/
async loadFile() {
try {
const content = await readFile(this.filePath, 'utf-8');
this.cache = YAML.parse(content);
}
catch (error) {
throw new Error(`加载YAML文件失败: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* 获取嵌套对象的属性值
*/
getNestedValue(obj, key) {
const parts = key.split('.');
let current = obj;
for (const part of parts) {
if (current === undefined ||
current === null ||
typeof current !== 'object') {
return undefined;
}
current = current[part];
}
return current;
}
/**
* 关闭资源
*/
dispose() {
if (this.watcher) {
this.watcher.close();
this.watcher = null;
}
}
};
YamlConfigSource = __decorate([
injectable(),
__metadata("design:paramtypes", [String, Object])
], YamlConfigSource);
export { YamlConfigSource };
//# sourceMappingURL=yaml-config-source.js.map