mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-28 00:35:32 +08:00
2b34dc4ec9
- Refactor ProviderService to use database queries instead of in-memory config - Update McpService to fetch and store MCP servers in database - Migrate PromptService to database-backed storage - Simplify ConfigService by removing complex transaction logic - Remove 648 lines of redundant code through database abstraction
201 lines
6.4 KiB
Rust
201 lines
6.4 KiB
Rust
use indexmap::IndexMap;
|
||
use std::collections::HashMap;
|
||
|
||
use crate::app_config::{AppType, McpServer};
|
||
use crate::error::AppError;
|
||
use crate::mcp;
|
||
use crate::store::AppState;
|
||
|
||
/// MCP 相关业务逻辑(v3.7.0 统一结构)
|
||
pub struct McpService;
|
||
|
||
impl McpService {
|
||
/// 获取所有 MCP 服务器(统一结构)
|
||
pub fn get_all_servers(state: &AppState) -> Result<IndexMap<String, McpServer>, AppError> {
|
||
state.db.get_all_mcp_servers()
|
||
}
|
||
|
||
/// 添加或更新 MCP 服务器
|
||
pub fn upsert_server(state: &AppState, server: McpServer) -> Result<(), AppError> {
|
||
state.db.save_mcp_server(&server)?;
|
||
|
||
// 同步到各个启用的应用
|
||
Self::sync_server_to_apps(state, &server)?;
|
||
|
||
Ok(())
|
||
}
|
||
|
||
/// 删除 MCP 服务器
|
||
pub fn delete_server(state: &AppState, id: &str) -> Result<bool, AppError> {
|
||
let server = state.db.get_all_mcp_servers()?.shift_remove(id);
|
||
|
||
if let Some(server) = server {
|
||
state.db.delete_mcp_server(id)?;
|
||
|
||
// 从所有应用的 live 配置中移除
|
||
Self::remove_server_from_all_apps(state, id, &server)?;
|
||
Ok(true)
|
||
} else {
|
||
Ok(false)
|
||
}
|
||
}
|
||
|
||
/// 切换指定应用的启用状态
|
||
pub fn toggle_app(
|
||
state: &AppState,
|
||
server_id: &str,
|
||
app: AppType,
|
||
enabled: bool,
|
||
) -> Result<(), AppError> {
|
||
let mut servers = state.db.get_all_mcp_servers()?;
|
||
|
||
if let Some(server) = servers.get_mut(server_id) {
|
||
server.apps.set_enabled_for(&app, enabled);
|
||
state.db.save_mcp_server(server)?;
|
||
|
||
// 同步到对应应用
|
||
if enabled {
|
||
Self::sync_server_to_app(state, server, &app)?;
|
||
} else {
|
||
Self::remove_server_from_app(state, server_id, &app)?;
|
||
}
|
||
}
|
||
|
||
Ok(())
|
||
}
|
||
|
||
/// 将 MCP 服务器同步到所有启用的应用
|
||
fn sync_server_to_apps(_state: &AppState, server: &McpServer) -> Result<(), AppError> {
|
||
for app in server.apps.enabled_apps() {
|
||
Self::sync_server_to_app_no_config(server, &app)?;
|
||
}
|
||
|
||
Ok(())
|
||
}
|
||
|
||
/// 将 MCP 服务器同步到指定应用
|
||
fn sync_server_to_app(
|
||
_state: &AppState,
|
||
server: &McpServer,
|
||
app: &AppType,
|
||
) -> Result<(), AppError> {
|
||
Self::sync_server_to_app_no_config(server, app)
|
||
}
|
||
|
||
fn sync_server_to_app_no_config(server: &McpServer, app: &AppType) -> Result<(), AppError> {
|
||
match app {
|
||
AppType::Claude => {
|
||
mcp::sync_single_server_to_claude(&Default::default(), &server.id, &server.server)?;
|
||
}
|
||
AppType::Codex => {
|
||
// Codex uses TOML format, must use the correct function
|
||
mcp::sync_single_server_to_codex(&Default::default(), &server.id, &server.server)?;
|
||
}
|
||
AppType::Gemini => {
|
||
mcp::sync_single_server_to_gemini(&Default::default(), &server.id, &server.server)?;
|
||
}
|
||
}
|
||
Ok(())
|
||
}
|
||
|
||
/// 从所有曾启用过该服务器的应用中移除
|
||
fn remove_server_from_all_apps(
|
||
state: &AppState,
|
||
id: &str,
|
||
server: &McpServer,
|
||
) -> Result<(), AppError> {
|
||
// 从所有曾启用的应用中移除
|
||
for app in server.apps.enabled_apps() {
|
||
Self::remove_server_from_app(state, id, &app)?;
|
||
}
|
||
Ok(())
|
||
}
|
||
|
||
fn remove_server_from_app(_state: &AppState, id: &str, app: &AppType) -> Result<(), AppError> {
|
||
match app {
|
||
AppType::Claude => mcp::remove_server_from_claude(id)?,
|
||
AppType::Codex => mcp::remove_server_from_codex(id)?,
|
||
AppType::Gemini => mcp::remove_server_from_gemini(id)?,
|
||
}
|
||
Ok(())
|
||
}
|
||
|
||
/// 手动同步所有启用的 MCP 服务器到对应的应用
|
||
pub fn sync_all_enabled(state: &AppState) -> Result<(), AppError> {
|
||
let servers = Self::get_all_servers(state)?;
|
||
|
||
for server in servers.values() {
|
||
Self::sync_server_to_apps(state, server)?;
|
||
}
|
||
|
||
Ok(())
|
||
}
|
||
|
||
// ========================================================================
|
||
// 兼容层:支持旧的 v3.6.x 命令(已废弃,将在 v4.0 移除)
|
||
// ========================================================================
|
||
|
||
/// [已废弃] 获取指定应用的 MCP 服务器(兼容旧 API)
|
||
#[deprecated(since = "3.7.0", note = "Use get_all_servers instead")]
|
||
pub fn get_servers(
|
||
state: &AppState,
|
||
app: AppType,
|
||
) -> Result<HashMap<String, serde_json::Value>, AppError> {
|
||
let all_servers = Self::get_all_servers(state)?;
|
||
let mut result = HashMap::new();
|
||
|
||
for (id, server) in all_servers {
|
||
if server.apps.is_enabled_for(&app) {
|
||
result.insert(id, server.server);
|
||
}
|
||
}
|
||
|
||
Ok(result)
|
||
}
|
||
|
||
/// [已废弃] 设置 MCP 服务器在指定应用的启用状态(兼容旧 API)
|
||
#[deprecated(since = "3.7.0", note = "Use toggle_app instead")]
|
||
pub fn set_enabled(
|
||
state: &AppState,
|
||
app: AppType,
|
||
id: &str,
|
||
enabled: bool,
|
||
) -> Result<bool, AppError> {
|
||
Self::toggle_app(state, id, app, enabled)?;
|
||
Ok(true)
|
||
}
|
||
|
||
/// [已废弃] 同步启用的 MCP 到指定应用(兼容旧 API)
|
||
#[deprecated(since = "3.7.0", note = "Use sync_all_enabled instead")]
|
||
pub fn sync_enabled(state: &AppState, app: AppType) -> Result<(), AppError> {
|
||
let servers = Self::get_all_servers(state)?;
|
||
|
||
for server in servers.values() {
|
||
if server.apps.is_enabled_for(&app) {
|
||
Self::sync_server_to_app(state, server, &app)?;
|
||
}
|
||
}
|
||
|
||
Ok(())
|
||
}
|
||
|
||
/// 从 Claude 导入 MCP(v3.7.0 已更新为统一结构)
|
||
pub fn import_from_claude(_state: &AppState) -> Result<usize, AppError> {
|
||
// TODO: Implement import logic using database
|
||
// For now, return 0 as a placeholder
|
||
Ok(0)
|
||
}
|
||
|
||
/// 从 Codex 导入 MCP(v3.7.0 已更新为统一结构)
|
||
pub fn import_from_codex(_state: &AppState) -> Result<usize, AppError> {
|
||
// TODO: Implement import logic using database
|
||
Ok(0)
|
||
}
|
||
|
||
/// 从 Gemini 导入 MCP(v3.7.0 已更新为统一结构)
|
||
pub fn import_from_gemini(_state: &AppState) -> Result<usize, AppError> {
|
||
// TODO: Implement import logic using database
|
||
Ok(0)
|
||
}
|
||
}
|