Jaasomn
Initial deployment
ceb3821
import { existsSync, readFileSync, writeFileSync } from 'fs';
import { promises as fs } from 'fs';
import path from 'path';
import { CONFIG } from '../core/config-manager.js';
import { serviceInstances } from '../providers/adapter.js';
import { initApiService } from '../services/service-manager.js';
import { getRequestBody } from '../utils/common.js';
import { broadcastEvent } from '../ui-modules/event-broadcast.js';
/**
* 重载配置文件
* 动态导入config-manager并重新初始化配置
* @returns {Promise<Object>} 返回重载后的配置对象
*/
export async function reloadConfig(providerPoolManager) {
try {
// Import config manager dynamically
const { initializeConfig } = await import('../core/config-manager.js');
// Reload main config
const newConfig = await initializeConfig(process.argv.slice(2), 'configs/config.json');
// Update provider pool manager if available
if (providerPoolManager) {
providerPoolManager.providerPools = newConfig.providerPools;
providerPoolManager.initializeProviderStatus();
}
// Update global CONFIG
Object.assign(CONFIG, newConfig);
console.log('[UI API] Configuration reloaded:');
// Update initApiService - 清空并重新初始化服务实例
Object.keys(serviceInstances).forEach(key => delete serviceInstances[key]);
initApiService(CONFIG);
console.log('[UI API] Configuration reloaded successfully');
return newConfig;
} catch (error) {
console.error('[UI API] Failed to reload configuration:', error);
throw error;
}
}
/**
* 获取配置
*/
export async function handleGetConfig(req, res, currentConfig) {
let systemPrompt = '';
if (currentConfig.SYSTEM_PROMPT_FILE_PATH && existsSync(currentConfig.SYSTEM_PROMPT_FILE_PATH)) {
try {
systemPrompt = readFileSync(currentConfig.SYSTEM_PROMPT_FILE_PATH, 'utf-8');
} catch (e) {
console.warn('[UI API] Failed to read system prompt file:', e.message);
}
}
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
...currentConfig,
systemPrompt
}));
return true;
}
/**
* 更新配置
*/
export async function handleUpdateConfig(req, res, currentConfig) {
try {
const body = await getRequestBody(req);
const newConfig = body;
// Update config values in memory
if (newConfig.REQUIRED_API_KEY !== undefined) currentConfig.REQUIRED_API_KEY = newConfig.REQUIRED_API_KEY;
if (newConfig.HOST !== undefined) currentConfig.HOST = newConfig.HOST;
if (newConfig.SERVER_PORT !== undefined) currentConfig.SERVER_PORT = newConfig.SERVER_PORT;
if (newConfig.MODEL_PROVIDER !== undefined) currentConfig.MODEL_PROVIDER = newConfig.MODEL_PROVIDER;
if (newConfig.SYSTEM_PROMPT_FILE_PATH !== undefined) currentConfig.SYSTEM_PROMPT_FILE_PATH = newConfig.SYSTEM_PROMPT_FILE_PATH;
if (newConfig.SYSTEM_PROMPT_MODE !== undefined) currentConfig.SYSTEM_PROMPT_MODE = newConfig.SYSTEM_PROMPT_MODE;
if (newConfig.PROMPT_LOG_BASE_NAME !== undefined) currentConfig.PROMPT_LOG_BASE_NAME = newConfig.PROMPT_LOG_BASE_NAME;
if (newConfig.PROMPT_LOG_MODE !== undefined) currentConfig.PROMPT_LOG_MODE = newConfig.PROMPT_LOG_MODE;
if (newConfig.REQUEST_MAX_RETRIES !== undefined) currentConfig.REQUEST_MAX_RETRIES = newConfig.REQUEST_MAX_RETRIES;
if (newConfig.REQUEST_BASE_DELAY !== undefined) currentConfig.REQUEST_BASE_DELAY = newConfig.REQUEST_BASE_DELAY;
if (newConfig.CREDENTIAL_SWITCH_MAX_RETRIES !== undefined) currentConfig.CREDENTIAL_SWITCH_MAX_RETRIES = newConfig.CREDENTIAL_SWITCH_MAX_RETRIES;
if (newConfig.CRON_NEAR_MINUTES !== undefined) currentConfig.CRON_NEAR_MINUTES = newConfig.CRON_NEAR_MINUTES;
if (newConfig.CRON_REFRESH_TOKEN !== undefined) currentConfig.CRON_REFRESH_TOKEN = newConfig.CRON_REFRESH_TOKEN;
if (newConfig.PROVIDER_POOLS_FILE_PATH !== undefined) currentConfig.PROVIDER_POOLS_FILE_PATH = newConfig.PROVIDER_POOLS_FILE_PATH;
if (newConfig.MAX_ERROR_COUNT !== undefined) currentConfig.MAX_ERROR_COUNT = newConfig.MAX_ERROR_COUNT;
if (newConfig.WARMUP_TARGET !== undefined) currentConfig.WARMUP_TARGET = newConfig.WARMUP_TARGET;
if (newConfig.REFRESH_CONCURRENCY_PER_PROVIDER !== undefined) currentConfig.REFRESH_CONCURRENCY_PER_PROVIDER = newConfig.REFRESH_CONCURRENCY_PER_PROVIDER;
if (newConfig.providerFallbackChain !== undefined) currentConfig.providerFallbackChain = newConfig.providerFallbackChain;
if (newConfig.modelFallbackMapping !== undefined) currentConfig.modelFallbackMapping = newConfig.modelFallbackMapping;
// Proxy settings
if (newConfig.PROXY_URL !== undefined) currentConfig.PROXY_URL = newConfig.PROXY_URL;
if (newConfig.PROXY_ENABLED_PROVIDERS !== undefined) currentConfig.PROXY_ENABLED_PROVIDERS = newConfig.PROXY_ENABLED_PROVIDERS;
// Handle system prompt update
if (newConfig.systemPrompt !== undefined) {
const promptPath = currentConfig.SYSTEM_PROMPT_FILE_PATH || 'configs/input_system_prompt.txt';
try {
const relativePath = path.relative(process.cwd(), promptPath);
writeFileSync(promptPath, newConfig.systemPrompt, 'utf-8');
// 广播更新事件
broadcastEvent('config_update', {
action: 'update',
filePath: relativePath,
type: 'system_prompt',
timestamp: new Date().toISOString()
});
console.log('[UI API] System prompt updated');
} catch (e) {
console.warn('[UI API] Failed to write system prompt:', e.message);
}
}
// Update config.json file
try {
const configPath = 'configs/config.json';
// Create a clean config object for saving (exclude runtime-only properties)
const configToSave = {
REQUIRED_API_KEY: currentConfig.REQUIRED_API_KEY,
SERVER_PORT: currentConfig.SERVER_PORT,
HOST: currentConfig.HOST,
MODEL_PROVIDER: currentConfig.MODEL_PROVIDER,
SYSTEM_PROMPT_FILE_PATH: currentConfig.SYSTEM_PROMPT_FILE_PATH,
SYSTEM_PROMPT_MODE: currentConfig.SYSTEM_PROMPT_MODE,
PROMPT_LOG_BASE_NAME: currentConfig.PROMPT_LOG_BASE_NAME,
PROMPT_LOG_MODE: currentConfig.PROMPT_LOG_MODE,
REQUEST_MAX_RETRIES: currentConfig.REQUEST_MAX_RETRIES,
REQUEST_BASE_DELAY: currentConfig.REQUEST_BASE_DELAY,
CREDENTIAL_SWITCH_MAX_RETRIES: currentConfig.CREDENTIAL_SWITCH_MAX_RETRIES,
CRON_NEAR_MINUTES: currentConfig.CRON_NEAR_MINUTES,
CRON_REFRESH_TOKEN: currentConfig.CRON_REFRESH_TOKEN,
PROVIDER_POOLS_FILE_PATH: currentConfig.PROVIDER_POOLS_FILE_PATH,
MAX_ERROR_COUNT: currentConfig.MAX_ERROR_COUNT,
POOL_SIZE_LIMIT: currentConfig.POOL_SIZE_LIMIT,
WARMUP_TARGET: currentConfig.WARMUP_TARGET,
REFRESH_CONCURRENCY_PER_PROVIDER: currentConfig.REFRESH_CONCURRENCY_PER_PROVIDER,
providerFallbackChain: currentConfig.providerFallbackChain,
modelFallbackMapping: currentConfig.modelFallbackMapping,
PROXY_URL: currentConfig.PROXY_URL,
PROXY_ENABLED_PROVIDERS: currentConfig.PROXY_ENABLED_PROVIDERS
};
writeFileSync(configPath, JSON.stringify(configToSave, null, 2), 'utf-8');
console.log('[UI API] Configuration saved to configs/config.json');
// 广播更新事件
broadcastEvent('config_update', {
action: 'update',
filePath: 'configs/config.json',
type: 'main_config',
timestamp: new Date().toISOString()
});
} catch (error) {
console.error('[UI API] Failed to save configuration to file:', error.message);
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: {
message: 'Failed to save configuration to file: ' + error.message,
partial: true // Indicate that memory config was updated but not saved
}
}));
return true;
}
// Update the global CONFIG object to reflect changes immediately
Object.assign(CONFIG, currentConfig);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
success: true,
message: 'Configuration updated successfully',
details: 'Configuration has been updated in both memory and config.json file'
}));
return true;
} catch (error) {
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: { message: error.message } }));
return true;
}
}
/**
* 重载配置文件
*/
export async function handleReloadConfig(req, res, providerPoolManager) {
try {
// 调用重载配置函数
const newConfig = await reloadConfig(providerPoolManager);
// 广播更新事件
broadcastEvent('config_update', {
action: 'reload',
filePath: 'configs/config.json',
providerPoolsPath: newConfig.PROVIDER_POOLS_FILE_PATH || null,
timestamp: new Date().toISOString()
});
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
success: true,
message: 'Configuration files reloaded successfully',
details: {
configReloaded: true,
configPath: 'configs/config.json',
providerPoolsPath: newConfig.PROVIDER_POOLS_FILE_PATH || null
}
}));
return true;
} catch (error) {
console.error('[UI API] Failed to reload config files:', error);
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: {
message: 'Failed to reload configuration files: ' + error.message
}
}));
return true;
}
}
/**
* 更新管理员密码
*/
export async function handleUpdateAdminPassword(req, res) {
try {
const body = await getRequestBody(req);
const { password } = body;
if (!password || password.trim() === '') {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: {
message: 'Password cannot be empty'
}
}));
return true;
}
// 写入密码到 pwd 文件
const pwdFilePath = path.join(process.cwd(), 'configs', 'pwd');
await fs.writeFile(pwdFilePath, password.trim(), 'utf-8');
console.log('[UI API] Admin password updated successfully');
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
success: true,
message: 'Admin password updated successfully'
}));
return true;
} catch (error) {
console.error('[UI API] Failed to update admin password:', error);
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: {
message: 'Failed to update password: ' + error.message
}
}));
return true;
}
}