fcm_http1/client/
mod.rs

1pub mod response;
2
3pub use crate::client::response::*;
4
5use crate::message::Message;
6use reqwest::header::{AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE, RETRY_AFTER};
7use reqwest::{Body, StatusCode};
8
9/// An async client for sending the notification payload.
10pub struct Client {
11    http_client: reqwest::Client,
12}
13
14impl Default for Client {
15    fn default() -> Self {
16        Self::new()
17    }
18}
19
20impl Client {
21    /// Get a new instance of Client.
22    pub fn new() -> Client {
23        let http_client = reqwest::ClientBuilder::new()
24            .pool_max_idle_per_host(std::usize::MAX)
25            .build()
26            .unwrap();
27
28        Client { http_client }
29    }
30
31    /// Try sending a `Message` to FCM.
32    pub async fn send(&self, message: Message<'_>) -> Result<FcmResponse, FcmError> {
33        let payload = serde_json::to_vec(&message.body).unwrap();
34
35        let request = self
36            .http_client
37            .post("https://fcm.googleapis.com/fcm/send")
38            .header(CONTENT_TYPE, "application/json")
39            .header(CONTENT_LENGTH, format!("{}", payload.len() as u64).as_bytes())
40            .header(AUTHORIZATION, format!("key={}", message.api_key).as_bytes())
41            .body(Body::from(payload))
42            .build()?;
43        let response = self.http_client.execute(request).await?;
44
45        let response_status = response.status();
46
47        let retry_after = response
48            .headers()
49            .get(RETRY_AFTER)
50            .and_then(|ra| ra.to_str().ok())
51            .and_then(|ra| ra.parse::<RetryAfter>().ok());
52
53        match response_status {
54            StatusCode::OK => {
55                let fcm_response: FcmResponse = response.json().await.unwrap();
56
57                match fcm_response.error {
58                    Some(ErrorReason::Unavailable) => Err(response::FcmError::ServerError(retry_after)),
59                    Some(ErrorReason::InternalServerError) => Err(response::FcmError::ServerError(retry_after)),
60                    _ => Ok(fcm_response),
61                }
62            }
63            StatusCode::UNAUTHORIZED => Err(response::FcmError::Unauthorized),
64            StatusCode::BAD_REQUEST => Err(response::FcmError::InvalidMessage("Bad Request".to_string())),
65            status if status.is_server_error() => Err(response::FcmError::ServerError(retry_after)),
66            _ => Err(response::FcmError::InvalidMessage("Unknown Error".to_string())),
67        }
68    }
69}