use std::collections::HashMap; use tauri::State; use crate::app_config::AppType; use crate::error::AppError; use crate::provider::Provider; use crate::services::{EndpointLatency, ProviderService, ProviderSortUpdate, SpeedtestService}; use crate::store::AppState; fn missing_param(param: &str) -> String { format!("缺少 {} 参数 (Missing {} parameter)", param, param) } fn resolve_app_type(app_type: Option, app: Option) -> Result { match (app_type, app) { (Some(at), None) => Ok(at), (None, Some(a)) => match a.to_lowercase().as_str() { "claude" => Ok(AppType::Claude), "codex" => Ok(AppType::Codex), other => Err(format!( "params.invalid: 无效的 app 值: {} (Invalid app)", other )), }, (Some(at), Some(a)) => { let a_norm = a.to_lowercase(); let at_norm = at.as_str().to_string(); if a_norm == at_norm { // 接受但提示:建议仅传 app log::warn!("params.deprecated: 同时传递 app 与 app_type,建议仅使用 app"); Ok(at) } else { Err(format!( "params.conflict: app 与 app_type 冲突 (app={}, app_type={})", a_norm, at_norm )) } } (None, None) => Err(missing_param("app")), } } /// 获取所有供应商 #[tauri::command] pub fn get_providers( state: State<'_, AppState>, app_type: Option, app: Option, ) -> Result, String> { let app_type = resolve_app_type(app_type, app)?; ProviderService::list(state.inner(), app_type).map_err(|e| e.to_string()) } /// 获取当前供应商ID #[tauri::command] pub fn get_current_provider( state: State<'_, AppState>, app_type: Option, app: Option, ) -> Result { let app_type = resolve_app_type(app_type, app)?; ProviderService::current(state.inner(), app_type).map_err(|e| e.to_string()) } /// 添加供应商 #[tauri::command] pub fn add_provider( state: State<'_, AppState>, app_type: Option, app: Option, provider: Provider, ) -> Result { let app_type = resolve_app_type(app_type, app)?; ProviderService::add(state.inner(), app_type, provider).map_err(|e| e.to_string()) } /// 更新供应商 #[tauri::command] pub fn update_provider( state: State<'_, AppState>, app_type: Option, app: Option, provider: Provider, ) -> Result { let app_type = resolve_app_type(app_type, app)?; ProviderService::update(state.inner(), app_type, provider).map_err(|e| e.to_string()) } /// 删除供应商 #[tauri::command] pub fn delete_provider( state: State<'_, AppState>, app_type: Option, app: Option, id: String, ) -> Result { let app_type = resolve_app_type(app_type, app)?; ProviderService::delete(state.inner(), app_type, &id) .map(|_| true) .map_err(|e| e.to_string()) } /// 切换供应商 fn switch_provider_internal(state: &AppState, app_type: AppType, id: &str) -> Result<(), AppError> { ProviderService::switch(state, app_type, id) } #[cfg_attr(not(feature = "test-hooks"), doc(hidden))] pub fn switch_provider_test_hook( state: &AppState, app_type: AppType, id: &str, ) -> Result<(), AppError> { switch_provider_internal(state, app_type, id) } #[tauri::command] pub fn switch_provider( state: State<'_, AppState>, app_type: Option, app: Option, id: String, ) -> Result { let app_type = resolve_app_type(app_type, app)?; switch_provider_internal(&state, app_type, &id) .map(|_| true) .map_err(|e| e.to_string()) } fn import_default_config_internal(state: &AppState, app_type: AppType) -> Result<(), AppError> { ProviderService::import_default_config(state, app_type) } #[cfg_attr(not(feature = "test-hooks"), doc(hidden))] pub fn import_default_config_test_hook( state: &AppState, app_type: AppType, ) -> Result<(), AppError> { import_default_config_internal(state, app_type) } /// 导入当前配置为默认供应商 #[tauri::command] pub fn import_default_config( state: State<'_, AppState>, app_type: Option, app: Option, ) -> Result { let app_type = resolve_app_type(app_type, app)?; import_default_config_internal(&state, app_type) .map(|_| true) .map_err(Into::into) } /// 查询供应商用量 #[tauri::command] pub async fn query_provider_usage( state: State<'_, AppState>, provider_id: Option, app_type: Option, app: Option, ) -> Result { let provider_id = provider_id.ok_or_else(|| missing_param("providerId"))?; let app_type = resolve_app_type(app_type, app)?; ProviderService::query_usage(state.inner(), app_type, &provider_id) .await .map_err(|e| e.to_string()) } /// 读取当前生效的配置内容 #[tauri::command] pub fn read_live_provider_settings(app_type: Option) -> Result { let app_type = app_type.unwrap_or(AppType::Claude); ProviderService::read_live_settings(app_type).map_err(|e| e.to_string()) } /// 测试第三方/自定义供应商端点的网络延迟 #[tauri::command] pub async fn test_api_endpoints( urls: Vec, timeout_secs: Option, ) -> Result, String> { SpeedtestService::test_endpoints(urls, timeout_secs) .await .map_err(|e| e.to_string()) } /// 获取自定义端点列表 #[tauri::command] pub fn get_custom_endpoints( state: State<'_, AppState>, app_type: Option, app: Option, provider_id: Option, ) -> Result, String> { let app_type = resolve_app_type(app_type, app)?; let provider_id = provider_id.ok_or_else(|| missing_param("providerId"))?; ProviderService::get_custom_endpoints(state.inner(), app_type, &provider_id) .map_err(|e| e.to_string()) } /// 添加自定义端点 #[tauri::command] pub fn add_custom_endpoint( state: State<'_, AppState>, app_type: Option, app: Option, provider_id: Option, url: String, ) -> Result<(), String> { let app_type = resolve_app_type(app_type, app)?; let provider_id = provider_id.ok_or_else(|| missing_param("providerId"))?; ProviderService::add_custom_endpoint(state.inner(), app_type, &provider_id, url) .map_err(|e| e.to_string()) } /// 删除自定义端点 #[tauri::command] pub fn remove_custom_endpoint( state: State<'_, AppState>, app_type: Option, app: Option, provider_id: Option, url: String, ) -> Result<(), String> { let app_type = resolve_app_type(app_type, app)?; let provider_id = provider_id.ok_or_else(|| missing_param("providerId"))?; ProviderService::remove_custom_endpoint(state.inner(), app_type, &provider_id, url) .map_err(|e| e.to_string()) } /// 更新端点最后使用时间 #[tauri::command] pub fn update_endpoint_last_used( state: State<'_, AppState>, app_type: Option, app: Option, provider_id: Option, url: String, ) -> Result<(), String> { let app_type = resolve_app_type(app_type, app)?; let provider_id = provider_id.ok_or_else(|| missing_param("providerId"))?; ProviderService::update_endpoint_last_used(state.inner(), app_type, &provider_id, url) .map_err(|e| e.to_string()) } /// 更新多个供应商的排序 #[tauri::command] pub fn update_providers_sort_order( state: State<'_, AppState>, app_type: Option, app: Option, updates: Vec, ) -> Result { let app_type = resolve_app_type(app_type, app)?; ProviderService::update_sort_order(state.inner(), app_type, updates).map_err(|e| e.to_string()) }