Skip to main content

actix_cloud/
state.rs

1//! Global application state and server handle.
2//!
3//! Populate [`GlobalState`] (fields depend on enabled features), attach it with
4//! `.build()` as app data, and let [`ServerHandle`] own the actix server lifecycle.
5use actix_web::dev;
6use actix_web::web::Data;
7use chrono::{DateTime, Utc};
8use parking_lot::{Mutex, RwLock};
9
10use crate::Result;
11
12/// Shared application state, stored as actix-web `Data<GlobalState>`.
13pub struct GlobalState {
14    #[cfg(feature = "memorydb")]
15    /// Shared key-value database (sessions, CSRF tokens, ...).
16    pub memorydb: std::sync::Arc<dyn crate::memorydb::interface::MemoryDB>,
17
18    #[cfg(feature = "config")]
19    /// Application configuration loaded through the `config` crate.
20    pub config: config::Config,
21
22    #[cfg(feature = "logger")]
23    /// Global logger.
24    pub logger: Option<crate::logger::Logger>,
25
26    #[cfg(feature = "i18n")]
27    /// Default locale; used when the request middleware cannot identify a language.
28    pub locale: crate::i18n::Locale,
29
30    /// Handle server state.
31    pub server: ServerHandle,
32}
33
34impl GlobalState {
35    /// Wrap the state into actix-web `Data` for `.app_data(...)`.
36    pub fn build(self) -> Data<Self> {
37        Data::new(self)
38    }
39}
40
41/// Owns the running server: start/stop timestamps, running flag and the stop signal.
42#[derive(Default)]
43pub struct ServerHandle {
44    inner: Mutex<Option<dev::ServerHandle>>,
45
46    /// Whether server is running (never received stop signals).
47    pub running: RwLock<bool>,
48    /// Server start timestamp.
49    pub start_time: RwLock<DateTime<Utc>>,
50    /// Server stop timestamp.
51    pub stop_time: RwLock<Option<DateTime<Utc>>>,
52}
53
54impl ServerHandle {
55    /// Sets the server handle and start blocking.
56    pub async fn start(&self, server: dev::Server) -> Result<()> {
57        *self.inner.lock() = Some(server.handle());
58        *self.running.write() = true;
59        *self.start_time.write() = Utc::now();
60
61        server.await.map_err(Into::into)
62    }
63
64    /// Sends stop signal through contained server handle.
65    ///
66    /// Does nothing if [`Self::start`] has never completed.
67    pub fn stop(&self, graceful: bool) {
68        *self.running.write() = false;
69        *self.stop_time.write() = Some(Utc::now());
70        if let Some(handle) = self.inner.lock().as_ref() {
71            #[allow(clippy::let_underscore_future)]
72            let _ = handle.stop(graceful);
73        }
74    }
75}