1use http::{HeaderMap, HeaderName, HeaderValue};
2use serde::{Deserialize, Serialize};
3use url::Url;
4
5use crate::{
6 concepts::Facilitator,
7 transport::{
8 FacilitatorPaymentRequest, FacilitatorSettleFailed, FacilitatorSettleResponse,
9 FacilitatorSettleSuccess, FacilitatorSupportedResponse, FacilitatorVerifyInvalid,
10 FacilitatorVerifyResponse, FacilitatorVerifyValid, PaymentPayload, PaymentRequirements,
11 },
12};
13
14#[derive(Debug, Clone)]
25pub struct RemoteFacilitatorClient<VReq, VRes, SReq, SRes>
26where
27 VReq: From<FacilitatorPaymentRequest> + Serialize,
28 VRes: IntoVerifyResponse + for<'de> Deserialize<'de>,
29 SReq: From<FacilitatorPaymentRequest> + Serialize,
30 SRes: IntoSettleResponse + for<'de> Deserialize<'de>,
31{
32 pub base_url: Url,
33 pub client: reqwest::Client,
34 pub supported_headers: HeaderMap,
35 pub verify_headers: HeaderMap,
36 pub settle_headers: HeaderMap,
37 pub _phantom: std::marker::PhantomData<(VReq, VRes, SReq, SRes)>,
38}
39
40pub trait IntoVerifyResponse {
41 fn into_verify_response(self) -> FacilitatorVerifyResponse;
42}
43
44pub trait IntoSettleResponse {
45 fn into_settle_response(self) -> FacilitatorSettleResponse;
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
49#[serde(rename_all = "camelCase")]
50pub struct DefaultPaymentRequest {
51 pub payment_payload: PaymentPayload,
52 pub payment_requirements: PaymentRequirements,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
56#[serde(rename_all = "camelCase")]
57pub struct DefaultVerifyResponse {
58 pub is_valid: bool,
59 #[serde(skip_serializing_if = "Option::is_none")]
60 pub invalid_reason: Option<String>,
61 pub payer: Option<String>,
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
65#[serde(rename_all = "camelCase")]
66pub struct DefaultSettleResponse {
67 pub success: bool,
68 #[serde(skip_serializing_if = "Option::is_none")]
69 pub error_reason: Option<String>,
70 pub payer: Option<String>,
71 pub transaction: Option<String>,
72 pub network: Option<String>,
73}
74
75impl From<FacilitatorPaymentRequest> for DefaultPaymentRequest {
76 fn from(request: FacilitatorPaymentRequest) -> Self {
77 DefaultPaymentRequest {
78 payment_payload: request.payload.payment_payload,
79 payment_requirements: request.payload.payment_requirements,
80 }
81 }
82}
83
84impl IntoVerifyResponse for DefaultVerifyResponse {
85 fn into_verify_response(self) -> FacilitatorVerifyResponse {
86 if self.is_valid {
87 FacilitatorVerifyResponse::valid(FacilitatorVerifyValid {
88 payer: self.payer.unwrap_or_default(),
89 })
90 } else {
91 FacilitatorVerifyResponse::invalid(FacilitatorVerifyInvalid {
92 invalid_reason: self.invalid_reason.unwrap_or_default(),
93 payer: self.payer,
94 })
95 }
96 }
97}
98
99impl IntoSettleResponse for DefaultSettleResponse {
100 fn into_settle_response(self) -> FacilitatorSettleResponse {
101 if self.success {
102 FacilitatorSettleResponse::success(FacilitatorSettleSuccess {
103 payer: self.payer.unwrap_or_default(),
104 transaction: self.transaction.unwrap_or_default(),
105 network: self.network.unwrap_or_default(),
106 })
107 } else {
108 FacilitatorSettleResponse::failed(FacilitatorSettleFailed {
109 error_reason: self.error_reason.unwrap_or_default(),
110 payer: self.payer,
111 })
112 }
113 }
114}
115
116pub type DefaultRemoteFacilitatorClient = RemoteFacilitatorClient<
118 DefaultPaymentRequest,
119 DefaultVerifyResponse,
120 DefaultPaymentRequest,
121 DefaultSettleResponse,
122>;
123
124impl<VReq, VRes, SReq, SRes> RemoteFacilitatorClient<VReq, VRes, SReq, SRes>
125where
126 VReq: From<FacilitatorPaymentRequest> + Serialize,
127 VRes: IntoVerifyResponse + for<'de> Deserialize<'de>,
128 SReq: From<FacilitatorPaymentRequest> + Serialize,
129 SRes: IntoSettleResponse + for<'de> Deserialize<'de>,
130{
131 pub fn new_from_url(base_url: Url) -> Self {
132 RemoteFacilitatorClient {
133 base_url,
134 client: reqwest::Client::new(),
135 supported_headers: HeaderMap::new(),
136 verify_headers: HeaderMap::new(),
137 settle_headers: HeaderMap::new(),
138 _phantom: std::marker::PhantomData,
139 }
140 }
141
142 pub fn with_verify_request_type<NewVReq>(
143 self,
144 ) -> RemoteFacilitatorClient<NewVReq, VRes, SReq, SRes>
145 where
146 NewVReq: From<FacilitatorPaymentRequest> + Serialize,
147 {
148 RemoteFacilitatorClient {
149 base_url: self.base_url,
150 client: self.client,
151 supported_headers: self.supported_headers,
152 verify_headers: self.verify_headers,
153 settle_headers: self.settle_headers,
154 _phantom: std::marker::PhantomData,
155 }
156 }
157
158 pub fn with_verify_response_type<NewVRes>(
159 self,
160 ) -> RemoteFacilitatorClient<VReq, NewVRes, SReq, SRes>
161 where
162 NewVRes: IntoVerifyResponse + for<'de> Deserialize<'de>,
163 {
164 RemoteFacilitatorClient {
165 supported_headers: self.supported_headers,
166 base_url: self.base_url,
167 verify_headers: self.verify_headers,
168 settle_headers: self.settle_headers,
169 client: self.client,
170 _phantom: std::marker::PhantomData,
171 }
172 }
173
174 pub fn with_settle_request_type<NewSReq>(
175 self,
176 ) -> RemoteFacilitatorClient<VReq, VRes, NewSReq, SRes>
177 where
178 NewSReq: From<FacilitatorPaymentRequest> + Serialize,
179 {
180 RemoteFacilitatorClient {
181 supported_headers: self.supported_headers,
182 base_url: self.base_url,
183 verify_headers: self.verify_headers,
184 settle_headers: self.settle_headers,
185 client: self.client,
186 _phantom: std::marker::PhantomData,
187 }
188 }
189
190 pub fn with_settle_response_type<NewSRes>(
191 self,
192 ) -> RemoteFacilitatorClient<VReq, VRes, SReq, NewSRes>
193 where
194 NewSRes: IntoSettleResponse + for<'de> Deserialize<'de>,
195 {
196 RemoteFacilitatorClient {
197 supported_headers: self.supported_headers,
198 base_url: self.base_url,
199 verify_headers: self.verify_headers,
200 settle_headers: self.settle_headers,
201 client: self.client,
202 _phantom: std::marker::PhantomData,
203 }
204 }
205
206 pub fn header(mut self, key: &HeaderName, value: &HeaderValue) -> Self {
207 self.supported_headers.insert(key, value.to_owned());
208 self.verify_headers.insert(key, value.to_owned());
209 self.settle_headers.insert(key, value.to_owned());
210 self
211 }
212
213 pub fn supported_header(mut self, key: &HeaderName, value: &HeaderValue) -> Self {
214 self.supported_headers.insert(key, value.to_owned());
215 self
216 }
217
218 pub fn verify_header(mut self, key: &HeaderName, value: &HeaderValue) -> Self {
219 self.verify_headers.insert(key, value.to_owned());
220 self
221 }
222
223 pub fn settle_header(mut self, key: &HeaderName, value: &HeaderValue) -> Self {
224 self.settle_headers.insert(key, value.to_owned());
225 self
226 }
227}
228
229impl
230 RemoteFacilitatorClient<
231 DefaultPaymentRequest,
232 DefaultVerifyResponse,
233 DefaultPaymentRequest,
234 DefaultSettleResponse,
235 >
236{
237 pub fn from_url(base_url: Url) -> Self {
238 RemoteFacilitatorClient::new_from_url(base_url)
239 }
240}
241
242#[derive(Debug, thiserror::Error)]
243pub enum RemoteFacilitatorClientError {
244 #[error("URL parse error: {0}")]
245 UrlParseError(#[from] url::ParseError),
246 #[error("HTTP request error: {0}")]
247 HttpRequestError(#[from] reqwest::Error),
248 #[error("Serialization/Deserialization error: {0}")]
249 SerdeError(#[from] serde_json::Error),
250}
251
252impl<VReq, VRes, SReq, SRes> Facilitator for RemoteFacilitatorClient<VReq, VRes, SReq, SRes>
253where
254 VReq: From<FacilitatorPaymentRequest> + Serialize,
255 VRes: IntoVerifyResponse + for<'de> Deserialize<'de>,
256 SReq: From<FacilitatorPaymentRequest> + Serialize,
257 SRes: IntoSettleResponse + for<'de> Deserialize<'de>,
258{
259 type Error = RemoteFacilitatorClientError;
260
261 async fn supported(&self) -> Result<FacilitatorSupportedResponse, Self::Error> {
262 let supported = self
263 .client
264 .get(self.base_url.join("supported")?)
265 .headers(self.supported_headers.clone())
266 .send()
267 .await?
268 .json()
269 .await?;
270
271 Ok(supported)
272 }
273
274 async fn verify(
275 &self,
276 request: FacilitatorPaymentRequest,
277 ) -> Result<FacilitatorVerifyResponse, Self::Error> {
278 let result = self
279 .client
280 .post(self.base_url.join("verify")?)
281 .headers(self.verify_headers.clone())
282 .json(&VReq::from(request))
283 .send()
284 .await?
285 .json::<VRes>()
286 .await?;
287
288 Ok(result.into_verify_response())
289 }
290
291 async fn settle(
292 &self,
293 request: FacilitatorPaymentRequest,
294 ) -> Result<FacilitatorSettleResponse, Self::Error> {
295 let result = self
296 .client
297 .post(self.base_url.join("settle")?)
298 .headers(self.settle_headers.clone())
299 .json(&SReq::from(request))
300 .send()
301 .await?
302 .json::<SRes>()
303 .await?;
304
305 Ok(result.into_settle_response())
306 }
307}