Skip to main content

vibe_ready/status/
status_manager.rs

1use crate::api::connection_status::VibeConnectionStatus;
2use crate::api::engine_error::VibeEngineError;
3use crate::{log_e, log_s, platform};
4use std::sync::Arc;
5use tokio::sync::Mutex;
6
7/// Callback invoked when the connection status changes.
8pub type ConnectionStatusListener = Box<dyn Fn(VibeConnectionStatus) + Send + Sync + 'static>;
9
10#[derive(Default)]
11/// Tracks and publishes connection status changes.
12pub struct VibeStatusManager {
13    conn_status: Mutex<VibeConnectionStatus>,
14    conn_status_listener: Arc<Mutex<Option<ConnectionStatusListener>>>,
15}
16
17impl VibeStatusManager {
18    /// Creates a status manager with the default connection status.
19    ///
20    /// # Returns
21    ///
22    /// A new [`VibeStatusManager`].
23    pub fn new() -> Self {
24        Self::default()
25    }
26
27    /// Reads the current connection status.
28    ///
29    /// # Returns
30    ///
31    /// The current [`VibeConnectionStatus`].
32    pub async fn get_connection_status(&self) -> VibeConnectionStatus {
33        *self.conn_status.lock().await
34    }
35
36    /// Sets or clears the listener called when connection status changes.
37    ///
38    /// # Returns
39    ///
40    /// This async method returns `()` after updating the listener slot.
41    pub async fn set_connection_status_listener(
42        &self,
43        listener_opt: Option<ConnectionStatusListener>,
44    ) {
45        match listener_opt {
46            Some(listener) => {
47                self.conn_status_listener.lock().await.replace(listener);
48            }
49            None => {
50                self.conn_status_listener.lock().await.take();
51            }
52        }
53    }
54
55    /// Transitions to a new connection status and notifies the listener.
56    ///
57    /// # Returns
58    ///
59    /// `Ok(status)` when the transition is allowed, or [`VibeEngineError`] when
60    /// the status transition is invalid.
61    pub async fn set_connection_status(
62        &self,
63        status: VibeConnectionStatus,
64    ) -> Result<VibeConnectionStatus, VibeEngineError> {
65        let method = "set_server_tcp_connection_status";
66        let mut conn_status_lock = self.conn_status.lock().await;
67        let last_status = *conn_status_lock;
68        log_s!(
69            method,
70            "from_status|to_status",
71            last_status.to_string(),
72            status.to_string()
73        );
74        let ret = conn_status_lock.trans(status);
75        if let Err(err) = ret {
76            log_e!(method, "trans_ret", err.to_string());
77            return Err(err);
78        }
79        log_s!(method, "trans_ret", "success");
80        if last_status != status {
81            let listener_clone = self.conn_status_listener.clone();
82            platform::spawn(async move {
83                let listener_opt_lock = listener_clone.lock().await;
84                if let Some(listener) = listener_opt_lock.as_ref() {
85                    listener(status);
86                }
87            });
88        }
89        Ok(status)
90    }
91}
92
93#[cfg(test)]
94mod strict_tests {
95    use super::*;
96    include!(concat!(
97        env!("CARGO_MANIFEST_DIR"),
98        "/test/unit/status/status_manager_tests.rs"
99    ));
100}