1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#[cfg(feature = "colors")]
use colored::Colorize;
use std::{fmt, fmt::Formatter, time::Duration};

const TIMEOUT: u64 = 5;

/// The availability status of a crate name.
pub enum Availability {
    /// The crate name is available.
    Available,
    /// The crate name is unavailable.
    Unavailable,
    /// The crate name can't be resolved.
    Unknown,
}

impl fmt::Display for Availability {
    #[cfg(not(feature = "colors"))]
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Availability::Available => write!(f, "Available"),
            Availability::Unavailable => write!(f, "Unavailable"),
            Availability::Unknown => write!(f, "Unknown"),
        }
    }

    #[cfg(feature = "colors")]
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Availability::Available => write!(f, "{}", "Available".green()),
            Availability::Unavailable => write!(f, "{}", "Unavailable".red()),
            Availability::Unknown => write!(f, "{}", "Unknown".bright_black()),
        }
    }
}

/// Checks the availability for a given crate name.
///
/// # Arguments
///
/// - `name`: The crate name to check
///
/// # Returns
///
/// `Ok(Availability)` if the name could be resolved, an error otherwise.
///
/// # Note
///
/// The needed network request will timeout after five seconds.
pub fn check_availability(name: impl AsRef<str>) -> Result<Availability, ()> {
    let name = name.as_ref();
    if name.is_empty() {
        eprintln!("Crate name can't be empty");
        return Err(());
    }

    let url = format!("https://crates.io/api/v1/crates/{}", name);
    let resp = ureq::get(&url).timeout(Duration::from_secs(TIMEOUT)).call();
    let availability = match resp.status() {
        200 => Availability::Unavailable,
        404 => Availability::Available,
        _ => Availability::Unknown,
    };
    Ok(availability)
}