feat(ccswitch): 添加一键导入和用量查询

This commit is contained in:
Entropy.Xu
2026-05-29 21:39:45 +08:00
parent 0d76a8e478
commit 7ed4b84654
23 changed files with 1720 additions and 48 deletions
@@ -195,6 +195,9 @@ fn select_primary_credential(
if signature.starts_with("openai:") {
return select_openai_credential(bundle);
}
if signature.starts_with("aether:") {
return select_openai_credential(bundle);
}
select_generic_credential(bundle)
}
@@ -826,8 +826,9 @@ async fn build_data_backed_auth_context(
.map(|(provider, _)| provider)
.unwrap_or(auth_endpoint_signature)
.trim();
let requested_provider_allowed =
auth_snapshot_allows_requested_provider(state, &snapshot, auth_endpoint_signature).await;
let identity_only = auth_gate_identity_only(auth_endpoint_signature);
let requested_provider_allowed = identity_only
|| auth_snapshot_allows_requested_provider(state, &snapshot, auth_endpoint_signature).await;
let local_rejection = if invalid_api_key {
Some(GatewayLocalAuthRejection::InvalidApiKey)
} else if locked_api_key {
@@ -845,14 +846,15 @@ async fn build_data_backed_auth_context(
Some(GatewayLocalAuthRejection::ProviderNotAllowed {
provider: requested_provider.to_string(),
})
} else if snapshot
.effective_allowed_api_formats()
.is_some_and(|allowed| {
!contains_api_format_or_alias(
allowed,
auth_gate_api_format(auth_endpoint_signature).as_str(),
)
})
} else if !identity_only
&& snapshot
.effective_allowed_api_formats()
.is_some_and(|allowed| {
!contains_api_format_or_alias(
allowed,
auth_gate_api_format(auth_endpoint_signature).as_str(),
)
})
{
Some(GatewayLocalAuthRejection::ApiFormatNotAllowed {
api_format: auth_endpoint_signature.to_string(),
@@ -896,6 +898,13 @@ fn auth_gate_api_format(auth_endpoint_signature: &str) -> String {
}
}
fn auth_gate_identity_only(auth_endpoint_signature: &str) -> bool {
matches!(
auth_endpoint_signature.trim().to_ascii_lowercase().as_str(),
"aether:ccswitch_usage"
)
}
fn api_format_matches(left: &str, right: &str) -> bool {
aether_scheduler_core::api_format_matches_allowed_value(left, right)
}
@@ -505,6 +505,19 @@ pub(super) fn classify_public_support_route(
"public:payment",
false,
))
} else if method == http::Method::GET
&& matches!(
normalized_path,
"/api/ccswitch/usage" | "/api/ccswitch/usage/"
)
{
Some(classified(
"public_support",
"ccswitch",
"usage",
"aether:ccswitch_usage",
false,
))
} else if method == http::Method::GET
&& matches!(
normalized_path,
@@ -517,6 +530,7 @@ pub(super) fn classify_public_support_route(
| "/api/users/me/usage/heatmap"
| "/api/users/me/providers"
| "/api/users/me/available-models"
| "/api/users/me/client-config"
| "/api/users/me/endpoint-status"
| "/api/users/me/preferences"
| "/api/users/me/referral"
@@ -533,6 +547,7 @@ pub(super) fn classify_public_support_route(
"/api/users/me/usage/heatmap" => "usage_heatmap",
"/api/users/me/providers" => "providers",
"/api/users/me/available-models" => "available_models",
"/api/users/me/client-config" => "client_config",
"/api/users/me/endpoint-status" => "endpoint_status",
"/api/users/me/preferences" => "preferences",
"/api/users/me/referral" => "referral",
@@ -463,6 +463,23 @@ fn classifies_users_me_routes_as_public_support_route() {
}
}
#[test]
fn classifies_ccswitch_usage_as_api_key_public_support_route() {
let headers = headers(&[]);
let uri: Uri = "/api/ccswitch/usage".parse().expect("uri should parse");
let decision =
classify_control_route(&http::Method::GET, &uri, &headers).expect("route should classify");
assert_eq!(decision.route_class.as_deref(), Some("public_support"));
assert_eq!(decision.route_family.as_deref(), Some("ccswitch"));
assert_eq!(decision.route_kind.as_deref(), Some("usage"));
assert_eq!(
decision.auth_endpoint_signature.as_deref(),
Some("aether:ccswitch_usage")
);
assert!(!decision.is_execution_runtime_candidate());
}
#[test]
fn user_api_key_install_session_create_buffers_request_body() {
let headers = headers(&[]);