@nexe/config-manager
Version:
Nexe Config Manager - A flexible configuration management solution with multiple sources and hot reload support
169 lines • 5.33 kB
JavaScript
import { __decorate, __metadata } from "tslib";
import { createLogger } from '@nexe/logger';
import { injectable } from 'tsyringe';
const logger = createLogger('RemoteApiConfigSource');
/**
* 远程API配置源
*/
let RemoteApiConfigSource = class RemoteApiConfigSource {
/**
* @param baseUrl 远程API基础URL
* @param headers 请求头
* @param pollingInterval 轮询间隔(毫秒),如果设置则启用轮询更新
*/
constructor(baseUrl, headers = {}, pollingInterval) {
this.cache = {};
this.callbacks = new Map();
this.baseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
this.headers = headers;
this.pollingInterval = pollingInterval;
if (this.pollingInterval && this.pollingInterval > 0) {
this.startPolling();
}
}
/**
* 从远程API加载配置
*/
async load(key, _pathPrefix) {
try {
if (Object.keys(this.cache).length === 0) {
await this.fetchAllConfig();
}
if (!key) {
return this.cache;
}
return this.getNestedValue(this.cache, key);
}
catch (error) {
logger.error(`从远程API加载配置失败: ${error instanceof Error ? error.message : String(error)}`);
return undefined;
}
}
/**
* 获取配置源名称
*/
getName() {
return `RemoteApiConfigSource(${this.baseUrl})`;
}
/**
* 是否支持热更新
*/
supportsHotReload() {
return !!this.pollingInterval;
}
/**
* 订阅配置变更
*/
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);
}
/**
* 开始轮询更新
*/
startPolling() {
if (this.pollingTimer) {
clearInterval(this.pollingTimer);
}
this.pollingTimer = setInterval(() => {
this.pollForChanges().catch(error => {
logger.error(`轮询配置更新失败: ${error instanceof Error ? error.message : String(error)}`);
});
}, this.pollingInterval);
}
/**
* 轮询检查配置变更
*/
async pollForChanges() {
const oldCache = { ...this.cache };
await this.fetchAllConfig();
// 通知所有订阅者
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));
}
});
}
/**
* 获取特定键的配置值
*/
// private async fetchConfig(key: string): Promise<unknown> {
// try {
// const url = `${this.baseUrl}/config/${encodeURIComponent(key)}`;
// const response = await fetch(url, { headers: this.headers });
// if (!response.ok) {
// throw new Error(
// `API返回错误: ${response.status} ${response.statusText}`,
// );
// }
// const data = await response.json() as { value?: unknown };
// return data.value; // 根据实际API响应格式调整
// } catch (error) {
// logger.error(
// `获取配置值失败: ${error instanceof Error ? error.message : String(error)}`,
// );
// return undefined;
// }
// }
/**
* 获取所有配置
*/
async fetchAllConfig() {
try {
const url = `${this.baseUrl}/config`;
const response = await fetch(url, { headers: this.headers });
if (!response.ok) {
throw new Error(`API返回错误: ${response.status} ${response.statusText}`);
}
const data = (await response.json());
this.cache = data;
}
catch (error) {
throw new Error(`获取所有配置失败: ${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.pollingTimer) {
clearInterval(this.pollingTimer);
this.pollingTimer = undefined;
}
}
};
RemoteApiConfigSource = __decorate([
injectable(),
__metadata("design:paramtypes", [String, Object, Number])
], RemoteApiConfigSource);
export { RemoteApiConfigSource };
//# sourceMappingURL=remote-api-config-source.js.map