1use std::convert::Infallible;
4use std::future::Future;
5#[cfg(feature = "siwx")]
6use std::pin::Pin;
7use std::sync::Arc;
8
9use axum_core::extract::Request;
10use axum_core::response::Response;
11use r402_protocol::error::FacilitatorError;
12use r402_protocol::payment::{PriceTag, ResourceInfo, SettleResponse, SettlementOverrides};
13use r402_server::{
14 AfterHandler, BackgroundSettlementTracker, CancellationGuard, CompletedSettlement,
15 PaymentFlowName, ResourceServer, ScheduledSettlement, SequentialFinish, SettlePhase,
16 SettlementMode, finish, run, schedule,
17};
18use tower::Service;
19
20use super::fail::GateError;
21use super::hooks::DynGateHooks;
22use super::overrides::strip_response_settlement_overrides;
23use super::receipt::{
24 attach_failure_path_settlement, attach_payment_response, skip_handler_response,
25};
26use super::verify::{
27 HANDLER_FAILED, VerifiedPayment, cancellation_guard, handler_failed_reason, map_settle,
28 payment_flow_of, phases_of, settle_before_handler_if_needed,
29};
30
31pub struct Gate {
33 pub(crate) server: ResourceServer,
34 pub(crate) accepts: Arc<[PriceTag]>,
35 pub(crate) resource: ResourceInfo,
36 pub(crate) payment_required: Option<r402_protocol::payment::PaymentRequired>,
37 pub(crate) hooks: Option<Arc<dyn DynGateHooks>>,
38 pub(crate) settlement_mode: SettlementMode,
39 pub(crate) settlement_tracker: Option<BackgroundSettlementTracker>,
40 #[cfg(feature = "siwx")]
41 pub(crate) siwx: Option<Arc<super::SiwxGate>>,
42}
43
44impl std::fmt::Debug for Gate {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 f.debug_struct("Gate")
47 .field("accepts", &self.accepts.len())
48 .field("resource", &self.resource)
49 .field("settlement_mode", &self.settlement_mode)
50 .finish_non_exhaustive()
51 }
52}
53
54enum Prepared {
55 Skipped(Response),
56 Ready {
57 verified: Box<VerifiedPayment>,
58 before_handler: Option<Box<CompletedSettlement>>,
59 },
60}
61
62#[derive(Debug)]
63enum ConcurrentHandlerError {
64 Failed(Box<Response>),
65 SettlementAborted(String),
66}
67
68impl Gate {
69 pub(crate) fn from_parts(
70 server: ResourceServer,
71 accepts: Vec<PriceTag>,
72 resource: ResourceInfo,
73 settlement_mode: SettlementMode,
74 settlement_tracker: Option<BackgroundSettlementTracker>,
75 hooks: Option<Arc<dyn DynGateHooks>>,
76 #[cfg(feature = "siwx")] siwx: Option<Arc<super::SiwxGate>>,
77 ) -> Self {
78 Self {
79 server,
80 accepts: accepts.into(),
81 resource,
82 payment_required: None,
83 hooks,
84 settlement_mode,
85 settlement_tracker,
86 #[cfg(feature = "siwx")]
87 siwx,
88 }
89 }
90
91 #[cfg(feature = "siwx")]
93 pub(crate) fn attach_siwx_challenge(
94 &mut self,
95 siwx: &super::SiwxGate,
96 path: &str,
97 ) -> Result<(), GateError> {
98 let Some(payment_required) = self.payment_required.as_mut() else {
99 return Ok(());
100 };
101 let entry = siwx
102 .challenge_entry(path)
103 .map_err(|err| GateError::PaymentRequiredBuild(err.to_string()))?;
104 payment_required.extensions.insert(super::SIWX_KEY, entry);
105 Ok(())
106 }
107
108 fn record_siwx_success(&self, path: &str, settlement: &SettleResponse) {
109 #[cfg(feature = "siwx")]
110 if let Some(siwx) = self.siwx.as_ref() {
111 record_paid_address(siwx, path, settlement);
112 }
113 #[cfg(not(feature = "siwx"))]
114 {
115 let _ = (path, settlement);
116 }
117 }
118
119 #[must_use]
121 pub const fn resource_server(&self) -> &ResourceServer {
122 &self.server
123 }
124
125 #[must_use]
127 pub fn accepts(&self) -> &[PriceTag] {
128 &self.accepts
129 }
130
131 #[must_use]
133 pub const fn resource(&self) -> &ResourceInfo {
134 &self.resource
135 }
136
137 #[must_use]
139 pub const fn payment_required(&self) -> Option<&r402_protocol::payment::PaymentRequired> {
140 self.payment_required.as_ref()
141 }
142
143 pub async fn require_schemes(&self) -> Result<(), GateError> {
149 for tag in self.accepts.iter() {
150 let requirements = &tag.requirements;
151 if self
152 .server
153 .registered_scheme(requirements.scheme.as_str(), &requirements.network)
154 .is_none()
155 {
156 return Err(GateError::MissingScheme {
157 scheme: requirements.scheme.clone(),
158 network: requirements.network.clone(),
159 });
160 }
161 let flow = payment_flow_of(&self.server, requirements)?;
162 if flow == PaymentFlowName::Escrow
163 && !self.server.has_settle_on_cancel(requirements).await
164 {
165 return Err(GateError::MissingSettleOnCancel {
166 scheme: requirements.scheme.clone(),
167 });
168 }
169 }
170 Ok(())
171 }
172
173 pub fn assert_mode_compatible(&self, mode: SettlementMode) -> Result<(), GateError> {
179 if mode == SettlementMode::Sequential {
180 return Ok(());
181 }
182 for tag in self.accepts.iter() {
183 let flow = payment_flow_of(&self.server, &tag.requirements)?;
184 let phases = flow.phases();
185 if let Err(err) = schedule(phases, mode) {
186 return Err(GateError::IncompatibleSettlementMode {
187 mode: err.mode,
188 flow: err.flow,
189 });
190 }
191 }
192 Ok(())
193 }
194
195 pub async fn handle_request<S>(&self, inner: S, mut req: Request) -> Result<Response, GateError>
203 where
204 S: Service<Request, Response = Response, Error = Infallible>,
205 S::Future: Send,
206 {
207 let path = req.uri().path().to_owned();
208 match self.prepare(&mut req).await? {
209 Prepared::Skipped(response) => Ok(response),
210 Prepared::Ready {
211 verified,
212 before_handler,
213 } => {
214 sequential_after_verify(
215 self,
216 &path,
217 inner,
218 req,
219 *verified,
220 before_handler.map(|b| *b),
221 )
222 .await
223 }
224 }
225 }
226
227 pub async fn handle_request_concurrent<S>(
234 &self,
235 inner: S,
236 mut req: Request,
237 ) -> Result<Response, GateError>
238 where
239 S: Service<Request, Response = Response, Error = Infallible> + Send,
240 S::Future: Send,
241 {
242 let path = req.uri().path().to_owned();
243 match self.prepare(&mut req).await? {
244 Prepared::Skipped(response) => Ok(response),
245 Prepared::Ready {
246 verified,
247 before_handler,
248 } => {
249 concurrent_after_verify(
250 self,
251 &path,
252 inner,
253 req,
254 *verified,
255 before_handler.map(|b| *b),
256 )
257 .await
258 }
259 }
260 }
261
262 pub async fn handle_request_background<S>(
268 &self,
269 inner: S,
270 mut req: Request,
271 ) -> Result<Response, GateError>
272 where
273 S: Service<Request, Response = Response, Error = Infallible> + Send,
274 S::Future: Send,
275 {
276 let path = req.uri().path().to_owned();
277 match self.prepare(&mut req).await? {
278 Prepared::Skipped(response) => Ok(response),
279 Prepared::Ready {
280 verified,
281 before_handler,
282 } => {
283 background_after_verify(
284 self,
285 &path,
286 inner,
287 req,
288 *verified,
289 before_handler.map(|b| *b),
290 )
291 .await
292 }
293 }
294 }
295
296 async fn prepare(&self, req: &mut Request) -> Result<Prepared, GateError> {
297 let verified = self.verify_only(req.headers()).await?;
298 if let Some(h) = self.hooks.as_ref() {
299 h.on_payment_verified(req).await;
300 }
301 if let Some(directive) = verified.skip_handler.clone() {
302 let receipt = sequential_after_handler(&verified, None, None).await?;
303 self.record_siwx_success(req.uri().path(), &receipt);
304 return Ok(Prepared::Skipped(skip_handler_response(
305 &directive, &receipt,
306 )?));
307 }
308 let (flow, phases) = phases_of(&verified)?;
309 let before_handler = settle_before_handler_if_needed(&verified, flow, phases).await?;
310 Ok(Prepared::Ready {
311 verified: Box::new(verified),
312 before_handler: before_handler.map(Box::new),
313 })
314 }
315}
316
317async fn sequential_after_verify<S>(
318 gate: &Gate,
319 path: &str,
320 inner: S,
321 req: Request,
322 verified: VerifiedPayment,
323 before_handler: Option<CompletedSettlement>,
324) -> Result<Response, GateError>
325where
326 S: Service<Request, Response = Response, Error = Infallible>,
327 S::Future: Send,
328{
329 let cancel = cancellation_guard(&verified, before_handler.as_ref());
330 let response = match call_inner(inner, req).await {
331 Ok(r) => r,
332 Err(never) => match never {},
333 };
334
335 if response.status().is_client_error() || response.status().is_server_error() {
336 if let Some(completed) = before_handler.as_ref() {
337 gate.record_siwx_success(path, &completed.result);
338 }
339 return failed_handler_response(
340 response,
341 &cancel,
342 before_handler.as_ref(),
343 Some(&verified.payload),
344 )
345 .await;
346 }
347
348 let mut response = response;
349 let override_amount = super::overrides::resolve_response_settlement_amount(
350 &mut response,
351 verified.requirements(),
352 )
353 .map_err(|e| GateError::SettlementAborted(e.to_string()))?;
354 let overrides = override_amount.as_deref().map(SettlementOverrides::amount);
355
356 let settlement =
357 sequential_after_handler(&verified, overrides.as_ref(), before_handler.as_ref()).await?;
358 gate.record_siwx_success(path, &settlement);
359 attach_payment_response(&mut response, &settlement)?;
360 Ok(response)
361}
362
363async fn concurrent_after_verify<S>(
364 gate: &Gate,
365 path: &str,
366 inner: S,
367 req: Request,
368 verified: VerifiedPayment,
369 before_handler: Option<CompletedSettlement>,
370) -> Result<Response, GateError>
371where
372 S: Service<Request, Response = Response, Error = Infallible> + Send,
373 S::Future: Send,
374{
375 let (_, phases) = phases_of(&verified)?;
376 let scheduled = schedule(phases, SettlementMode::Concurrent).map_err(|err| {
377 GateError::IncompatibleSettlementMode {
378 mode: err.mode,
379 flow: err.flow,
380 }
381 })?;
382 if scheduled.after_handler() != AfterHandler::JoinSettle {
383 return Err(GateError::PaymentRequiredBuild(
384 "concurrent handle_request cannot run sequential finish".into(),
385 ));
386 }
387
388 let cancel = cancellation_guard(&verified, before_handler.as_ref());
389 let settle = after_handler_settle(verified.clone());
390 let outcome = run(scheduled, concurrent_handler(inner, req), settle).await;
391 map_concurrent_outcome(
392 gate,
393 path,
394 outcome,
395 cancel,
396 before_handler.as_ref(),
397 Some(&verified.payload),
398 )
399 .await
400}
401
402async fn background_after_verify<S>(
403 gate: &Gate,
404 path: &str,
405 inner: S,
406 req: Request,
407 verified: VerifiedPayment,
408 before_handler: Option<CompletedSettlement>,
409) -> Result<Response, GateError>
410where
411 S: Service<Request, Response = Response, Error = Infallible> + Send,
412 S::Future: Send,
413{
414 let (_, phases) = phases_of(&verified)?;
415 let scheduled = schedule(phases, SettlementMode::Background).map_err(|err| {
416 GateError::IncompatibleSettlementMode {
417 mode: err.mode,
418 flow: err.flow,
419 }
420 })?;
421 let scheduled = match gate.settlement_tracker.clone() {
422 Some(tracker) => scheduled.with_tracker(tracker),
423 None => scheduled,
424 };
425 if scheduled.after_handler() != AfterHandler::SpawnSettle {
426 return Err(GateError::PaymentRequiredBuild(
427 "background handle_request cannot run sequential finish".into(),
428 ));
429 }
430
431 let cancel = cancellation_guard(&verified, before_handler.as_ref());
432 let settle = wrap_background_siwx(gate, path, after_handler_settle(verified.clone()));
433 let outcome = run(scheduled, background_handler(inner, req), settle).await;
434 map_background_outcome(outcome, cancel).await
435}
436
437#[cfg(feature = "siwx")]
439fn wrap_background_siwx(
440 gate: &Gate,
441 path: &str,
442 settle: impl Future<Output = Result<SettleResponse, FacilitatorError>> + Send + 'static,
443) -> Pin<Box<dyn Future<Output = Result<SettleResponse, FacilitatorError>> + Send>> {
444 let siwx = gate.siwx.clone();
445 let path = path.to_owned();
446 Box::pin(async move {
447 let result = settle.await;
448 if let (Some(siwx), Ok(settlement)) = (siwx.as_ref(), result.as_ref()) {
449 record_paid_address(siwx, &path, settlement);
450 }
451 result
452 })
453}
454
455#[cfg(not(feature = "siwx"))]
456fn wrap_background_siwx(
457 _gate: &Gate,
458 _path: &str,
459 settle: impl Future<Output = Result<SettleResponse, FacilitatorError>> + Send + 'static,
460) -> impl Future<Output = Result<SettleResponse, FacilitatorError>> + Send + 'static {
461 settle
462}
463
464#[cfg(feature = "siwx")]
465fn record_paid_address(siwx: &super::SiwxGate, path: &str, settlement: &SettleResponse) {
466 let SettleResponse::Success { payer, .. } = settlement else {
467 return;
468 };
469 let payer = payer.as_deref().unwrap_or("");
470 if payer.is_empty() {
471 return;
472 }
473 siwx.record_success(path, payer);
474}
475
476async fn after_handler_settle(
477 verified: VerifiedPayment,
478) -> Result<SettleResponse, FacilitatorError> {
479 verified.settle_phase(SettlePhase::AfterHandler, None).await
480}
481
482async fn concurrent_handler<S>(inner: S, req: Request) -> Result<Response, ConcurrentHandlerError>
483where
484 S: Service<Request, Response = Response, Error = Infallible> + Send,
485 S::Future: Send,
486{
487 let mut response = match call_inner(inner, req).await {
488 Ok(r) => r,
489 Err(never) => match never {},
490 };
491 if response.status().is_client_error() || response.status().is_server_error() {
492 return Err(ConcurrentHandlerError::Failed(Box::new(response)));
493 }
494 if strip_response_settlement_overrides(&mut response) {
496 return Err(ConcurrentHandlerError::SettlementAborted(
497 "Settlement-Overrides / UptoActualAmount require SettlementMode::Sequential".into(),
498 ));
499 }
500 Ok(response)
501}
502
503async fn background_handler<S>(inner: S, req: Request) -> Result<Response, Box<Response>>
504where
505 S: Service<Request, Response = Response, Error = Infallible> + Send,
506 S::Future: Send,
507{
508 let response = match call_inner(inner, req).await {
509 Ok(r) => r,
510 Err(never) => match never {},
511 };
512 if response.status().is_client_error() || response.status().is_server_error() {
513 Err(Box::new(response))
514 } else {
515 Ok(response)
516 }
517}
518
519async fn map_concurrent_outcome(
520 gate: &Gate,
521 path: &str,
522 outcome: ScheduledSettlement<Response, ConcurrentHandlerError>,
523 cancel: CancellationGuard,
524 before_handler: Option<&CompletedSettlement>,
525 payload: Option<&r402_server::WirePaymentPayload>,
526) -> Result<Response, GateError> {
527 match outcome {
528 ScheduledSettlement::HandlerOkSettleOk { mut value, receipt } => {
529 let settlement = map_settle(Ok(*receipt))?;
530 gate.record_siwx_success(path, &settlement);
531 attach_payment_response(&mut value, &settlement)?;
532 Ok(value)
533 }
534 ScheduledSettlement::HandlerErrDetach { error } => match error {
535 ConcurrentHandlerError::SettlementAborted(detail) => {
536 Err(GateError::SettlementAborted(detail))
537 }
538 ConcurrentHandlerError::Failed(response) => {
539 failed_handler_response(*response, &cancel, before_handler, payload).await
540 }
541 },
542 ScheduledSettlement::SettleErr { error, .. } => {
543 Err(GateError::from_settle_facilitator(error))
544 }
545 ScheduledSettlement::Spawned { .. } => Err(GateError::PaymentRequiredBuild(
546 "concurrent run returned Spawned".into(),
547 )),
548 }
549}
550
551async fn map_background_outcome(
552 outcome: ScheduledSettlement<Response, Box<Response>>,
553 cancel: CancellationGuard,
554) -> Result<Response, GateError> {
555 match outcome {
556 ScheduledSettlement::HandlerErrDetach { mut error } => {
557 let status = error.status().as_u16();
558 let _ = cancel
559 .cancel(handler_failed_reason(), Some(HANDLER_FAILED), Some(status))
560 .await;
561 let _ = strip_response_settlement_overrides(&mut error);
562 Ok(*error)
563 }
564 ScheduledSettlement::Spawned { mut value }
565 | ScheduledSettlement::HandlerOkSettleOk { mut value, .. }
566 | ScheduledSettlement::SettleErr { mut value, .. } => {
567 let _ = strip_response_settlement_overrides(&mut value);
568 Ok(value)
569 }
570 }
571}
572
573async fn failed_handler_response(
574 response: Response,
575 cancel: &CancellationGuard,
576 before_handler: Option<&CompletedSettlement>,
577 payload: Option<&r402_server::WirePaymentPayload>,
578) -> Result<Response, GateError> {
579 let cancel_settlement = cancel
580 .cancel(
581 handler_failed_reason(),
582 Some(HANDLER_FAILED),
583 Some(response.status().as_u16()),
584 )
585 .await;
586 let mut response = response;
587 attach_failure_path_settlement(
588 &mut response,
589 cancel_settlement.as_ref(),
590 before_handler,
591 payload,
592 )?;
593 Ok(response)
594}
595
596async fn sequential_after_handler(
597 verified: &VerifiedPayment,
598 overrides: Option<&SettlementOverrides>,
599 before_handler: Option<&CompletedSettlement>,
600) -> Result<SettleResponse, GateError> {
601 let (_, phases) = phases_of(verified)?;
602 let scheduled = schedule(phases, SettlementMode::Sequential).map_err(|err| {
603 GateError::IncompatibleSettlementMode {
604 mode: err.mode,
605 flow: err.flow,
606 }
607 })?;
608
609 match scheduled.after_handler() {
610 AfterHandler::WaitThenSettle => {
611 let fut = verified.settle_phase(SettlePhase::AfterHandler, overrides);
612 match finish(scheduled, Some(fut)).await {
613 Ok(SequentialFinish::Settled(receipt)) => map_settle(Ok(receipt)),
614 Ok(SequentialFinish::Echo) => Ok(echo_or_empty(before_handler, verified)),
615 Err(err) => Err(GateError::from_settle_facilitator(err)),
616 }
617 }
618 AfterHandler::EchoReceipt => match finish(
619 scheduled,
620 None::<std::future::Ready<Result<SettleResponse, FacilitatorError>>>,
621 )
622 .await
623 {
624 Ok(SequentialFinish::Echo) => Ok(echo_or_empty(before_handler, verified)),
625 Ok(SequentialFinish::Settled(receipt)) => map_settle(Ok(receipt)),
626 Err(err) => Err(GateError::from_settle_facilitator(err)),
627 },
628 AfterHandler::JoinSettle | AfterHandler::SpawnSettle => {
629 Err(GateError::PaymentRequiredBuild(
630 "sequential handle_request cannot run concurrent/background finish".into(),
631 ))
632 }
633 }
634}
635
636fn echo_or_empty(
637 before_handler: Option<&CompletedSettlement>,
638 verified: &VerifiedPayment,
639) -> SettleResponse {
640 if let Some(completed) = before_handler {
641 return completed.result.clone();
642 }
643 SettleResponse::Success {
644 payer: None,
645 transaction: compact_str::CompactString::default(),
646 network: verified.requirements().network.to_string().into(),
647 amount: None,
648 extensions: r402_protocol::payment::Extensions::new(),
649 extension_responses: r402_protocol::payment::Extensions::new(),
650 extra: None,
651 }
652}
653
654async fn call_inner<S>(mut inner: S, req: Request) -> Result<Response, Infallible>
655where
656 S: Service<Request, Response = Response, Error = Infallible>,
657 S::Future: Send,
658{
659 inner.call(req).await
660}