sysmonk/squire/
util.rs

1use regex::Regex;
2use std::collections::HashMap;
3use std::process::Command;
4
5/// Function to retrieve the REGEX object for an IPv4 address format
6///
7/// # Returns
8///
9/// A `Regex` object that can be used to match an IPv4 address format
10pub fn ip_regex() -> Regex {
11    Regex::new(
12        r"^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$"
13    ).unwrap()
14}
15
16/// Mapping of URLs to check for public IP addresses
17///
18/// # Returns
19///
20/// A `HashMap` containing the URL and a boolean value indicating whether the URL expects text or JSON response
21pub fn public_ip_mapping() -> HashMap<String, bool> {
22    let mapping: HashMap<String, bool> = vec![
23        ("https://checkip.amazonaws.com/".to_string(), true), // expects text
24        ("https://api.ipify.org/".to_string(), true),         // expects text
25        ("https://ipinfo.io/ip/".to_string(), true),          // expects text
26        ("https://v4.ident.me/".to_string(), true),           // expects text
27        ("https://httpbin.org/ip".to_string(), false),        // expects JSON
28        ("https://myip.dnsomatic.com/".to_string(), true),    // expects text
29    ]
30        .into_iter()
31        .collect();
32    mapping
33}
34
35
36/// Function to convert seconds to human-readable format
37///
38/// # Arguments
39///
40/// * `seconds` - The number of seconds to convert
41///
42/// # Returns
43///
44/// A `String` containing the human-readable format of the seconds
45pub fn convert_seconds(seconds: i64) -> String {
46    let days = seconds / 86_400; // 86,400 seconds in a day
47    let hours = (seconds % 86_400) / 3_600; // 3,600 seconds in an hour
48    let minutes = (seconds % 3_600) / 60; // 60 seconds in a minute
49    let remaining_seconds = seconds % 60;
50
51    let mut result = Vec::new();
52
53    if days > 0 {
54        result.push(format!("{} day{}", days, if days > 1 { "s" } else { "" }));
55    }
56    if hours > 0 {
57        result.push(format!("{} hour{}", hours, if hours > 1 { "s" } else { "" }));
58    }
59    if minutes > 0 && result.len() < 2 {
60        result.push(format!("{} minute{}", minutes, if minutes > 1 { "s" } else { "" }));
61    }
62    if remaining_seconds > 0 && result.len() < 2 {
63        result.push(format!("{} second{}", remaining_seconds, if remaining_seconds > 1 { "s" } else { "" }));
64    }
65    result.join(" and ")
66}
67
68/// Function to convert byte size to human-readable format
69///
70/// # Arguments
71///
72/// * `byte_size` - The size in bytes to convert
73///
74/// # Returns
75///
76/// A `String` containing the human-readable format of the byte size
77pub fn size_converter(byte_size: u64) -> String {
78    let size_name = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
79    let mut index = 0;
80    let mut size = byte_size as f64;
81
82    while size >= 1024.0 && index < size_name.len() - 1 {
83        size /= 1024.0;
84        index += 1;
85    }
86
87    format!("{:.2} {}", size, size_name[index])
88}
89
90/// Function to run a terminal command.
91///
92/// # Arguments
93///
94/// * `command` - Command to run
95/// * `log` - Boolean flag to log errors
96///
97/// # Returns
98///
99/// A `String` containing the parsed size string.
100pub fn run_command(command: &str, args: &[&str], log: bool) -> Result<String, String> {
101    match Command::new(command)
102        .args(args)
103        .output()
104    {
105        Ok(output) => {
106            if output.status.success() {
107                Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
108            } else {
109                let stderr = String::from_utf8_lossy(&output.stderr).to_string();
110                let exit_code = output.status.code().unwrap_or(-1);
111                if log {
112                    log::error!("Command [{}] failed with exit code: {}", command, exit_code);
113                    log::error!("Stderr: {}", stderr);
114                }
115                Err(stderr)
116            }
117        }
118        Err(err) => {
119            if log {
120                log::error!("Failed to execute command [{}]: {}", command, err);
121            }
122            Err(err.to_string())
123        }
124    }
125}
126
127/// Function to capitalize the first letter of each word in a string.
128///
129/// # Arguments
130///
131/// * `s` - The string to capitalize
132/// * `sep` - The separator to split the string
133///
134/// # Returns
135///
136/// A `String` containing the capitalized string
137pub fn capwords(string: &str, sep: Option<&str>) -> String {
138    let separator = sep.unwrap_or(" ");
139    let mut result = Vec::new();
140
141    for word in string.split(separator) {
142        let mut chars = word.chars();
143        if let Some(first) = chars.next() {
144            let capitalized_word = first.to_uppercase().collect::<String>() + chars.as_str();
145            result.push(capitalized_word);
146        } else {
147            result.push(String::new());
148        }
149    }
150
151    result.join(separator)
152}