avam-client and oauth2
This commit is contained in:
149
avam-client/src/state_machine.rs
Normal file
149
avam-client/src/state_machine.rs
Normal file
@@ -0,0 +1,149 @@
|
||||
use tokio::sync::broadcast::{Receiver, Sender};
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
models::{CodeChallengeMethod, CodeVerifier},
|
||||
oauth,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum State {
|
||||
Init,
|
||||
AppStart {
|
||||
config: Config,
|
||||
},
|
||||
Authenticate {
|
||||
code_verifier: CodeVerifier,
|
||||
code_challenge_method: CodeChallengeMethod,
|
||||
},
|
||||
Connect {
|
||||
token: String,
|
||||
},
|
||||
WaitForSim,
|
||||
Running,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Event {
|
||||
Ready {
|
||||
config: Config,
|
||||
},
|
||||
StartAuthenticate {
|
||||
code_verifier: CodeVerifier,
|
||||
code_challenge_method: CodeChallengeMethod,
|
||||
}, // should not be string
|
||||
TokenReceived {
|
||||
token: String,
|
||||
}, // AppStart and Authenticate can fire off TokenReceived to transition into Connect
|
||||
Connected, // Once connected to the socket, and properly authenticated, fire off Connected to transition to WaitForSim
|
||||
Disconnected, // If for whatever reason we're disconnected from the backend, we need to transition back to Connect
|
||||
SimConnected, // SimConnect is connected, we're in the world and ready to send data, transition to Running
|
||||
SimDisconnected, // SimConnect is disconnected, we've finished the flight and exited back to the menu, transition back to WaitForSim
|
||||
Quit,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub async fn next(self, event: Event) -> State {
|
||||
match (self, event) {
|
||||
// (Current State, SomeEvent) => NextState
|
||||
(State::Init, Event::Ready { config }) => State::AppStart { config },
|
||||
(
|
||||
State::AppStart { .. },
|
||||
Event::StartAuthenticate {
|
||||
code_verifier: code_challenge,
|
||||
code_challenge_method,
|
||||
},
|
||||
) => Self::Authenticate {
|
||||
code_verifier: code_challenge,
|
||||
code_challenge_method,
|
||||
}, // Goto Authenticate
|
||||
|
||||
(State::AppStart { .. }, Event::TokenReceived { token }) => State::Connect { token },
|
||||
(State::Authenticate { .. }, Event::TokenReceived { token }) => {
|
||||
State::Connect { token }
|
||||
}
|
||||
|
||||
(State::Connect { .. }, Event::Connected) => todo!(), // Goto WaitForSim
|
||||
|
||||
(State::WaitForSim, Event::SimConnected) => todo!(), // Goto Running
|
||||
|
||||
(State::Running, Event::Disconnected) => todo!(), // Goto Connect
|
||||
(State::Running, Event::SimDisconnected) => todo!(), // Goto WaitForSim
|
||||
|
||||
(_, Event::Quit) => todo!(), // All events can go into quit, to shutdown the application
|
||||
|
||||
_ => panic!("Invalid state transition"),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run(&self, signal: Sender<Event>) -> Result<(), anyhow::Error> {
|
||||
match self {
|
||||
State::Init => Ok(()),
|
||||
State::AppStart { config } => {
|
||||
if let Some(token) = config.token() {
|
||||
signal.send(Event::TokenReceived {
|
||||
token: token.to_string(),
|
||||
})?;
|
||||
} else {
|
||||
let code_verifier = CodeVerifier::new();
|
||||
let code_challenge_method = CodeChallengeMethod::Sha256;
|
||||
|
||||
config.set_code_verifier(Some(code_verifier.clone()))?;
|
||||
config.set_code_challenge_method(Some(code_challenge_method.clone()))?;
|
||||
|
||||
signal.send(Event::StartAuthenticate {
|
||||
code_verifier,
|
||||
code_challenge_method,
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
State::Authenticate {
|
||||
code_verifier,
|
||||
code_challenge_method,
|
||||
} => {
|
||||
oauth::open_browser(code_verifier.clone(), code_challenge_method.clone())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
State::Connect { token } => {
|
||||
println!("Holyshit we've got a token: {}", token);
|
||||
Ok(())
|
||||
}
|
||||
State::WaitForSim => Ok(()),
|
||||
State::Running => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start(
|
||||
config: Config,
|
||||
event_sender: Sender<Event>,
|
||||
mut event_receiver: Receiver<Event>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let mut state = State::Init;
|
||||
|
||||
state.run(event_sender.clone()).await?;
|
||||
|
||||
loop {
|
||||
if let Ok(event) = event_receiver.recv().await {
|
||||
if event == Event::Quit {
|
||||
println!("Shutting down State Machine");
|
||||
break;
|
||||
}
|
||||
|
||||
state = state.next(event).await;
|
||||
|
||||
// before run
|
||||
if let State::Connect { token } = &state {
|
||||
// before run Connect, save the given token in config
|
||||
config.set_token(Some(token.clone()))?;
|
||||
}
|
||||
|
||||
state.run(event_sender.clone()).await?;
|
||||
}
|
||||
}
|
||||
|
||||
println!("State Machine Shutdown");
|
||||
Ok(())
|
||||
}
|
Reference in New Issue
Block a user