server-watchdog 0.1.0

A server monitoring and remote control tool via messenger.
Documentation
use std::sync::OnceLock;
use regex::Regex;
use tokio::io::{stdin, AsyncBufReadExt, BufReader};

pub async fn read_string_option(name: &str, format_checker: FormatChecker) -> Option<String> {
    let mut reader = BufReader::new(stdin());
    loop {
        println!("--- type {name} ---");
        println!("(Leave empty and press Enter to set as None)");
        let mut value = String::new();
        match reader.read_line(&mut value).await {
            Ok(_) => (),
            Err(_) => continue
        }

        let value = value.trim();

        if value.is_empty() {
            return None
        }

        if format_checker.valid(value) {
            return Some(value.to_string());
        } else {
            println!("invalid input");
        }
    }
}

pub async fn read_string(name: &str, format_checker: FormatChecker) -> String {
    let mut reader = BufReader::new(stdin());
    loop {
        println!("--- type {name} ---");
        let mut value = String::new();
        match reader.read_line(&mut value).await {
            Ok(_) => (),
            Err(_) => continue
        }

        let value = value.trim();

        if format_checker.valid(value) {
            return value.to_string();
        } else {
            println!("invalid input");
        }
    }
}

pub async fn read_int(name: &str) -> i32 {
    let mut reader = BufReader::new(stdin());
    loop {
        println!("--- type {name} ---");
        let mut value = String::new();
        match reader.read_line(&mut value).await {
            Ok(_) => (),
            Err(_) => continue
        }

        let value = value.trim();

        match value.parse() {
            Ok(value) => {
              return value
            },
            Err(_) => {
                println!("invalid input");
                continue;
            }
        };
    }
}

pub enum FormatChecker {
    BaseUrl,
    Name,
    NotAllowWhitespace,
    None,
}

impl FormatChecker {
    pub fn valid(&self, text: &str) -> bool {
        match self {
            FormatChecker::BaseUrl => {
                static RE: OnceLock<Regex> = OnceLock::new();
                RE.get_or_init(||{Regex::new(r"^[a-zA-Z]+://[a-zA-Z0-9]+(:[0-9]+)?$").unwrap()})
                    .is_match(text)
            },
            FormatChecker::Name => {
                static RE: OnceLock<Regex> = OnceLock::new();
                RE.get_or_init(||{Regex::new(r"^[a-zA-Z0-9-]+$").unwrap()})
                    .is_match(text)
            },
            FormatChecker::NotAllowWhitespace => {
                !text.chars().any(|c| c.is_whitespace())
            },
            FormatChecker::None => true
        }
    }
}