1use std::time::{Duration, Instant};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub enum SessionState {
5 Init,
6 Handshake,
7 Authenticated { since: Instant },
8 Ready { since: Instant },
9 Streaming { since: Instant },
10 Failed(String),
11 Closed,
12}
13
14impl SessionState {
15 pub fn can_transition(&self, next: &SessionState) -> bool {
16 use SessionState::*;
17 match (self, next) {
18 (Init, Handshake) => true,
19 (Handshake, Authenticated { .. }) => true,
20 (Authenticated { .. }, Ready { .. }) => true,
21 (Ready { .. }, Streaming { .. }) => true,
22 (_, Failed(_)) => true,
24 (_, Closed) => true,
25 _ => false,
26 }
27 }
28
29 pub fn transition(self, next: SessionState) -> Result<SessionState, SessionStateError> {
30 if self.can_transition(&next) {
31 Ok(next)
32 } else {
33 Err(SessionStateError::InvalidTransition(format!(
34 "cannot transition from {:?} to {:?}",
35 self, next
36 )))
37 }
38 }
39
40 pub fn is_failed(&self) -> bool {
41 matches!(self, SessionState::Failed(_))
42 }
43
44 pub fn is_closed(&self) -> bool {
45 matches!(self, SessionState::Closed)
46 }
47
48 pub fn check_timeout(&self, timeout: Duration, now: Instant) -> bool {
49 match self {
50 SessionState::Authenticated { since }
51 | SessionState::Ready { since }
52 | SessionState::Streaming { since } => now.duration_since(*since) > timeout,
53 _ => false,
54 }
55 }
56}
57
58#[derive(Debug, thiserror::Error)]
59pub enum SessionStateError {
60 #[error("invalid state transition: {0}")]
61 InvalidTransition(String),
62}