Skip to content

Commit 3db083a

Browse files
committed
feat(配置系统): 实现统一配置管理系统和React上下文集成
重构配置管理器为统一配置系统,新增React上下文和hooks支持 添加配置合并、验证工具函数和测试用例 实现向后兼容的配置管理器封装 提供细粒度的配置访问和响应式更新能力
1 parent 2c9769b commit 3db083a

21 files changed

Lines changed: 8635 additions & 564 deletions

packages/core/src/config/ConfigManager.ts

Lines changed: 123 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,54 @@
11
/**
2-
* Blade 极简配置管理器
3-
* 平铺式配置加载
2+
* Blade 配置管理器 (向后兼容封装)
3+
* 基于新的统一配置管理器,保持原有接口不变
44
*/
55

6-
import fs from 'fs';
7-
import path from 'path';
8-
import os from 'os';
6+
import { UnifiedConfigManager } from './UnifiedConfigManager.js';
97
import type { BladeConfig } from '@blade-ai/types';
10-
import { DEFAULT_CONFIG, ENV_MAPPING } from './defaults.js';
118
import {
129
ErrorFactory,
1310
ConfigError,
1411
globalErrorMonitor
1512
} from '../error/index.js';
1613

1714
export class ConfigManager {
15+
private unifiedManager: UnifiedConfigManager;
1816
private config: BladeConfig;
1917

2018
constructor() {
21-
this.config = DEFAULT_CONFIG;
19+
this.unifiedManager = new UnifiedConfigManager();
20+
this.config = {} as BladeConfig;
2221
this.loadConfiguration();
2322
}
2423

25-
private loadConfiguration(): void {
26-
// 1. 默认值 (已包含在DEFAULT_CONFIG)
27-
28-
// 2. 用户全局配置
29-
this.loadUserConfig();
30-
31-
// 3. 项目级配置
32-
this.loadProjectConfig();
33-
34-
// 4. 环境变量 (平铺式)
35-
this.loadFromEnvironment();
36-
}
37-
38-
private loadUserConfig(): void {
39-
const configPath = path.join(os.homedir(), '.blade', 'config.json');
24+
private async loadConfiguration(): Promise<void> {
4025
try {
41-
if (fs.existsSync(configPath)) {
42-
const file = fs.readFileSync(configPath, 'utf-8');
43-
const userConfig = JSON.parse(file);
44-
45-
// 验证用户配置
46-
const validation = this.validateConfig(userConfig);
47-
if (validation.length > 0) {
48-
console.warn('用户配置验证警告:', validation.map(e => e.message).join(', '));
49-
}
50-
51-
Object.assign(this.config, userConfig);
52-
}
26+
await this.unifiedManager.initialize();
27+
this.config = this.unifiedManager.getConfig();
5328
} catch (error) {
5429
const bladeError = error instanceof Error
55-
? ErrorFactory.fromNativeError(error, '用户配置加载失败')
56-
: new ConfigError('CONFIG_LOAD_FAILED', '用户配置加载失败', { context: { configPath } });
30+
? ErrorFactory.fromNativeError(error, '配置加载失败')
31+
: new ConfigError('CONFIG_LOAD_FAILED', '配置加载失败');
5732

5833
globalErrorMonitor.monitor(bladeError);
59-
console.warn('用户配置加载失败,将使用默认配置');
34+
console.warn('配置加载失败,使用默认配置:', error);
35+
36+
// 保持原有默认配置加载逻辑作为降级方案
37+
this.loadDefaultConfiguration();
6038
}
6139
}
6240

63-
private loadProjectConfig(): void {
64-
const configPaths = [
65-
path.join(process.cwd(), '.blade', 'settings.local.json'),
66-
path.join(process.cwd(), 'package.json'),
67-
];
41+
private loadDefaultConfiguration(): void {
42+
// 原有的默认配置加载逻辑
43+
const { DEFAULT_CONFIG, ENV_MAPPING } = require('./defaults.js');
44+
this.config = { ...DEFAULT_CONFIG } as BladeConfig;
6845

69-
for (const configPath of configPaths) {
70-
try {
71-
if (fs.existsSync(configPath)) {
72-
const file = fs.readFileSync(configPath, 'utf-8');
73-
const config = JSON.parse(file);
74-
const projectConfig = configPath.endsWith('package.json') ? config.blade : config;
75-
76-
if (!projectConfig) {
77-
console.warn(`项目配置文件 ${configPath} 中未找到blade配置项`);
78-
continue;
79-
}
80-
81-
// 验证项目配置
82-
const validation = this.validateConfig(projectConfig);
83-
if (validation.length > 0) {
84-
console.warn(`项目配置 ${configPath} 验证警告:`, validation.map(e => e.message).join(', '));
85-
}
86-
87-
// 只合并非敏感配置项(不包括apiKey, baseUrl, modelName)
88-
const safeConfig: Partial<BladeConfig> = {};
89-
for (const [key, value] of Object.entries(projectConfig)) {
90-
if (!['apiKey', 'baseUrl', 'modelName'].includes(key)) {
91-
(safeConfig as any)[key] = value;
92-
}
93-
}
94-
Object.assign(this.config, safeConfig);
95-
}
96-
} catch (error) {
97-
const bladeError = error instanceof Error
98-
? ErrorFactory.fromNativeError(error, '项目配置加载失败')
99-
: new ConfigError('CONFIG_LOAD_FAILED', '项目配置加载失败', { context: { configPath } });
100-
101-
globalErrorMonitor.monitor(bladeError);
102-
console.warn(`项目配置 ${configPath} 加载失败,跳过此配置文件`);
103-
}
104-
}
46+
// 加载环境变量
47+
this.loadFromEnvironment();
10548
}
10649

10750
private loadFromEnvironment(): void {
51+
const { ENV_MAPPING } = require('./defaults.js');
10852
for (const [envKey, configKey] of Object.entries(ENV_MAPPING)) {
10953
const value = process.env[envKey];
11054
if (value !== undefined) {
@@ -113,25 +57,47 @@ export class ConfigManager {
11357
}
11458
}
11559

116-
getConfig(): BladeConfig {
117-
return { ...this.config };
60+
async getConfig(): Promise<BladeConfig> {
61+
try {
62+
this.config = this.unifiedManager.getConfig();
63+
return { ...this.config };
64+
} catch (error) {
65+
console.warn('获取最新配置失败,返回缓存配置:', error);
66+
return { ...this.config };
67+
}
11868
}
11969

120-
updateConfig(updates: Partial<BladeConfig>): void {
70+
async updateConfig(updates: Partial<BladeConfig>): Promise<void> {
12171
// 验证更新配置
12272
const validation = this.validateConfig(updates);
12373
if (validation.length > 0) {
12474
console.warn('配置更新验证警告:', validation.map(e => e.message).join(', '));
12575
}
12676

127-
Object.assign(this.config, updates);
77+
try {
78+
await this.unifiedManager.updateConfig(updates);
79+
this.config = this.unifiedManager.getConfig();
80+
} catch (error) {
81+
const bladeError = error instanceof Error
82+
? ErrorFactory.fromNativeError(error, '配置更新失败')
83+
: new ConfigError('CONFIG_UPDATE_FAILED', '配置更新失败');
84+
85+
globalErrorMonitor.monitor(bladeError);
86+
console.error('配置更新失败:', error);
87+
throw error;
88+
}
12889
}
12990

130-
get(key: keyof BladeConfig): any {
131-
return this.config[key];
91+
async get(key: keyof BladeConfig): Promise<any> {
92+
try {
93+
return this.unifiedManager.get(key as string);
94+
} catch (error) {
95+
console.warn(`获取配置项 ${String(key)} 失败,返回缓存值:`, error);
96+
return this.config[key];
97+
}
13298
}
13399

134-
set(key: keyof BladeConfig, value: any): void {
100+
async set(key: keyof BladeConfig, value: any): Promise<void> {
135101
// 验证单个配置值
136102
if (value !== undefined && value !== null) {
137103
const validationErrors = this.validateConfigValue(key, value);
@@ -140,14 +106,81 @@ export class ConfigManager {
140106
}
141107
}
142108

143-
(this.config as any)[key] = value;
109+
try {
110+
await this.unifiedManager.set(key as string, value);
111+
this.config = this.unifiedManager.getConfig();
112+
} catch (error) {
113+
const bladeError = error instanceof Error
114+
? ErrorFactory.fromNativeError(error, `设置配置项 ${String(key)} 失败`)
115+
: new ConfigError('CONFIG_SET_FAILED', `设置配置项 ${String(key)} 失败`, { context: { key } });
116+
117+
globalErrorMonitor.monitor(bladeError);
118+
console.error(`设置配置项 ${String(key)} 失败:`, error);
119+
throw error;
120+
}
121+
}
122+
123+
async reload(): Promise<BladeConfig> {
124+
try {
125+
const reloadedConfig = await this.unifiedManager.reload();
126+
this.config = reloadedConfig;
127+
return { ...this.config };
128+
} catch (error) {
129+
const bladeError = error instanceof Error
130+
? ErrorFactory.fromNativeError(error, '重新加载配置失败')
131+
: new ConfigError('CONFIG_RELOAD_FAILED', '重新加载配置失败');
132+
133+
globalErrorMonitor.monitor(bladeError);
134+
console.error('重新加载配置失败:', error);
135+
throw error;
136+
}
137+
}
138+
139+
enableHotReload(): void {
140+
try {
141+
this.unifiedManager.enableHotReload();
142+
} catch (error) {
143+
const bladeError = error instanceof Error
144+
? ErrorFactory.fromNativeError(error, '启用热重载失败')
145+
: new ConfigError('CONFIG_HOT_RELOAD_ENABLE_FAILED', '启用热重载失败');
146+
147+
globalErrorMonitor.monitor(bladeError);
148+
console.warn('启用热重载失败:', error);
149+
}
150+
}
151+
152+
disableHotReload(): void {
153+
try {
154+
this.unifiedManager.disableHotReload();
155+
} catch (error) {
156+
const bladeError = error instanceof Error
157+
? ErrorFactory.fromNativeError(error, '禁用热重载失败')
158+
: new ConfigError('CONFIG_HOT_RELOAD_DISABLE_FAILED', '禁用热重载失败');
159+
160+
globalErrorMonitor.monitor(bladeError);
161+
console.warn('禁用热重载失败:', error);
162+
}
163+
}
164+
165+
subscribe(callback: (config: BladeConfig) => void): () => void {
166+
try {
167+
return this.unifiedManager.subscribe(callback);
168+
} catch (error) {
169+
const bladeError = error instanceof Error
170+
? ErrorFactory.fromNativeError(error, '订阅配置变更失败')
171+
: new ConfigError('CONFIG_SUBSCRIBE_FAILED', '订阅配置变更失败');
172+
173+
globalErrorMonitor.monitor(bladeError);
174+
console.warn('订阅配置变更失败:', error);
175+
return () => {};
176+
}
144177
}
145178

146179
/**
147180
* 验证配置对象
148181
*/
149-
private validateConfig(config: Partial<BladeConfig>): BladeError[] {
150-
const errors: BladeError[] = [];
182+
private validateConfig(config: Partial<BladeConfig>): any[] {
183+
const errors: any[] = [];
151184

152185
// 验证各个配置项
153186
for (const [key, value] of Object.entries(config)) {
@@ -161,8 +194,8 @@ export class ConfigManager {
161194
/**
162195
* 验证单个配置项
163196
*/
164-
private validateConfigValue(key: keyof BladeConfig, value: any): BladeError[] {
165-
const errors: BladeError[] = [];
197+
private validateConfigValue(key: keyof BladeConfig, value: any): any[] {
198+
const errors: any[] = [];
166199

167200
// 特定字段验证
168201
switch (key) {

0 commit comments

Comments
 (0)