From a210ab86ee43dea3b4d9d0f2af5750c5a4adf096 Mon Sep 17 00:00:00 2001 From: "1992414357@qq.com" <1992414357@qq.com> Date: Fri, 13 Jun 2025 19:20:06 +0800 Subject: . --- apps/console/src/utils.rs | 107 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 apps/console/src/utils.rs (limited to 'apps/console/src/utils.rs') diff --git a/apps/console/src/utils.rs b/apps/console/src/utils.rs new file mode 100644 index 0000000..1e65f0e --- /dev/null +++ b/apps/console/src/utils.rs @@ -0,0 +1,107 @@ +use std::io::{self, Read, Write}; +use crossterm::terminal; +use tokio::task; + +pub fn read_password(prompt: &str) -> Option { + print!("{}", prompt); + io::stdout().flush().unwrap(); + + let raw_mode_enabled = terminal::enable_raw_mode().is_ok(); + if !raw_mode_enabled { + eprintln!("Warning: Password will be displayed in plain text"); + } + + let mut buffer = Vec::new(); + loop { + let mut byte = [0]; + if io::stdin().read(&mut byte).is_err() || byte[0] == b'\n' || byte[0] == b'\r' { + break; + } + + match byte[0] { + 8 | 127 => { + if buffer.pop().is_some() { + print!("\x08 \x08"); + io::stdout().flush().unwrap(); + } + } + 3 => { + println!(); + return None; + } + _ => { + buffer.push(byte[0]); + print!("*"); + io::stdout().flush().unwrap(); + } + } + } + + if raw_mode_enabled { + terminal::disable_raw_mode().unwrap(); + } + println!(); + + Some(String::from_utf8_lossy(&buffer).into_owned()) +} + +pub fn read_password_and_confirm( + prompt: &str, + confirm_prompt: &str +) -> Option { + loop { + let pw1 = read_password(prompt).unwrap(); + let pw2 = read_password(confirm_prompt).unwrap(); + + if pw1 == pw2 { + return Some(pw1); + } + eprintln!("The passwords entered twice do not match, please try again."); + } +} + +pub fn confirm(prompt: &str) -> bool { + let prompt = format!("{} [Y/n]: ", prompt); + loop { + let input = read_password(&prompt).unwrap_or_default(); + match input.to_lowercase().as_str() { + "y" | "yes" | "" => return true, + "n" | "no" => return false, + _ => eprintln!("Invalid input, please enter Y or n."), + } + } +} + +pub async fn read_password_async(prompt: &str) -> Option { + let prompt = prompt.to_owned(); + task::spawn_blocking(move || read_password(&prompt)) + .await + .unwrap_or_else(|_| None) +} + +pub async fn read_password_and_confirm_async( + prompt: &str, + confirm_prompt: &str +) -> Option { + loop { + let pw1 = read_password_async(prompt).await.unwrap(); + let pw2 = read_password_async(confirm_prompt).await.unwrap(); + + if pw1 == pw2 { + return Some(pw1); + } + eprintln!("The passwords entered twice do not match, please try again."); + } +} + +pub async fn confirm_async(prompt: &str) -> bool { + let prompt = format!("{} [Y/n]: ", prompt); + loop { + let input = read_password_async(&prompt).await.unwrap_or_default(); + match input.to_lowercase().as_str() { + "y" | "yes" | "" => return true, + "n" | "no" => return false, + _ => eprintln!("Invalid input, please enter Y or n."), + } + } +} \ No newline at end of file -- cgit