mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-24 23:10:56 +08:00
chore: bump version to 0.17.7
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "proxycast",
|
||||
"private": true,
|
||||
"version": "0.17.6",
|
||||
"version": "0.17.7",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Generated
+1
-1
@@ -3377,7 +3377,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proxycast"
|
||||
version = "0.17.6"
|
||||
version = "0.17.7"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "proxycast"
|
||||
version = "0.17.6"
|
||||
version = "0.17.7"
|
||||
description = "AI API Proxy Desktop App"
|
||||
authors = ["you"]
|
||||
edition = "2021"
|
||||
|
||||
@@ -493,6 +493,7 @@ pub fn update_provider_pool_credential(
|
||||
request.check_health,
|
||||
request.check_model_name,
|
||||
request.not_supported_models,
|
||||
request.new_proxy_url,
|
||||
)?
|
||||
};
|
||||
|
||||
@@ -548,7 +549,7 @@ pub fn toggle_provider_pool_credential(
|
||||
) -> Result<ProviderCredential, String> {
|
||||
pool_service
|
||||
.0
|
||||
.update_credential(&db, &uuid, None, Some(is_disabled), None, None, None)
|
||||
.update_credential(&db, &uuid, None, Some(is_disabled), None, None, None, None)
|
||||
}
|
||||
|
||||
/// 重置凭证计数器
|
||||
|
||||
@@ -18,7 +18,7 @@ impl ProviderPoolDao {
|
||||
"SELECT uuid, provider_type, credential_data, name, is_healthy, is_disabled,
|
||||
check_health, check_model_name, not_supported_models, usage_count, error_count,
|
||||
last_used, last_error_time, last_error_message, last_health_check_time,
|
||||
last_health_check_model, created_at, updated_at, source
|
||||
last_health_check_model, created_at, updated_at, source, proxy_url
|
||||
FROM provider_pool_credentials
|
||||
ORDER BY provider_type, created_at ASC",
|
||||
)?;
|
||||
@@ -41,7 +41,7 @@ impl ProviderPoolDao {
|
||||
"SELECT uuid, provider_type, credential_data, name, is_healthy, is_disabled,
|
||||
check_health, check_model_name, not_supported_models, usage_count, error_count,
|
||||
last_used, last_error_time, last_error_message, last_health_check_time,
|
||||
last_health_check_model, created_at, updated_at, source
|
||||
last_health_check_model, created_at, updated_at, source, proxy_url
|
||||
FROM provider_pool_credentials
|
||||
WHERE provider_type = ?1
|
||||
ORDER BY created_at ASC",
|
||||
@@ -67,7 +67,7 @@ impl ProviderPoolDao {
|
||||
"SELECT uuid, provider_type, credential_data, name, is_healthy, is_disabled,
|
||||
check_health, check_model_name, not_supported_models, usage_count, error_count,
|
||||
last_used, last_error_time, last_error_message, last_health_check_time,
|
||||
last_health_check_model, created_at, updated_at, source
|
||||
last_health_check_model, created_at, updated_at, source, proxy_url
|
||||
FROM provider_pool_credentials
|
||||
WHERE uuid = ?1",
|
||||
)?;
|
||||
@@ -89,7 +89,7 @@ impl ProviderPoolDao {
|
||||
"SELECT uuid, provider_type, credential_data, name, is_healthy, is_disabled,
|
||||
check_health, check_model_name, not_supported_models, usage_count, error_count,
|
||||
last_used, last_error_time, last_error_message, last_health_check_time,
|
||||
last_health_check_model, created_at, updated_at, source
|
||||
last_health_check_model, created_at, updated_at, source, proxy_url
|
||||
FROM provider_pool_credentials
|
||||
WHERE name = ?1",
|
||||
)?;
|
||||
@@ -131,8 +131,8 @@ impl ProviderPoolDao {
|
||||
(uuid, provider_type, credential_data, name, is_healthy, is_disabled,
|
||||
check_health, check_model_name, not_supported_models, usage_count, error_count,
|
||||
last_used, last_error_time, last_error_message, last_health_check_time,
|
||||
last_health_check_model, created_at, updated_at, source)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19)",
|
||||
last_health_check_model, created_at, updated_at, source, proxy_url)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20)",
|
||||
params![
|
||||
cred.uuid,
|
||||
cred.provider_type.to_string(),
|
||||
@@ -153,6 +153,7 @@ impl ProviderPoolDao {
|
||||
cred.created_at.timestamp(),
|
||||
cred.updated_at.timestamp(),
|
||||
source_str,
|
||||
cred.proxy_url,
|
||||
],
|
||||
)?;
|
||||
Ok(())
|
||||
@@ -171,7 +172,7 @@ impl ProviderPoolDao {
|
||||
is_disabled = ?6, check_health = ?7, check_model_name = ?8,
|
||||
not_supported_models = ?9, usage_count = ?10, error_count = ?11,
|
||||
last_used = ?12, last_error_time = ?13, last_error_message = ?14,
|
||||
last_health_check_time = ?15, last_health_check_model = ?16, updated_at = ?17
|
||||
last_health_check_time = ?15, last_health_check_model = ?16, updated_at = ?17, proxy_url = ?18
|
||||
WHERE uuid = ?1",
|
||||
params![
|
||||
cred.uuid,
|
||||
@@ -191,6 +192,7 @@ impl ProviderPoolDao {
|
||||
cred.last_health_check_time.map(|t| t.timestamp()),
|
||||
cred.last_health_check_model,
|
||||
cred.updated_at.timestamp(),
|
||||
cred.proxy_url,
|
||||
],
|
||||
)?;
|
||||
Ok(())
|
||||
@@ -305,6 +307,7 @@ impl ProviderPoolDao {
|
||||
let created_at_ts: i64 = row.get(16)?;
|
||||
let updated_at_ts: i64 = row.get(17)?;
|
||||
let source_str: Option<String> = row.get(18).ok();
|
||||
let proxy_url: Option<String> = row.get(19).ok();
|
||||
|
||||
let provider_type: PoolProviderType =
|
||||
provider_type_str.parse().unwrap_or(PoolProviderType::Kiro);
|
||||
@@ -351,6 +354,7 @@ impl ProviderPoolDao {
|
||||
.unwrap_or_default(),
|
||||
cached_token: None, // 从 get_token_cache 单独获取
|
||||
source,
|
||||
proxy_url,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -157,5 +157,122 @@ pub fn create_tables(conn: &Connection) -> Result<(), rusqlite::Error> {
|
||||
[],
|
||||
);
|
||||
|
||||
// Migration: 添加代理URL字段 - 使用重建表结构的方式
|
||||
migrate_add_proxy_url_column(conn)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 迁移:添加proxy_url列到provider_pool_credentials表
|
||||
/// 使用重建表结构的方式确保数据完整性
|
||||
fn migrate_add_proxy_url_column(conn: &Connection) -> Result<(), rusqlite::Error> {
|
||||
// 检查是否已经存在proxy_url列
|
||||
let mut stmt = conn.prepare("PRAGMA table_info(provider_pool_credentials)")?;
|
||||
let column_info: Vec<String> = stmt
|
||||
.query_map([], |row| {
|
||||
let column_name: String = row.get(1)?;
|
||||
Ok(column_name)
|
||||
})?
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
// 如果proxy_url列已存在,跳过迁移
|
||||
if column_info.contains(&"proxy_url".to_string()) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
tracing::info!("开始迁移:添加proxy_url列到provider_pool_credentials表");
|
||||
|
||||
// 开始事务
|
||||
conn.execute("BEGIN TRANSACTION", [])?;
|
||||
|
||||
let migration_result = (|| -> Result<(), rusqlite::Error> {
|
||||
// 1. 备份现有数据
|
||||
conn.execute(
|
||||
"CREATE TABLE provider_pool_credentials_backup AS
|
||||
SELECT * FROM provider_pool_credentials",
|
||||
[],
|
||||
)?;
|
||||
|
||||
// 2. 删除原表
|
||||
conn.execute("DROP TABLE provider_pool_credentials", [])?;
|
||||
|
||||
// 3. 重建表结构(包含proxy_url列)
|
||||
conn.execute(
|
||||
"CREATE TABLE provider_pool_credentials (
|
||||
uuid TEXT PRIMARY KEY,
|
||||
provider_type TEXT NOT NULL,
|
||||
credential_data TEXT NOT NULL,
|
||||
name TEXT,
|
||||
is_healthy INTEGER DEFAULT 1,
|
||||
is_disabled INTEGER DEFAULT 0,
|
||||
check_health INTEGER DEFAULT 1,
|
||||
check_model_name TEXT,
|
||||
not_supported_models TEXT,
|
||||
usage_count INTEGER DEFAULT 0,
|
||||
error_count INTEGER DEFAULT 0,
|
||||
last_used INTEGER,
|
||||
last_error_time INTEGER,
|
||||
last_error_message TEXT,
|
||||
last_health_check_time INTEGER,
|
||||
last_health_check_model TEXT,
|
||||
proxy_url TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
cached_access_token TEXT,
|
||||
cached_refresh_token TEXT,
|
||||
token_expiry_time TEXT,
|
||||
last_refresh_time TEXT,
|
||||
refresh_error_count INTEGER DEFAULT 0,
|
||||
last_refresh_error TEXT,
|
||||
source TEXT DEFAULT 'manual'
|
||||
)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
// 4. 恢复数据(proxy_url默认为NULL)
|
||||
conn.execute(
|
||||
"INSERT INTO provider_pool_credentials (
|
||||
uuid, provider_type, credential_data, name, is_healthy, is_disabled,
|
||||
check_health, check_model_name, not_supported_models, usage_count,
|
||||
error_count, last_used, last_error_time, last_error_message,
|
||||
last_health_check_time, last_health_check_model, proxy_url,
|
||||
created_at, updated_at, cached_access_token, cached_refresh_token,
|
||||
token_expiry_time, last_refresh_time, refresh_error_count,
|
||||
last_refresh_error, source
|
||||
) SELECT
|
||||
uuid, provider_type, credential_data, name, is_healthy, is_disabled,
|
||||
check_health, check_model_name, not_supported_models, usage_count,
|
||||
error_count, last_used, last_error_time, last_error_message,
|
||||
last_health_check_time, last_health_check_model, NULL as proxy_url,
|
||||
created_at, updated_at, cached_access_token, cached_refresh_token,
|
||||
token_expiry_time, last_refresh_time, refresh_error_count,
|
||||
last_refresh_error, source
|
||||
FROM provider_pool_credentials_backup",
|
||||
[],
|
||||
)?;
|
||||
|
||||
// 5. 重建索引
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_provider_pool_type ON provider_pool_credentials(provider_type)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
// 6. 删除备份表
|
||||
conn.execute("DROP TABLE provider_pool_credentials_backup", [])?;
|
||||
|
||||
Ok(())
|
||||
})();
|
||||
|
||||
match migration_result {
|
||||
Ok(()) => {
|
||||
conn.execute("COMMIT", [])?;
|
||||
tracing::info!("proxy_url列迁移成功完成");
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
conn.execute("ROLLBACK", [])?;
|
||||
tracing::error!("proxy_url列迁移失败,已回滚: {}", e);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,6 +228,8 @@ pub struct ProviderCredential {
|
||||
/// 凭证来源(手动添加/导入/私有)
|
||||
#[serde(default)]
|
||||
pub source: CredentialSource,
|
||||
/// 代理 URL(可覆盖全局代理设置)
|
||||
pub proxy_url: Option<String>,
|
||||
}
|
||||
|
||||
fn default_true() -> bool {
|
||||
@@ -259,6 +261,7 @@ impl ProviderCredential {
|
||||
updated_at: now,
|
||||
cached_token: None,
|
||||
source: CredentialSource::Manual,
|
||||
proxy_url: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,6 +529,8 @@ pub struct CredentialDisplay {
|
||||
pub base_url: Option<String>,
|
||||
/// API Key 凭证的完整 api_key(仅用于 OpenAI/Claude API Key 类型,用于编辑)
|
||||
pub api_key: Option<String>,
|
||||
/// 凭证级代理 URL(可覆盖全局代理设置)
|
||||
pub proxy_url: Option<String>,
|
||||
}
|
||||
|
||||
/// 获取凭证类型字符串
|
||||
@@ -623,6 +628,7 @@ impl From<&ProviderCredential> for CredentialDisplay {
|
||||
source: cred.source,
|
||||
base_url: get_base_url(&cred.credential),
|
||||
api_key: get_api_key(&cred.credential),
|
||||
proxy_url: cred.proxy_url.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -664,7 +670,7 @@ pub struct AddCredentialRequest {
|
||||
pub check_model_name: Option<String>,
|
||||
}
|
||||
|
||||
/// 更新凭证的请求结构
|
||||
/// 更新凭证请求
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UpdateCredentialRequest {
|
||||
pub name: Option<String>,
|
||||
@@ -680,6 +686,8 @@ pub struct UpdateCredentialRequest {
|
||||
pub new_base_url: Option<String>,
|
||||
/// API Key 相关:新的 api_key(仅适用于 API Key 凭证)
|
||||
pub new_api_key: Option<String>,
|
||||
/// 新的代理 URL(可覆盖全局代理设置)
|
||||
pub new_proxy_url: Option<String>,
|
||||
}
|
||||
|
||||
pub type ProviderPools = HashMap<PoolProviderType, Vec<ProviderCredential>>;
|
||||
@@ -747,6 +755,7 @@ mod tests {
|
||||
updated_at: Utc::now(),
|
||||
cached_token: None,
|
||||
source: CredentialSource::Manual,
|
||||
proxy_url: None,
|
||||
};
|
||||
|
||||
assert!(!cred.supports_model("claude-opus"));
|
||||
@@ -780,6 +789,7 @@ mod tests {
|
||||
updated_at: Utc::now(),
|
||||
cached_token: None,
|
||||
source: CredentialSource::Manual,
|
||||
proxy_url: None,
|
||||
};
|
||||
|
||||
// Exact match exclusion
|
||||
@@ -815,6 +825,7 @@ mod tests {
|
||||
updated_at: Utc::now(),
|
||||
cached_token: None,
|
||||
source: CredentialSource::Manual,
|
||||
proxy_url: None,
|
||||
};
|
||||
|
||||
// Prefix wildcard exclusion
|
||||
@@ -854,6 +865,7 @@ mod tests {
|
||||
updated_at: Utc::now(),
|
||||
cached_token: None,
|
||||
source: CredentialSource::Manual,
|
||||
proxy_url: None,
|
||||
};
|
||||
|
||||
// Contains wildcard exclusion
|
||||
@@ -890,6 +902,7 @@ mod tests {
|
||||
updated_at: Utc::now(),
|
||||
cached_token: None,
|
||||
source: CredentialSource::Manual,
|
||||
proxy_url: None,
|
||||
};
|
||||
|
||||
// Excluded by not_supported_models (exact match)
|
||||
@@ -927,6 +940,7 @@ mod tests {
|
||||
updated_at: Utc::now(),
|
||||
cached_token: None,
|
||||
source: CredentialSource::Manual,
|
||||
proxy_url: None,
|
||||
};
|
||||
|
||||
// All models should be supported since not_supported_models is empty
|
||||
|
||||
@@ -131,6 +131,7 @@ impl ProviderPoolService {
|
||||
check_health: Option<bool>,
|
||||
check_model_name: Option<String>,
|
||||
not_supported_models: Option<Vec<String>>,
|
||||
proxy_url: Option<String>,
|
||||
) -> Result<ProviderCredential, String> {
|
||||
let conn = db.lock().map_err(|e| e.to_string())?;
|
||||
let mut cred = ProviderPoolDao::get_by_uuid(&conn, uuid)
|
||||
@@ -154,6 +155,10 @@ impl ProviderPoolService {
|
||||
if let Some(models) = not_supported_models {
|
||||
cred.not_supported_models = models;
|
||||
}
|
||||
// 处理 proxy_url:空字符串表示清除,None 表示不修改
|
||||
if let Some(p) = proxy_url {
|
||||
cred.proxy_url = if p.is_empty() { None } else { Some(p) };
|
||||
}
|
||||
cred.updated_at = Utc::now();
|
||||
|
||||
ProviderPoolDao::update(&conn, &cred).map_err(|e| e.to_string())?;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "ProxyCast",
|
||||
"version": "0.17.6",
|
||||
"version": "0.17.7",
|
||||
"identifier": "com.proxycast.app",
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
|
||||
Reference in New Issue
Block a user