use std::sync::{Arc, Mutex};
use crate::common::platform::{MonotonicInstant, monotonic_now};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConnectionState {
Disconnected,
Connecting,
Connected,
Disconnecting,
Failed,
Reconnecting,
}
impl ConnectionState {
pub fn can_send(&self) -> bool {
matches!(self, ConnectionState::Connected)
}
pub fn can_connect(&self) -> bool {
matches!(
self,
ConnectionState::Disconnected | ConnectionState::Failed
)
}
pub fn is_connecting(&self) -> bool {
matches!(
self,
ConnectionState::Connecting | ConnectionState::Reconnecting
)
}
}
pub struct ConnectionStateManager {
state: Arc<Mutex<ConnectionState>>,
state_changed_at: Arc<Mutex<MonotonicInstant>>,
connect_started_at: Arc<Mutex<Option<MonotonicInstant>>>,
}
impl Clone for ConnectionStateManager {
fn clone(&self) -> Self {
Self {
state: Arc::clone(&self.state),
state_changed_at: Arc::clone(&self.state_changed_at),
connect_started_at: Arc::clone(&self.connect_started_at),
}
}
}
impl ConnectionStateManager {
pub fn new() -> Self {
Self {
state: Arc::new(Mutex::new(ConnectionState::Disconnected)),
state_changed_at: Arc::new(Mutex::new(monotonic_now())),
connect_started_at: Arc::new(Mutex::new(None)),
}
}
pub fn set_state(&self, new_state: ConnectionState) {
if let Ok(mut state) = self.state.lock() {
*state = new_state;
}
if let Ok(mut changed_at) = self.state_changed_at.lock() {
*changed_at = monotonic_now();
}
}
pub fn get_state(&self) -> ConnectionState {
self.state
.lock()
.map(|s| *s)
.unwrap_or(ConnectionState::Disconnected)
}
pub fn start_connecting(&self) {
self.set_state(ConnectionState::Connecting);
if let Ok(mut started_at) = self.connect_started_at.lock() {
*started_at = Some(monotonic_now());
}
}
pub fn set_connected(&self) {
self.set_state(ConnectionState::Connected);
if let Ok(mut started_at) = self.connect_started_at.lock() {
*started_at = None;
}
}
pub fn set_disconnected(&self) {
self.set_state(ConnectionState::Disconnected);
if let Ok(mut started_at) = self.connect_started_at.lock() {
*started_at = None;
}
}
pub fn set_failed(&self) {
self.set_state(ConnectionState::Failed);
if let Ok(mut started_at) = self.connect_started_at.lock() {
*started_at = None;
}
}
pub fn set_reconnecting(&self) {
self.set_state(ConnectionState::Reconnecting);
if let Ok(mut started_at) = self.connect_started_at.lock() {
*started_at = Some(monotonic_now());
}
}
pub fn state_changed_at(&self) -> MonotonicInstant {
self.state_changed_at
.lock()
.map(|t| *t)
.unwrap_or_else(|_| monotonic_now())
}
pub fn connect_duration(&self) -> Option<std::time::Duration> {
self.connect_started_at
.lock()
.ok()
.and_then(|started_at| started_at.map(|start| start.elapsed()))
}
}
impl Default for ConnectionStateManager {
fn default() -> Self {
Self::new()
}
}