Skip to main content

cashweb_relay_client/
services.rs

1//! This module contains lower-level primitives for working with the [`RelayClient`].
2
3use std::{fmt, pin::Pin};
4
5use futures_core::{
6    task::{Context, Poll},
7    Future,
8};
9use http::Method;
10use hyper::{
11    body::aggregate, http::header::AUTHORIZATION, Body, Error as HyperError, Request, Response,
12    StatusCode,
13};
14pub use hyper::{
15    client::{connect::Connect, HttpConnector},
16    Uri,
17};
18use prost::{DecodeError, Message as _};
19use thiserror::Error;
20use tower_service::Service;
21
22use super::RelayClient;
23use ::auth_wrapper::*;
24use relay::{MessagePage, Profile};
25
26type ResponseFuture<Response, Error> =
27    Pin<Box<dyn Future<Output = Result<Response, Error>> + 'static + Send>>;
28
29/// Represents a request for the [`Profile`] object.
30#[derive(Clone, Debug)]
31pub struct GetProfile;
32
33/// Error associated with getting a [`Profile`] from a relay server.
34#[derive(Debug, Error)]
35pub enum GetProfileError<E: fmt::Debug + fmt::Display> {
36    /// Error while decoding the [`Profile`]
37    #[error("profile decoding failure: {0}")]
38    ProfileDecode(DecodeError),
39    /// Error while decoding the [`AuthWrapper`].
40    #[error("authwrapper decoding failure: {0}")]
41    AuthWrapperDecode(DecodeError),
42    /// Error while processing the body.
43    #[error("processing body failed: {0}")]
44    Body(HyperError),
45    /// A connection error occured.
46    #[error("connection failure: {0}")]
47    Service(E),
48    /// Unexpected status code.
49    #[error("unexpected status code: {0}")]
50    UnexpectedStatusCode(u16),
51}
52
53type FutResponse<Response, Error> =
54    Pin<Box<dyn Future<Output = Result<Response, Error>> + 'static + Send>>;
55
56impl<S> Service<(Uri, GetProfile)> for RelayClient<S>
57where
58    S: Service<Request<Body>, Response = Response<Body>>,
59    S: Send + Clone + 'static,
60    S::Future: Send,
61    S::Error: fmt::Debug + fmt::Display,
62{
63    type Response = AuthWrapper;
64    type Error = GetProfileError<S::Error>;
65    type Future = FutResponse<Self::Response, Self::Error>;
66
67    fn poll_ready(&mut self, context: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
68        self.inner_client
69            .poll_ready(context)
70            .map_err(GetProfileError::Service)
71    }
72
73    fn call(&mut self, (uri, _): (Uri, GetProfile)) -> Self::Future {
74        let mut client = self.inner_client.clone();
75        let http_request = Request::builder()
76            .method(Method::GET)
77            .uri(uri)
78            .body(Body::empty())
79            .unwrap(); // This is safe
80        let fut = async move {
81            // Get response
82            let response = client
83                .call(http_request)
84                .await
85                .map_err(Self::Error::Service)?;
86
87            // Check status code
88            // TODO: Fix this
89            match response.status() {
90                StatusCode::OK => (),
91                code => return Err(Self::Error::UnexpectedStatusCode(code.as_u16())),
92            }
93
94            // Deserialize and decode body
95            let body = response.into_body();
96            let buf = aggregate(body).await.map_err(Self::Error::Body)?;
97            let auth_wrapper = AuthWrapper::decode(buf).map_err(Self::Error::AuthWrapperDecode)?;
98
99            Ok(auth_wrapper)
100        };
101        Box::pin(fut)
102    }
103}
104
105/// Error associated with putting [`Profile`] to the relay server.
106#[derive(Clone, Debug, Error)]
107pub enum PutProfileError<E: fmt::Debug + fmt::Display> {
108    /// A connection error occured.
109    #[error("connection failure: {0}")]
110    Service(E),
111    /// Unexpected status code.
112    #[error("unexpected status code: {0}")]
113    UnexpectedStatusCode(u16),
114}
115
116/// Request for putting [`Profile`] to the keyserver.
117#[derive(Clone, Debug)]
118pub struct PutProfile {
119    /// POP token attached to the request.
120    pub token: String,
121    /// The [`Profile`] to be put.
122    pub profile: Profile,
123}
124
125impl<S> Service<(Uri, PutProfile)> for RelayClient<S>
126where
127    S: Service<Request<Body>, Response = Response<Body>>,
128    S: Send + Clone + 'static,
129    S::Future: Send,
130    S::Error: fmt::Debug + fmt::Display,
131{
132    type Response = ();
133    type Error = PutProfileError<S::Error>;
134    type Future = FutResponse<Self::Response, Self::Error>;
135
136    fn poll_ready(&mut self, context: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
137        self.inner_client
138            .poll_ready(context)
139            .map_err(PutProfileError::Service)
140    }
141
142    fn call(&mut self, (uri, request): (Uri, PutProfile)) -> Self::Future {
143        let mut client = self.inner_client.clone();
144
145        // Construct body
146        let mut body = Vec::with_capacity(request.profile.encoded_len());
147        request.profile.encode(&mut body).unwrap();
148
149        let http_request = Request::builder()
150            .method(Method::PUT)
151            .uri(uri)
152            .header(AUTHORIZATION, request.token)
153            .body(Body::from(body))
154            .unwrap(); // This is safe
155
156        let fut = async move {
157            // Get response
158            let response = client
159                .call(http_request)
160                .await
161                .map_err(Self::Error::Service)?;
162
163            // Check status code
164            // TODO: Fix this
165            match response.status() {
166                StatusCode::OK => (),
167                code => return Err(Self::Error::UnexpectedStatusCode(code.as_u16())),
168            }
169
170            Ok(())
171        };
172        Box::pin(fut)
173    }
174}
175
176/// Error associated with getting a [`MessagePage`] to the relay server.
177#[derive(Debug, Error)]
178pub enum GetMessageError<E: fmt::Debug + fmt::Display> {
179    /// A connection error occured.
180    #[error("connection failure: {0}")]
181    Service(E),
182    /// Unexpected status code.
183    #[error("unexpected status code: {0}")]
184    UnexpectedStatusCode(u16),
185    /// Error while processing the body.
186    #[error("processing body failed: {0}")]
187    Body(HyperError),
188    /// Error while decoding the [`MessagePage`].
189    #[error("messagepage decoding failure: {0}")]
190    MessagePageDecode(DecodeError),
191}
192
193/// Represents a request for a [`MessagePage`].
194#[derive(Clone, Debug)]
195pub struct GetMessages {
196    /// POP token attached to the request.
197    pub token: String,
198}
199
200impl<S> Service<(Uri, GetMessages)> for RelayClient<S>
201where
202    S: Service<Request<Body>, Response = Response<Body>>,
203    S: Send + Clone + 'static,
204    S::Future: Send,
205    S::Error: fmt::Debug + fmt::Display,
206{
207    type Response = MessagePage;
208    type Error = GetMessageError<S::Error>;
209    type Future = ResponseFuture<Self::Response, Self::Error>;
210
211    fn poll_ready(&mut self, context: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
212        self.inner_client
213            .poll_ready(context)
214            .map_err(GetMessageError::Service)
215    }
216
217    fn call(&mut self, (uri, request): (Uri, GetMessages)) -> Self::Future {
218        let mut client = self.inner_client.clone();
219
220        let http_request = Request::builder()
221            .method(Method::GET)
222            .uri(uri)
223            .header(AUTHORIZATION, request.token)
224            .body(Body::empty())
225            .unwrap(); // This is safe
226
227        let fut = async move {
228            // Get response
229            let response = client
230                .call(http_request)
231                .await
232                .map_err(Self::Error::Service)?;
233
234            // Check status code
235            // TODO: Fix this
236            match response.status() {
237                StatusCode::OK => (),
238                code => return Err(Self::Error::UnexpectedStatusCode(code.as_u16())),
239            }
240
241            // Deserialize and decode body
242            let body = response.into_body();
243            let buf = aggregate(body).await.map_err(Self::Error::Body)?;
244            let message_page = MessagePage::decode(buf).map_err(Self::Error::MessagePageDecode)?;
245
246            Ok(message_page)
247        };
248        Box::pin(fut)
249    }
250}