mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-28 08:44:41 +08:00
7096957b40
Add independent credential fields for usage query to support different query endpoints and authentication methods. Changes: - Add `apiKey` and `baseUrl` fields to UsageScript struct - Remove dependency on provider config credentials in query_usage - Update test_usage_script to accept independent credential parameters - Add credential input fields in UsageScriptModal based on template: * General: apiKey + baseUrl * NewAPI: baseUrl + accessToken + userId * Custom: no additional fields (full freedom) - Auto-clear irrelevant fields when switching templates - Add i18n text for "credentialsConfig" Benefits: - Query API can use different endpoint/key than provider config - Better separation of concerns - More flexible for various usage query scenarios
139 lines
4.6 KiB
Rust
139 lines
4.6 KiB
Rust
use serde::{Deserialize, Serialize};
|
||
use serde_json::Value;
|
||
use std::collections::HashMap;
|
||
|
||
// SSOT 模式:不再写供应商副本文件
|
||
|
||
/// 供应商结构体
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct Provider {
|
||
pub id: String,
|
||
pub name: String,
|
||
#[serde(rename = "settingsConfig")]
|
||
pub settings_config: Value,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
#[serde(rename = "websiteUrl")]
|
||
pub website_url: Option<String>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub category: Option<String>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
#[serde(rename = "createdAt")]
|
||
pub created_at: Option<i64>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
#[serde(rename = "sortIndex")]
|
||
pub sort_index: Option<usize>,
|
||
/// 供应商元数据(不写入 live 配置,仅存于 ~/.cc-switch/config.json)
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub meta: Option<ProviderMeta>,
|
||
}
|
||
|
||
impl Provider {
|
||
/// 从现有ID创建供应商
|
||
pub fn with_id(
|
||
id: String,
|
||
name: String,
|
||
settings_config: Value,
|
||
website_url: Option<String>,
|
||
) -> Self {
|
||
Self {
|
||
id,
|
||
name,
|
||
settings_config,
|
||
website_url,
|
||
category: None,
|
||
created_at: None,
|
||
sort_index: None,
|
||
meta: None,
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 供应商管理器
|
||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||
pub struct ProviderManager {
|
||
pub providers: HashMap<String, Provider>,
|
||
pub current: String,
|
||
}
|
||
|
||
/// 用量查询脚本配置
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct UsageScript {
|
||
pub enabled: bool,
|
||
pub language: String,
|
||
pub code: String,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub timeout: Option<u64>,
|
||
/// 用量查询专用的 API Key(通用模板使用)
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
#[serde(rename = "apiKey")]
|
||
pub api_key: Option<String>,
|
||
/// 用量查询专用的 Base URL(通用和 NewAPI 模板使用)
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
#[serde(rename = "baseUrl")]
|
||
pub base_url: Option<String>,
|
||
/// 访问令牌(用于需要登录的接口,NewAPI 模板使用)
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
#[serde(rename = "accessToken")]
|
||
pub access_token: Option<String>,
|
||
/// 用户ID(用于需要用户标识的接口,NewAPI 模板使用)
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
#[serde(rename = "userId")]
|
||
pub user_id: Option<String>,
|
||
/// 自动查询间隔(单位:分钟,0 表示禁用自动查询)
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
#[serde(rename = "autoQueryInterval")]
|
||
pub auto_query_interval: Option<u64>,
|
||
}
|
||
|
||
/// 用量数据
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct UsageData {
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
#[serde(rename = "planName")]
|
||
pub plan_name: Option<String>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub extra: Option<String>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
#[serde(rename = "isValid")]
|
||
pub is_valid: Option<bool>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
#[serde(rename = "invalidMessage")]
|
||
pub invalid_message: Option<String>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub total: Option<f64>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub used: Option<f64>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub remaining: Option<f64>,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub unit: Option<String>,
|
||
}
|
||
|
||
/// 用量查询结果(支持多套餐)
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct UsageResult {
|
||
pub success: bool,
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub data: Option<Vec<UsageData>>, // 支持返回多个套餐
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub error: Option<String>,
|
||
}
|
||
|
||
/// 供应商元数据
|
||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||
pub struct ProviderMeta {
|
||
/// 自定义端点列表(按 URL 去重存储)
|
||
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
||
pub custom_endpoints: HashMap<String, crate::settings::CustomEndpoint>,
|
||
/// 用量查询脚本配置
|
||
#[serde(skip_serializing_if = "Option::is_none")]
|
||
pub usage_script: Option<UsageScript>,
|
||
}
|
||
|
||
impl ProviderManager {
|
||
/// 获取所有供应商
|
||
pub fn get_all_providers(&self) -> &HashMap<String, Provider> {
|
||
&self.providers
|
||
}
|
||
}
|