mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-10 05:00:19 +08:00
Merge pull request #664 from MMEXA/codex/wallet-auth-cache-delay-20260706
修复钱包余额变更后的鉴权缓存延迟
This commit is contained in:
@@ -196,7 +196,11 @@ impl AppState {
|
||||
order.credited_at_unix_secs = Some(now_unix_secs);
|
||||
order.refundable_amount_usd = order.amount_usd;
|
||||
order.gateway_response = Some(serde_json::Value::Object(gateway_response));
|
||||
return Ok(AdminWalletMutationOutcome::Applied((order.clone(), true)));
|
||||
let updated_order = order.clone();
|
||||
drop(wallets);
|
||||
drop(orders);
|
||||
self.invalidate_auth_context_cache();
|
||||
return Ok(AdminWalletMutationOutcome::Applied((updated_order, true)));
|
||||
}
|
||||
|
||||
match self
|
||||
@@ -344,10 +348,18 @@ impl AppState {
|
||||
input: aether_data::repository::wallet::RedeemWalletCodeInput,
|
||||
) -> Result<Option<aether_data::repository::wallet::RedeemWalletCodeOutcome>, GatewayError>
|
||||
{
|
||||
self.data
|
||||
let outcome = self
|
||||
.data
|
||||
.redeem_wallet_code(input)
|
||||
.await
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
||||
if matches!(
|
||||
outcome,
|
||||
Some(aether_data::repository::wallet::RedeemWalletCodeOutcome::Redeemed { .. })
|
||||
) {
|
||||
self.invalidate_auth_context_cache();
|
||||
}
|
||||
Ok(outcome)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,10 @@ impl AppState {
|
||||
),
|
||||
created_at_unix_ms: chrono::Utc::now().timestamp().max(0) as u64,
|
||||
};
|
||||
return Ok(Some((wallet.clone(), transaction)));
|
||||
let updated_wallet = wallet.clone();
|
||||
drop(guard);
|
||||
self.invalidate_auth_context_cache();
|
||||
return Ok(Some((updated_wallet, transaction)));
|
||||
}
|
||||
|
||||
Ok(self
|
||||
@@ -153,7 +156,10 @@ impl AppState {
|
||||
credited_at_unix_secs: Some(created_at),
|
||||
expires_at_unix_secs: None,
|
||||
};
|
||||
return Ok(Some((wallet.clone(), order)));
|
||||
let updated_wallet = wallet.clone();
|
||||
drop(guard);
|
||||
self.invalidate_auth_context_cache();
|
||||
return Ok(Some((updated_wallet, order)));
|
||||
}
|
||||
|
||||
let now = chrono::Utc::now();
|
||||
|
||||
@@ -44,10 +44,15 @@ impl AppState {
|
||||
&self,
|
||||
input: ProcessPaymentCallbackInput,
|
||||
) -> Result<Option<ProcessPaymentCallbackOutcome>, GatewayError> {
|
||||
self.data
|
||||
let outcome = self
|
||||
.data
|
||||
.process_payment_callback(input)
|
||||
.await
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
||||
if matches!(outcome, Some(ProcessPaymentCallbackOutcome::Applied { .. })) {
|
||||
self.invalidate_auth_context_cache();
|
||||
}
|
||||
Ok(outcome)
|
||||
}
|
||||
|
||||
pub(crate) async fn adjust_wallet_balance(
|
||||
@@ -60,10 +65,15 @@ impl AppState {
|
||||
)>,
|
||||
GatewayError,
|
||||
> {
|
||||
self.data
|
||||
let result = self
|
||||
.data
|
||||
.adjust_wallet_balance(input)
|
||||
.await
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
||||
if result.is_some() {
|
||||
self.invalidate_auth_context_cache();
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub(crate) async fn create_manual_wallet_recharge(
|
||||
@@ -76,10 +86,15 @@ impl AppState {
|
||||
)>,
|
||||
GatewayError,
|
||||
> {
|
||||
self.data
|
||||
let result = self
|
||||
.data
|
||||
.create_manual_wallet_recharge(input)
|
||||
.await
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
||||
if result.is_some() {
|
||||
self.invalidate_auth_context_cache();
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub(crate) async fn process_admin_wallet_refund(
|
||||
@@ -95,10 +110,15 @@ impl AppState {
|
||||
>,
|
||||
GatewayError,
|
||||
> {
|
||||
self.data
|
||||
let outcome = self
|
||||
.data
|
||||
.process_admin_wallet_refund(input)
|
||||
.await
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
||||
if matches!(outcome, Some(WalletMutationOutcome::Applied(_))) {
|
||||
self.invalidate_auth_context_cache();
|
||||
}
|
||||
Ok(outcome)
|
||||
}
|
||||
|
||||
pub(crate) async fn complete_admin_wallet_refund(
|
||||
@@ -127,10 +147,18 @@ impl AppState {
|
||||
>,
|
||||
GatewayError,
|
||||
> {
|
||||
self.data
|
||||
let outcome = self
|
||||
.data
|
||||
.fail_admin_wallet_refund(input)
|
||||
.await
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
||||
if matches!(
|
||||
outcome,
|
||||
Some(WalletMutationOutcome::Applied((_, _, Some(_))))
|
||||
) {
|
||||
self.invalidate_auth_context_cache();
|
||||
}
|
||||
Ok(outcome)
|
||||
}
|
||||
|
||||
pub(crate) async fn expire_admin_payment_order(
|
||||
@@ -176,9 +204,14 @@ impl AppState {
|
||||
>,
|
||||
GatewayError,
|
||||
> {
|
||||
self.data
|
||||
let outcome = self
|
||||
.data
|
||||
.credit_admin_payment_order(input)
|
||||
.await
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
||||
if matches!(outcome, Some(WalletMutationOutcome::Applied((_, true)))) {
|
||||
self.invalidate_auth_context_cache();
|
||||
}
|
||||
Ok(outcome)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ impl AppState {
|
||||
.insert(updated_order.id.clone(), updated_order);
|
||||
}
|
||||
|
||||
self.invalidate_auth_context_cache();
|
||||
return Ok(AdminWalletMutationOutcome::Applied((
|
||||
updated_wallet,
|
||||
updated_refund,
|
||||
@@ -354,6 +355,7 @@ impl AppState {
|
||||
.expect("admin wallet refund store should lock")
|
||||
.insert(updated_refund.id.clone(), updated_refund.clone());
|
||||
|
||||
self.invalidate_auth_context_cache();
|
||||
return Ok(AdminWalletMutationOutcome::Applied((
|
||||
updated_wallet,
|
||||
updated_refund,
|
||||
|
||||
@@ -257,6 +257,44 @@ mod tests {
|
||||
assert_eq!(decision.remaining, Some(4.0));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn admin_wallet_recharge_invalidates_cached_auth_capacity_state() {
|
||||
let wallet = empty_user_wallet();
|
||||
let state =
|
||||
state_with_wallet_and_quota(wallet.clone(), None).with_auth_wallets_for_tests([wallet]);
|
||||
let auth_snapshot = ordinary_user_api_key_snapshot();
|
||||
|
||||
let denied = resolve_wallet_auth_gate(&state, &auth_snapshot)
|
||||
.await
|
||||
.expect("wallet gate should resolve")
|
||||
.expect("wallet gate should return a decision");
|
||||
|
||||
assert!(!denied.allowed);
|
||||
assert_eq!(denied.failure, Some(WalletAccessFailure::BalanceDenied));
|
||||
|
||||
let recharge = state
|
||||
.admin_create_manual_wallet_recharge(
|
||||
"wallet-user-1",
|
||||
10.0,
|
||||
"admin_manual",
|
||||
Some("admin-1"),
|
||||
Some("manual recharge"),
|
||||
)
|
||||
.await
|
||||
.expect("wallet recharge should complete");
|
||||
|
||||
assert!(recharge.is_some());
|
||||
|
||||
let refreshed = resolve_wallet_auth_gate(&state, &auth_snapshot)
|
||||
.await
|
||||
.expect("wallet gate should resolve after recharge")
|
||||
.expect("wallet gate should return a decision after recharge");
|
||||
|
||||
assert!(refreshed.allowed);
|
||||
assert_eq!(refreshed.failure, None);
|
||||
assert_eq!(refreshed.remaining, Some(10.0));
|
||||
}
|
||||
|
||||
fn state_with_wallet_and_quota(
|
||||
wallet: StoredWalletSnapshot,
|
||||
quota: Option<UserDailyQuotaAvailabilityRecord>,
|
||||
|
||||
Reference in New Issue
Block a user