File size: 5,766 Bytes
a21c316 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use super::{token::TokenData, quota::QuotaData};
/// 账号数据结构
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Account {
pub id: String,
pub email: String,
pub name: Option<String>,
pub token: TokenData,
/// 可选的设备指纹,用于切换账号时固定机器信息
#[serde(default, skip_serializing_if = "Option::is_none")]
pub device_profile: Option<DeviceProfile>,
/// 设备指纹历史(生成/采集时记录),不含基线
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub device_history: Vec<DeviceProfileVersion>,
pub quota: Option<QuotaData>,
/// Disabled accounts are ignored by the proxy token pool (e.g. revoked refresh_token -> invalid_grant).
#[serde(default)]
pub disabled: bool,
/// Optional human-readable reason for disabling.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub disabled_reason: Option<String>,
/// Unix timestamp when the account was disabled.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub disabled_at: Option<i64>,
/// User manually disabled proxy feature (does not affect app usage).
#[serde(default)]
pub proxy_disabled: bool,
/// Optional human-readable reason for proxy disabling.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub proxy_disabled_reason: Option<String>,
/// Unix timestamp when the proxy was disabled.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub proxy_disabled_at: Option<i64>,
/// 受配额保护禁用的模型列表 [NEW #621]
#[serde(default, skip_serializing_if = "HashSet::is_empty")]
pub protected_models: HashSet<String>,
/// [NEW] 403 验证阻止状态 (VALIDATION_REQUIRED)
#[serde(default)]
pub validation_blocked: bool,
/// [NEW] 验证阻止截止时间戳
#[serde(default, skip_serializing_if = "Option::is_none")]
pub validation_blocked_until: Option<i64>,
/// [NEW] 验证阻止原因
#[serde(default, skip_serializing_if = "Option::is_none")]
pub validation_blocked_reason: Option<String>,
/// [NEW] 验证链接 URL (#1522)
#[serde(default, skip_serializing_if = "Option::is_none")]
pub validation_url: Option<String>,
pub created_at: i64,
pub last_used: i64,
/// 绑定的代理 ID (None = 使用全局代理池)
#[serde(default, skip_serializing_if = "Option::is_none")]
pub proxy_id: Option<String>,
/// 代理绑定时间
#[serde(default, skip_serializing_if = "Option::is_none")]
pub proxy_bound_at: Option<i64>,
/// 用户自定义标签
#[serde(default, skip_serializing_if = "Option::is_none")]
pub custom_label: Option<String>,
}
impl Account {
pub fn new(id: String, email: String, token: TokenData) -> Self {
let now = chrono::Utc::now().timestamp();
Self {
id,
email,
name: None,
token,
device_profile: None,
device_history: Vec::new(),
quota: None,
disabled: false,
disabled_reason: None,
disabled_at: None,
proxy_disabled: false,
proxy_disabled_reason: None,
proxy_disabled_at: None,
protected_models: HashSet::new(),
validation_blocked: false,
validation_blocked_until: None,
validation_blocked_reason: None,
validation_url: None,
created_at: now,
last_used: now,
proxy_id: None,
proxy_bound_at: None,
custom_label: None,
}
}
pub fn update_last_used(&mut self) {
self.last_used = chrono::Utc::now().timestamp();
}
pub fn update_quota(&mut self, quota: QuotaData) {
self.quota = Some(quota);
}
}
/// 账号索引数据(accounts.json)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccountIndex {
pub version: String,
pub accounts: Vec<AccountSummary>,
pub current_account_id: Option<String>,
}
/// 账号摘要信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccountSummary {
pub id: String,
pub email: String,
pub name: Option<String>,
#[serde(default)]
pub disabled: bool,
#[serde(default)]
pub proxy_disabled: bool,
/// 受保护的模型列表 [NEW] 供 UI 显示锁定图标
#[serde(default, skip_serializing_if = "HashSet::is_empty")]
pub protected_models: HashSet<String>,
pub created_at: i64,
pub last_used: i64,
}
impl AccountIndex {
pub fn new() -> Self {
Self {
version: "2.0".to_string(),
accounts: Vec::new(),
current_account_id: None,
}
}
}
impl Default for AccountIndex {
fn default() -> Self {
Self::new()
}
}
/// 设备指纹(storage.json 中 telemetry 相关字段)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeviceProfile {
pub machine_id: String,
pub mac_machine_id: String,
pub dev_device_id: String,
pub sqm_id: String,
}
/// 指纹历史版本
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeviceProfileVersion {
pub id: String,
pub created_at: i64,
pub label: String,
pub profile: DeviceProfile,
#[serde(default)]
pub is_current: bool,
}
/// 导出账号项(用于备份/迁移)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccountExportItem {
pub email: String,
pub refresh_token: String,
}
/// 导出账号响应
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccountExportResponse {
pub accounts: Vec<AccountExportItem>,
}
|