fxa_client/state_machine/
mod.rs
1use error_support::breadcrumb;
10
11use crate::{internal::FirefoxAccount, DeviceConfig, Error, FxaEvent, FxaState, Result};
12
13pub mod checker;
14mod display;
15mod internal_machines;
16
17const MAX_INTERNAL_TRANSITIONS: usize = 20;
20
21use internal_machines::InternalStateMachine;
22use internal_machines::State as InternalState;
23
24impl FirefoxAccount {
25 pub fn get_state(&self) -> FxaState {
27 self.auth_state.clone()
28 }
29
30 pub fn process_event(&mut self, event: FxaEvent) -> Result<FxaState> {
35 match &self.auth_state {
36 FxaState::Uninitialized => self.process_event_with_internal_state_machine(
37 internal_machines::UninitializedStateMachine,
38 event,
39 ),
40 FxaState::Disconnected => self.process_event_with_internal_state_machine(
41 internal_machines::DisconnectedStateMachine,
42 event,
43 ),
44 FxaState::Authenticating { .. } => self.process_event_with_internal_state_machine(
45 internal_machines::AuthenticatingStateMachine,
46 event,
47 ),
48 FxaState::Connected => self.process_event_with_internal_state_machine(
49 internal_machines::ConnectedStateMachine,
50 event,
51 ),
52 FxaState::AuthIssues => self.process_event_with_internal_state_machine(
53 internal_machines::AuthIssuesStateMachine,
54 event,
55 ),
56 }
57 }
58
59 fn process_event_with_internal_state_machine<T: InternalStateMachine>(
60 &mut self,
61 state_machine: T,
62 event: FxaEvent,
63 ) -> Result<FxaState> {
64 let device_config = self.handle_state_machine_initialization(&event)?;
65
66 breadcrumb!("FxaStateMachine.process_event starting: {event}");
67 let mut internal_state = state_machine.initial_state(event)?;
68 let mut count = 0;
69 loop {
73 count += 1;
74 if count > MAX_INTERNAL_TRANSITIONS {
75 breadcrumb!("FxaStateMachine.process_event finished (MAX_INTERNAL_TRANSITIONS)");
76 return Err(Error::StateMachineLogicError(
77 "infinite loop detected".to_owned(),
78 ));
79 }
80 match internal_state {
81 InternalState::Complete(new_state) => {
82 breadcrumb!("FxaStateMachine.process_event finished (Complete({new_state}))");
83 self.auth_state = new_state.clone();
84 return Ok(new_state);
85 }
86 InternalState::Cancel => {
87 breadcrumb!("FxaStateMachine.process_event finished (Cancel)");
88 return Ok(self.auth_state.clone());
89 }
90 state => {
91 let event = state.make_call(self, &device_config)?;
92 let event_msg = event.to_string();
93 internal_state = state_machine.next_state(state, event)?;
94 breadcrumb!("FxaStateMachine.process_event {event_msg} -> {internal_state}")
95 }
96 }
97 }
98 }
99
100 fn handle_state_machine_initialization(&mut self, event: &FxaEvent) -> Result<DeviceConfig> {
105 match &event {
106 FxaEvent::Initialize { device_config } => match self.device_config {
107 Some(_) => Err(Error::InvalidStateTransition(
108 "Initialize already sent".to_owned(),
109 )),
110 None => {
111 self.device_config = Some(device_config.clone());
112 Ok(device_config.clone())
113 }
114 },
115 _ => match &self.device_config {
116 Some(device_config) => Ok(device_config.clone()),
117 None => Err(Error::InvalidStateTransition(
118 "Initialize not yet sent".to_owned(),
119 )),
120 },
121 }
122 }
123}