teamtalk 6.0.0

TeamTalk SDK for Rust
Documentation
use super::*;
use std::time::Instant;

impl Client {
    pub(crate) fn mark_connect_phase_started(&self) {
        let mut auto = self
            .auto_reconnect
            .lock()
            .unwrap_or_else(|e| e.into_inner());
        if !auto.enabled {
            return;
        }
        auto.clear_phase_tracking();
        auto.connect_started_at = Some(Instant::now());
        auto.recovery_completed = false;
    }

    pub(crate) fn mark_login_phase_started(&self, cmd_id: i32) {
        let mut auto = self
            .auto_reconnect
            .lock()
            .unwrap_or_else(|e| e.into_inner());
        if !auto.enabled {
            return;
        }
        auto.clear_join_phase();
        auto.login_started_at = Some(Instant::now());
        auto.pending_login_cmd = Some(cmd_id);
        auto.recovery_completed = false;
    }

    pub(crate) fn mark_join_phase_started(&self, cmd_id: i32) {
        let mut auto = self
            .auto_reconnect
            .lock()
            .unwrap_or_else(|e| e.into_inner());
        if !auto.enabled {
            return;
        }
        auto.join_started_at = Some(Instant::now());
        auto.pending_join_cmd = Some(cmd_id);
        auto.recovery_completed = false;
    }

    pub(crate) fn clear_all_reconnect_phase_tracking(&self) {
        self.auto_reconnect
            .lock()
            .unwrap_or_else(|e| e.into_inner())
            .clear_phase_tracking();
    }

    pub(crate) fn handle_pending_phase_timeout(&self) -> bool {
        let timed_out = {
            let mut auto = self
                .auto_reconnect
                .lock()
                .unwrap_or_else(|e| e.into_inner());
            if !auto.enabled {
                return false;
            }

            match self.connection_state() {
                ConnectionState::Connecting => auto
                    .phase_timeouts
                    .connect
                    .zip(auto.connect_started_at)
                    .filter(|(timeout, started_at)| started_at.elapsed() >= *timeout)
                    .map(|(timeout, _)| {
                        if let Some(handler) = auto.handler.as_mut() {
                            handler.mark_disconnected();
                        }
                        auto.clear_phase_tracking();
                        ("connect", timeout)
                    }),
                ConnectionState::LoggingIn => auto
                    .phase_timeouts
                    .login
                    .zip(auto.login_started_at)
                    .filter(|(timeout, started_at)| started_at.elapsed() >= *timeout)
                    .map(|(timeout, _)| {
                        if let Some(handler) = auto.handler.as_mut() {
                            handler.mark_disconnected();
                        }
                        if let Some(handler) = auto.login_handler.as_mut() {
                            handler.mark_disconnected();
                        }
                        auto.clear_login_phase();
                        auto.clear_join_phase();
                        ("login", timeout)
                    }),
                ConnectionState::Joining(_) => auto
                    .phase_timeouts
                    .join
                    .zip(auto.join_started_at)
                    .filter(|(timeout, started_at)| started_at.elapsed() >= *timeout)
                    .map(|(timeout, _)| {
                        if let Some(handler) = auto.handler.as_mut() {
                            handler.mark_disconnected();
                        }
                        if let Some(handler) = auto.join_handler.as_mut() {
                            handler.mark_disconnected();
                        }
                        auto.clear_join_phase();
                        ("join", timeout)
                    }),
                _ => None,
            }
        };

        let Some((phase, timeout)) = timed_out else {
            return false;
        };

        let _ = self.disconnect();
        self.set_connection_state(ConnectionState::Disconnected);
        #[cfg(feature = "logging")]
        tracing::warn!(
            phase,
            timeout_ms = timeout.as_millis() as u64,
            "teamtalk recovery phase watchdog timed out"
        );
        #[cfg(not(feature = "logging"))]
        let _ = (phase, timeout);
        true
    }

    #[cfg(feature = "mock")]
    pub fn mock_run_auto_reconnect_for_tests(&self) {
        self.handle_auto_reconnect();
    }

    #[cfg(feature = "mock")]
    pub fn mock_age_connect_phase_for_tests(&self, elapsed: std::time::Duration) {
        let mut auto = self
            .auto_reconnect
            .lock()
            .unwrap_or_else(|e| e.into_inner());
        auto.connect_started_at = Instant::now().checked_sub(elapsed);
    }

    #[cfg(feature = "mock")]
    pub fn mock_age_login_phase_for_tests(&self, elapsed: std::time::Duration) {
        let mut auto = self
            .auto_reconnect
            .lock()
            .unwrap_or_else(|e| e.into_inner());
        auto.login_started_at = Instant::now().checked_sub(elapsed);
    }

    #[cfg(feature = "mock")]
    pub fn mock_age_join_phase_for_tests(&self, elapsed: std::time::Duration) {
        let mut auto = self
            .auto_reconnect
            .lock()
            .unwrap_or_else(|e| e.into_inner());
        auto.join_started_at = Instant::now().checked_sub(elapsed);
    }
}