r402_http/server/
pricing.rs1use std::future::Future;
4use std::pin::Pin;
5use std::sync::Arc;
6
7use http::{HeaderMap, Uri};
8use r402_protocol::payment::PriceTag;
9use url::Url;
10
11pub trait PriceTagSource: Clone + Send + Sync + 'static {
13 fn resolve(
15 &self,
16 headers: &HeaderMap,
17 uri: &Uri,
18 base_url: &Url,
19 ) -> impl Future<Output = Vec<PriceTag>> + Send;
20}
21
22#[derive(Clone, Debug)]
24pub struct StaticPriceTags {
25 tags: Arc<[PriceTag]>,
26}
27
28impl StaticPriceTags {
29 #[must_use]
31 pub fn new(tags: Vec<PriceTag>) -> Self {
32 Self { tags: tags.into() }
33 }
34
35 #[must_use]
37 pub fn tags(&self) -> &[PriceTag] {
38 &self.tags
39 }
40
41 #[must_use]
43 pub fn with_price_tag(mut self, tag: PriceTag) -> Self {
44 let mut tags = self.tags.to_vec();
45 tags.push(tag);
46 self.tags = tags.into();
47 self
48 }
49}
50
51impl PriceTagSource for StaticPriceTags {
52 fn resolve(
53 &self,
54 _headers: &HeaderMap,
55 _uri: &Uri,
56 _base_url: &Url,
57 ) -> impl Future<Output = Vec<PriceTag>> + Send {
58 std::future::ready(self.tags.to_vec())
59 }
60}
61
62type BoxedDynamicPriceCallback = dyn for<'a> Fn(
63 &'a HeaderMap,
64 &'a Uri,
65 &'a Url,
66 ) -> Pin<Box<dyn Future<Output = Vec<PriceTag>> + Send + 'a>>
67 + Send
68 + Sync;
69
70pub struct DynamicPriceTags {
72 callback: Arc<BoxedDynamicPriceCallback>,
73}
74
75impl Clone for DynamicPriceTags {
76 fn clone(&self) -> Self {
77 Self {
78 callback: Arc::clone(&self.callback),
79 }
80 }
81}
82
83impl std::fmt::Debug for DynamicPriceTags {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 f.debug_struct("DynamicPriceTags")
86 .field("callback", &"<callback>")
87 .finish()
88 }
89}
90
91impl DynamicPriceTags {
92 pub fn new<F, Fut>(callback: F) -> Self
94 where
95 F: Fn(&HeaderMap, &Uri, &Url) -> Fut + Send + Sync + 'static,
96 Fut: Future<Output = Vec<PriceTag>> + Send + 'static,
97 {
98 Self {
99 callback: Arc::new(move |headers, uri, base_url| {
100 Box::pin(callback(headers, uri, base_url))
101 }),
102 }
103 }
104}
105
106impl PriceTagSource for DynamicPriceTags {
107 async fn resolve(&self, headers: &HeaderMap, uri: &Uri, base_url: &Url) -> Vec<PriceTag> {
108 (self.callback)(headers, uri, base_url).await
109 }
110}