web_push/clients/
isahc_client.rs1use async_trait::async_trait;
2use futures_lite::AsyncReadExt;
3use http::header::RETRY_AFTER;
4use isahc::HttpClient;
5
6use crate::clients::request_builder;
7use crate::clients::{WebPushClient, MAX_RESPONSE_SIZE};
8use crate::error::{RetryAfter, WebPushError};
9use crate::message::WebPushMessage;
10
11#[derive(Clone)]
19pub struct IsahcWebPushClient {
20 client: HttpClient,
21}
22
23impl Default for IsahcWebPushClient {
24 fn default() -> Self {
25 Self::new().unwrap()
26 }
27}
28
29impl From<HttpClient> for IsahcWebPushClient {
30 fn from(client: HttpClient) -> Self {
32 Self { client }
33 }
34}
35
36impl IsahcWebPushClient {
37 pub fn new() -> Result<Self, WebPushError> {
39 Ok(Self {
40 client: HttpClient::new()?,
41 })
42 }
43}
44
45#[async_trait]
46impl WebPushClient for IsahcWebPushClient {
47 async fn send(&self, message: WebPushMessage) -> Result<(), WebPushError> {
49 trace!("Message: {:?}", message);
50
51 let request = request_builder::build_request::<isahc::AsyncBody>(message);
52
53 trace!("Request: {:?}", request);
54
55 let requesting = self.client.send_async(request);
56
57 let response = requesting.await?;
58
59 trace!("Response: {:?}", response);
60
61 let retry_after = response
62 .headers()
63 .get(RETRY_AFTER)
64 .and_then(|ra| ra.to_str().ok())
65 .and_then(RetryAfter::from_str);
66
67 let response_status = response.status();
68 trace!("Response status: {}", response_status);
69
70 let mut body = Vec::new();
71 if response
72 .into_body()
73 .take(MAX_RESPONSE_SIZE as u64 + 1)
74 .read_to_end(&mut body)
75 .await?
76 > MAX_RESPONSE_SIZE
77 {
78 return Err(WebPushError::InvalidResponse); }
80 trace!("Body: {:?}", body);
81
82 trace!("Body text: {:?}", std::str::from_utf8(&body));
83
84 let response = request_builder::parse_response(response_status, body.to_vec());
85
86 trace!("Response: {:?}", response);
87
88 if let Err(WebPushError::ServerError(None)) = response {
89 Err(WebPushError::ServerError(retry_after))
90 } else {
91 Ok(response?)
92 }
93 }
94}