aboutsummaryrefslogtreecommitdiffstats
path: root/src/config/wizard.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/config/wizard.rs')
-rw-r--r--src/config/wizard.rs159
1 files changed, 159 insertions, 0 deletions
diff --git a/src/config/wizard.rs b/src/config/wizard.rs
new file mode 100644
index 0000000..b13d0e0
--- /dev/null
+++ b/src/config/wizard.rs
@@ -0,0 +1,159 @@
+use crate::prelude::*;
+use std::io::Write as _;
+
+pub fn run() -> Result<Option<config::Config>> {
+ println!("No configuration file found.");
+ let run_wizard = prompt(
+ "Would you like me to ask you some questions to generate one?",
+ )?;
+ if !run_wizard {
+ let shouldnt_touch = prompt(
+ "Would you like me to ask this question again in the future?",
+ )?;
+ if !shouldnt_touch {
+ touch_config_file()?;
+ }
+ return Ok(None);
+ }
+
+ let connect_address =
+ prompt_addr("Which server would you like to connect to?")?;
+ let tls = prompt("Does this server require a TLS connection?")?;
+ let auth_type = prompt_auth_type(
+ "How would you like to authenticate to this server?",
+ )?;
+
+ write_config_file(&connect_address, tls, &auth_type).and_then(
+ |config_filename| {
+ Some(super::config_from_filename(&config_filename)).transpose()
+ },
+ )
+}
+
+fn touch_config_file() -> Result<()> {
+ let config_filename = crate::dirs::Dirs::new()
+ .config_file(super::CONFIG_FILENAME, false)
+ .unwrap();
+ std::fs::File::create(config_filename.clone()).context(
+ crate::error::CreateFileSync {
+ filename: config_filename.to_string_lossy(),
+ },
+ )?;
+ Ok(())
+}
+
+fn write_config_file(
+ connect_address: &str,
+ tls: bool,
+ auth_type: &str,
+) -> Result<std::path::PathBuf> {
+ let contents = format!(
+ r#"[client]
+connect_address = "{}"
+tls = {}
+auth = "{}"
+"#,
+ connect_address, tls, auth_type
+ );
+ let config_filename = crate::dirs::Dirs::new()
+ .config_file(super::CONFIG_FILENAME, false)
+ .unwrap();
+ let mut file = std::fs::File::create(config_filename.clone()).context(
+ crate::error::CreateFileSync {
+ filename: config_filename.to_string_lossy(),
+ },
+ )?;
+ file.write_all(contents.as_bytes())
+ .context(crate::error::WriteFileSync)?;
+ Ok(config_filename)
+}
+
+fn prompt(msg: &str) -> Result<bool> {
+ print!("{} [y/n]: ", msg);
+ std::io::stdout()
+ .flush()
+ .context(crate::error::FlushTerminal)?;
+ let mut response = String::new();
+ std::io::stdin()
+ .read_line(&mut response)
+ .context(crate::error::ReadTerminal)?;
+
+ loop {
+ match response.trim() {
+ "y" | "yes" => {
+ return Ok(true);
+ }
+ "n" | "no" => {
+ return Ok(false);
+ }
+ _ => {
+ print!("Please answer [y]es or [n]o: ");
+ std::io::stdout()
+ .flush()
+ .context(crate::error::FlushTerminal)?;
+ std::io::stdin()
+ .read_line(&mut response)
+ .context(crate::error::ReadTerminal)?;
+ }
+ }
+ }
+}
+
+fn prompt_addr(msg: &str) -> Result<String> {
+ loop {
+ print!("{} [addr:port]: ", msg);
+ std::io::stdout()
+ .flush()
+ .context(crate::error::FlushTerminal)?;
+ let mut response = String::new();
+ std::io::stdin()
+ .read_line(&mut response)
+ .context(crate::error::ReadTerminal)?;
+
+ match response.trim() {
+ addr if addr.contains(':') => {
+ match super::to_connect_address(addr) {
+ Ok(..) => return Ok(addr.to_string()),
+ _ => {
+ println!("Couldn't parse '{}'.", addr);
+ }
+ };
+ }
+ _ => {
+ println!("Please include a port number.");
+ }
+ }
+ }
+}
+
+fn prompt_auth_type(msg: &str) -> Result<String> {
+ let auth_type_names: Vec<_> = crate::protocol::AuthType::iter()
+ .map(crate::protocol::AuthType::name)
+ .collect();
+
+ loop {
+ println!("{}", msg);
+ println!("Options are:");
+ for (i, name) in auth_type_names.iter().enumerate() {
+ println!("{}: {}", i + 1, name);
+ }
+ print!("Choose [1-{}]: ", auth_type_names.len());
+ std::io::stdout()
+ .flush()
+ .context(crate::error::FlushTerminal)?;
+ let mut response = String::new();
+ std::io::stdin()
+ .read_line(&mut response)
+ .context(crate::error::ReadTerminal)?;
+
+ let num: Option<usize> = response.trim().parse().ok();
+ if let Some(num) = num {
+ if num > 0 && num <= auth_type_names.len() {
+ let name = auth_type_names[num - 1];
+ return Ok(name.to_string());
+ }
+ }
+
+ println!("Invalid response '{}'", response.trim());
+ }
+}