autoendpoint/extractors/
routers.rs

1use crate::error::{ApiError, ApiResult};
2use crate::routers::apns::router::ApnsRouter;
3use crate::routers::fcm::router::FcmRouter;
4#[cfg(feature = "stub")]
5use crate::routers::stub::router::StubRouter;
6use crate::routers::webpush::WebPushRouter;
7use crate::routers::Router;
8use crate::server::AppState;
9use actix_web::dev::Payload;
10use actix_web::web::Data;
11use actix_web::{FromRequest, HttpRequest};
12use futures::future;
13use std::fmt::{self, Display};
14use std::str::FromStr;
15use std::sync::Arc;
16
17#[derive(Copy, Clone, Debug, Eq, PartialEq)]
18#[allow(clippy::upper_case_acronyms)]
19pub enum RouterType {
20    WebPush,
21    FCM,
22    GCM,
23    APNS,
24    #[cfg(feature = "stub")]
25    STUB,
26}
27
28impl FromStr for RouterType {
29    type Err = ();
30
31    fn from_str(s: &str) -> Result<Self, Self::Err> {
32        match s.to_lowercase().as_str() {
33            "webpush" => Ok(RouterType::WebPush),
34            "fcm" => Ok(RouterType::FCM),
35            "gcm" => Ok(RouterType::GCM),
36            "apns" => Ok(RouterType::APNS),
37            #[cfg(feature = "stub")]
38            "stub" => Ok(RouterType::STUB),
39            _ => Err(()),
40        }
41    }
42}
43
44impl Display for RouterType {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        f.write_str(match self {
47            RouterType::WebPush => "webpush",
48            RouterType::FCM => "fcm",
49            RouterType::GCM => "gcm",
50            RouterType::APNS => "apns",
51            #[cfg(feature = "stub")]
52            RouterType::STUB => "stub",
53        })
54    }
55}
56
57/// Holds the various notification routers. The routers use resources from the
58/// server state, which is why `Routers` is an extractor.
59pub struct Routers {
60    webpush: WebPushRouter,
61    fcm: Arc<FcmRouter>,
62    apns: Arc<ApnsRouter>,
63    #[cfg(feature = "stub")]
64    stub: Arc<StubRouter>,
65}
66
67impl FromRequest for Routers {
68    type Error = ApiError;
69    type Future = future::Ready<ApiResult<Self>>;
70
71    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
72        let app_state = Data::<AppState>::extract(req)
73            .into_inner()
74            .expect("No server state found");
75
76        future::ok(Routers {
77            webpush: WebPushRouter {
78                db: app_state.db.clone(),
79                metrics: app_state.metrics.clone(),
80                http: app_state.http.clone(),
81                endpoint_url: app_state.settings.endpoint_url(),
82                #[cfg(feature = "reliable_report")]
83                reliability: app_state.reliability.clone(),
84            },
85            fcm: app_state.fcm_router.clone(),
86            apns: app_state.apns_router.clone(),
87            #[cfg(feature = "stub")]
88            stub: app_state.stub_router.clone(),
89        })
90    }
91}
92
93impl Routers {
94    /// Get the router which handles the router type
95    pub fn get(&self, router_type: RouterType) -> &dyn Router {
96        match router_type {
97            RouterType::WebPush => &self.webpush,
98            RouterType::FCM | RouterType::GCM => self.fcm.as_ref(),
99            RouterType::APNS => self.apns.as_ref(),
100            #[cfg(feature = "stub")]
101            RouterType::STUB => self.stub.as_ref(),
102        }
103    }
104}