1use crate::{errors::SdkError, events::SessionStatus};
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub enum LifecycleEvent {
7 Connected,
8 NetworkLost,
9 Backgrounded,
10 Foregrounded,
11 RemoteExit,
12 Cancelled,
13 Failed,
14 Closed,
15}
16
17#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18pub struct Lifecycle {
19 status: SessionStatus,
20 input_generation: u64,
21 transport_open: bool,
22}
23
24impl Default for Lifecycle {
25 fn default() -> Self {
26 Self::new()
27 }
28}
29
30impl Lifecycle {
31 pub const fn new() -> Self {
32 Self {
33 status: SessionStatus::Connecting,
34 input_generation: 0,
35 transport_open: false,
36 }
37 }
38
39 pub const fn status(self) -> SessionStatus {
40 self.status
41 }
42
43 pub const fn input_generation(self) -> u64 {
44 self.input_generation
45 }
46
47 pub const fn transport_open(self) -> bool {
48 self.transport_open
49 }
50
51 pub fn transition(&mut self, event: LifecycleEvent) -> Result<SessionStatus, SdkError> {
52 let next = match (self.status, event) {
53 (SessionStatus::Connecting, LifecycleEvent::Connected) => {
54 self.transport_open = true;
55 SessionStatus::Live
56 }
57 (SessionStatus::Live, LifecycleEvent::NetworkLost)
58 | (SessionStatus::Suspended, LifecycleEvent::Foregrounded) => {
59 self.transport_open = false;
60 SessionStatus::Recovering
61 }
62 (SessionStatus::Live, LifecycleEvent::Backgrounded) => {
63 self.invalidate_input();
64 self.transport_open = false;
65 SessionStatus::Suspended
66 }
67 (SessionStatus::Recovering, LifecycleEvent::Connected) => {
68 self.transport_open = true;
69 SessionStatus::Live
70 }
71 (_, LifecycleEvent::RemoteExit | LifecycleEvent::Closed) => {
72 self.transport_open = false;
73 SessionStatus::Closed
74 }
75 (_, LifecycleEvent::Cancelled | LifecycleEvent::Failed) => {
76 self.transport_open = false;
77 SessionStatus::Failed
78 }
79 (SessionStatus::Recovering, LifecycleEvent::Backgrounded) => {
80 self.invalidate_input();
81 self.transport_open = false;
82 SessionStatus::Suspended
83 }
84 (status, _) => {
85 return Err(if status == SessionStatus::Closed {
86 SdkError::SessionClosed
87 } else {
88 SdkError::TransportUnavailable
89 });
90 }
91 };
92 self.status = next;
93 Ok(next)
94 }
95
96 fn invalidate_input(&mut self) {
97 self.input_generation = self.input_generation.saturating_add(1);
98 }
99}