use std::fmt::Display; use async_trait::async_trait; use gamenight_api_client_rs::apis::configuration::Configuration; use inquire::Text; use crate::{domain::config::{Config, Instance}, flows::{gamenight_menu::GamenightMenu, login::Login, FlowError}}; use super::{Flow, FlowOutcome, FlowResult, GamenightState}; #[derive(Clone)] pub struct Connect { instance: Option } impl Connect { pub fn to(instance: Instance) -> Self { Self { instance: Some(instance) } } pub fn new() -> Self { Self { instance: None } } pub fn prompt_new_instance(&self, config: &Config) -> Result, FlowError> { let instance_name: String; loop { if let Some(name) = Text::new("Name this instance:").prompt_skippable()? { if config.instances.iter().find(|x| x.name == name).is_none() { instance_name = name; break; } else { clear_screen::clear(); println!("Name already in use, please provide a unique name"); } } else { return Ok(None); } } if let Some(url) = Text::new("What is the server URL: ").prompt_skippable()? { Ok(Some(Instance::new(instance_name, url))) } else { Ok(None) } } pub async fn try_refresh_token_if_exists(&self, instance: &mut Instance, api_configuration: &mut Configuration, config: &mut Config, instance_name: &String) -> Result { if let Some(token) = &instance.token { api_configuration.bearer_access_token = Some(token.clone()); let result = gamenight_api_client_rs::apis::default_api::post_token(api_configuration).await; if let Ok(token) = result { let instance = config.instances.iter_mut().find(|x| x.name == *instance_name).unwrap(); instance.token = token.jwt_token.clone(); api_configuration.bearer_access_token = token.jwt_token.clone(); Config::save(&config)?; Ok(true) } else { Ok(false) } } else { Ok(false) } } pub fn update_state_on_logon(&self, instance: &mut Instance, api_configuration: &mut Configuration, config: &mut Config, instance_name: &String) -> Result<(), FlowError> { if self.instance.is_none() { instance.token = Some(api_configuration.bearer_access_token.clone().unwrap()); config.instances.push(instance.clone()); } else { let instance = config.instances.iter_mut().find(|x| x.name == *instance_name).unwrap(); instance.token = Some(api_configuration.bearer_access_token.clone().unwrap()); } config.last_instance = Some(instance_name.clone()); Config::save(&config)?; Ok(()) } } #[async_trait] impl<'a> Flow<'a> for Connect { async fn run(&self, state: &'a mut GamenightState) -> FlowResult<'a> { let mut instance = if let Some(instance) = self.instance.clone() { instance } else { if let Some(instance) = self.prompt_new_instance(&state.gamenight_configuration)? { instance } else { return Ok((FlowOutcome::Cancelled, state)); } }; let instance_name = instance.name.clone(); state.api_configuration.base_path = instance.url.clone(); if self.try_refresh_token_if_exists(&mut instance, &mut state.api_configuration, &mut state.gamenight_configuration, &instance_name).await? { let gamenight_menu_flow = GamenightMenu::new(); gamenight_menu_flow.run(state).await } else { let login_flow = Login::new(); let (outcome, state) = login_flow.run(state).await?; if outcome == FlowOutcome::Successful { self.update_state_on_logon(&mut instance, &mut state.api_configuration, &mut state.gamenight_configuration, &instance_name)?; let gamenight_menu_flow = GamenightMenu::new(); gamenight_menu_flow.run(state).await } else { Ok((outcome, state)) } } } } impl Display for Connect { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(instance) = &self.instance { write!(f, "Connect to: {}", instance.name) } else { write!(f, "Connect") } } }