Merge remote-tracking branch 'origin/pr/475'

# Conflicts:
#	apps/aether-gateway/src/handlers/admin/provider/oauth/dispatch/refresh/execution.rs
#	apps/aether-gateway/src/handlers/admin/provider/oauth/dispatch/refresh/response.rs
#	apps/aether-gateway/src/handlers/admin/provider/oauth/errors.rs
#	apps/aether-gateway/src/handlers/admin/provider/oauth/quota/shared.rs
#	apps/aether-gateway/src/state/oauth.rs
#	apps/aether-gateway/src/tests/control/admin/oauth.rs
#	crates/aether-admin/src/provider/quota.rs
This commit is contained in:
fawney19
2026-05-23 21:26:22 +08:00
11 changed files with 277 additions and 73 deletions
@@ -98,6 +98,10 @@ enum AccountSelfCheckOutcome {
status_code: Option<u16>,
message: String,
},
AutoRemoved {
status_code: Option<u16>,
message: String,
},
Failed {
status_code: Option<u16>,
message: String,
@@ -112,6 +116,7 @@ impl AccountSelfCheckOutcome {
match self {
Self::Success { .. } => "success",
Self::Blocked { .. } => "blocked",
Self::AutoRemoved { .. } => "auto_removed",
Self::Failed { .. } => "failed",
Self::Skipped { .. } => "skipped",
}
@@ -121,6 +126,7 @@ impl AccountSelfCheckOutcome {
match self {
Self::Success { status_code, .. }
| Self::Blocked { status_code, .. }
| Self::AutoRemoved { status_code, .. }
| Self::Failed { status_code, .. } => *status_code,
Self::Skipped { .. } => None,
}
@@ -130,6 +136,7 @@ impl AccountSelfCheckOutcome {
match self {
Self::Success { message, .. } => message.as_deref(),
Self::Blocked { message, .. }
| Self::AutoRemoved { message, .. }
| Self::Failed { message, .. }
| Self::Skipped { message, .. } => Some(message.as_str()),
}
@@ -392,6 +399,10 @@ fn quota_payload_result_for_key(key_id: &str, payload: Option<Value>) -> Account
.map(str::trim)
.filter(|value| !value.is_empty())
.map(ToOwned::to_owned);
let auto_removed = item
.get("auto_removed")
.and_then(Value::as_bool)
.unwrap_or(false);
if status == "success" {
return AccountSelfCheckOutcome::Success {
@@ -399,6 +410,12 @@ fn quota_payload_result_for_key(key_id: &str, payload: Option<Value>) -> Account
message,
};
}
if auto_removed {
return AccountSelfCheckOutcome::AutoRemoved {
status_code,
message: message.unwrap_or_else(|| "已自动删除".to_string()),
};
}
if quota_result_status_is_blocked(&status, status_code, message.as_deref()) {
return AccountSelfCheckOutcome::Blocked {
status_code,
@@ -499,6 +516,11 @@ async fn record_score_probe_result_for_key(
Some(PoolMemberHardState::Banned),
PoolMemberProbeStatus::Failed,
),
AccountSelfCheckOutcome::AutoRemoved { .. } => (
false,
Some(PoolMemberHardState::Banned),
PoolMemberProbeStatus::Failed,
),
AccountSelfCheckOutcome::Failed { .. } => (
false,
Some(PoolMemberHardState::Cooldown),
@@ -565,6 +587,9 @@ fn update_summary_from_outcome(
AccountSelfCheckOutcome::Blocked { .. } => {
summary.blocked = summary.blocked.saturating_add(1);
}
AccountSelfCheckOutcome::AutoRemoved { .. } => {
summary.auto_removed = summary.auto_removed.saturating_add(1);
}
AccountSelfCheckOutcome::Failed { .. } => {
summary.failed = summary.failed.saturating_add(1);
}
@@ -1227,6 +1227,24 @@ async fn perform_pool_quota_probe_for_provider(
now_ts: u64,
) -> Result<PoolQuotaProbeRunSummary, GatewayError> {
let mut summary = PoolQuotaProbeRunSummary::empty();
let provider_short_id = provider.id.chars().take(8).collect::<String>();
if aether_admin::provider::quota::provider_auto_remove_banned_keys(provider.config.as_ref()) {
let auto_removed = admin_state
.cleanup_known_banned_provider_catalog_keys(provider)
.await?;
if auto_removed > 0 {
summary.auto_removed += auto_removed;
info!(
event_name = "auto_removed_hard_banned",
provider_id = %provider_short_id,
provider_type,
auto_removed,
"gateway pool quota probe auto-cleaned known abnormal provider keys"
);
}
}
let Some(endpoint) = endpoint_for_probe_with_reconcile(
state,
admin_state,
@@ -1308,7 +1326,6 @@ async fn perform_pool_quota_probe_for_provider(
record_score_probe_in_progress_for_key(state, &provider.id, key_id, now_ts).await;
}
let provider_short_id = provider.id.chars().take(8).collect::<String>();
let probe_concurrency = pool_config.probe_concurrency.clamp(1, 64) as usize;
let probe_concurrency = probe_concurrency.min(config.global_concurrency).max(1);
let probe_results = stream::iter(keys.into_iter().map(|key| {