Merge remote-tracking branch 'upstream/main' into feat/500-api-key-ip-whitelist

This commit is contained in:
RWDai
2026-05-20 11:14:43 +08:00
53 changed files with 5596 additions and 446 deletions
+52 -23
View File
@@ -879,6 +879,7 @@ impl AppState {
&current_transport,
status_code,
body_excerpt.as_str(),
false,
)
.await
{
@@ -1212,11 +1213,12 @@ impl AppState {
Ok(())
}
async fn persist_local_oauth_refresh_failure_state(
pub(crate) async fn persist_local_oauth_refresh_failure_state(
&self,
transport: &provider_transport::GatewayProviderTransportSnapshot,
status_code: u16,
body_excerpt: &str,
access_token_invalid_proven: bool,
) -> Result<bool, GatewayError> {
let key_id = transport.key.id.trim();
if key_id.is_empty() {
@@ -1248,44 +1250,71 @@ impl AppState {
) else {
return Ok(false);
};
if latest_key.oauth_invalid_reason.as_deref() == Some(merged_reason.as_str())
&& latest_key.oauth_invalid_at_unix_secs.is_some()
{
return Ok(false);
}
let now_unix_secs = SystemTime::now()
.duration_since(UNIX_EPOCH)
.ok()
.map(|duration| duration.as_secs())
.unwrap_or(0);
latest_key.oauth_invalid_at_unix_secs = latest_key
.oauth_invalid_at_unix_secs
.or(Some(now_unix_secs));
latest_key.oauth_invalid_reason = Some(merged_reason);
latest_key.updated_at_unix_secs = Some(now_unix_secs);
let current_status_snapshot = latest_key.status_snapshot.take();
latest_key.status_snapshot =
sync_provider_key_oauth_status_snapshot(current_status_snapshot, &latest_key);
let mut updated = false;
if latest_key.oauth_invalid_reason.as_deref() != Some(merged_reason.as_str())
|| latest_key.oauth_invalid_at_unix_secs.is_none()
{
latest_key.oauth_invalid_at_unix_secs = latest_key
.oauth_invalid_at_unix_secs
.or(Some(now_unix_secs));
latest_key.oauth_invalid_reason = Some(merged_reason);
latest_key.updated_at_unix_secs = Some(now_unix_secs);
let current_status_snapshot = latest_key.status_snapshot.take();
latest_key.status_snapshot =
sync_provider_key_oauth_status_snapshot(current_status_snapshot, &latest_key);
let updated = self
.update_provider_catalog_key(&latest_key)
.await?
.is_some();
if updated {
self.clear_provider_transport_snapshot_cache();
let _ = self.invalidate_local_oauth_refresh_entry(key_id).await;
updated = self
.update_provider_catalog_key(&latest_key)
.await?
.is_some();
if updated {
self.clear_provider_transport_snapshot_cache();
let _ = self.invalidate_local_oauth_refresh_entry(key_id).await;
}
}
let auto_removed = if admin_provider_quota_pure::provider_auto_remove_banned_keys(
transport.provider.config.as_ref(),
) && admin_provider_quota_pure::should_auto_remove_oauth_invalid_key(
&latest_key,
None,
access_token_invalid_proven,
now_unix_secs,
) {
self.clear_provider_transport_snapshot_cache();
if self.delete_provider_catalog_key(key_id).await? {
let deleted_key_ids = [key_id.to_string()];
self.cleanup_deleted_provider_catalog_refs(
&transport.provider.id,
&[],
&deleted_key_ids,
)
.await?;
let _ = self.invalidate_local_oauth_refresh_entry(key_id).await;
true
} else {
false
}
} else {
false
};
tracing::info!(
key_id = %key_id,
provider_id = %transport.provider.id,
provider_type = %transport.provider.provider_type,
status_code,
updated,
cleared_provider_transport_snapshot_cache = updated,
auto_removed,
cleared_provider_transport_snapshot_cache = updated || auto_removed,
"gateway local oauth refresh failure state persisted"
);
Ok(updated)
Ok(auto_removed)
}
async fn execute_local_oauth_http_request(
@@ -144,9 +144,51 @@ impl AppState {
refund_id: &str,
) -> Result<Option<aether_data::repository::wallet::StoredAdminWalletRefund>, GatewayError>
{
#[cfg(test)]
if let Some(store) = self.admin_wallet_refund_store.as_ref() {
return Ok(store
.lock()
.expect("admin wallet refund store should lock")
.get(refund_id)
.filter(|refund| refund.wallet_id == wallet_id)
.cloned()
.map(test_admin_wallet_refund_to_stored));
}
self.data
.find_wallet_refund(wallet_id, refund_id)
.await
.map_err(|err| GatewayError::Internal(err.to_string()))
}
}
#[cfg(test)]
fn test_admin_wallet_refund_to_stored(
refund: crate::AdminWalletRefundRecord,
) -> aether_data::repository::wallet::StoredAdminWalletRefund {
aether_data::repository::wallet::StoredAdminWalletRefund {
id: refund.id,
refund_no: refund.refund_no,
wallet_id: refund.wallet_id,
user_id: refund.user_id,
payment_order_id: refund.payment_order_id,
source_type: refund.source_type,
source_id: refund.source_id,
refund_mode: refund.refund_mode,
amount_usd: refund.amount_usd,
status: refund.status,
reason: refund.reason,
failure_reason: refund.failure_reason,
gateway_refund_id: refund.gateway_refund_id,
payout_method: refund.payout_method,
payout_reference: refund.payout_reference,
payout_proof: refund.payout_proof,
requested_by: refund.requested_by,
approved_by: refund.approved_by,
processed_by: refund.processed_by,
created_at_unix_ms: refund.created_at_unix_ms,
updated_at_unix_secs: refund.updated_at_unix_secs,
processed_at_unix_secs: refund.processed_at_unix_secs,
completed_at_unix_secs: refund.completed_at_unix_secs,
}
}