minehut 2.0.0

Simple, easy to use Rust wrapper for the Minehut API
Documentation
//! A simple, easy to use Rust wrapper for the Minehut API.
//! 
//! All functions that return/modify data in the crate use async/await.
//! 
//! This module provides functions for:
//! 
//! * Getting Minehut stats in an organized manner from the Minehut API.
//! * Client authentication allowing you to access and or modify more data.
//! 
//! # Example
//! Creating a client instance:
//! 
//! ```no_run
//! // Functions can be seen at the Client struct
//! let client = minehut::Client::new("auth-token", "session-id");
//! 
//! // Do something with it
//! ```

pub mod models;
mod http;
mod handlers;

use std::fmt;

use crate::models::{PlayerDistribution, HomePageStats, SimpleStats, OwnedServer, OwnedServerRes};
pub use crate::handlers::{servers, products};

/// All error types for the crate. Used by the crate to propogate errors. 
/// Users can use it for error handling.
#[derive(Debug)]
pub enum Error {
    /// This is called if Reqwest produces an HTTP error.
    Http(reqwest::Error), 
    /// This is called if Serde failed to parse the response. Usually this
    /// means the data received is not what the crate expected. 
    Json(reqwest::Error),
    /// This means the operation failed.
    FailedOp(String)
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::Http(e) => write!(f, "{}", e)?,
            Error::Json(e) => write!(f, "{}", e)?,
            Error::FailedOp(s) => write!(f, "{}", s)?
        }
        Ok(())
    }
}

/// This is the Minehut client struct, it only stores an authentication
/// token and session ID. All data that require authentication can only
/// be ran using this struct.
pub struct Client {
    /// The authentication token.
    auth_token: String,
    /// The session ID, this changes periodically.
    session_id: String
}

impl Client {
    /// Creates a new instance of Client with provided auth and session 
    /// ID. You can get both of these using the inspect element on the
    /// Minehut dashboard.
    /// 
    /// # Arguments
    /// 
    /// * `auth` - Authentication token from Minehut.
    /// * `session_id` - Session ID from Minehut.
    /// 
    /// # Example
    /// 
    /// ```no_run
    /// use minehut::Client;
    /// 
    /// let client = Client::new("auth-token", "session-id");
    /// // Now do something with
    /// ```
    pub fn new(auth_token: String, session_id: String) -> Self {
        Client { 
            auth_token,
            session_id 
        }
    }

    /// Retrieves a server that the client user owns by name using the Minehut
    /// API.
    /// 
    /// # Arguments
    /// 
    /// * `name` - Name of the server.
    /// 
    /// # Example
    /// 
    /// ```no_run
    /// let client = minehut::Client::new("","");
    /// 
    /// match client.my_server("weird-name").await {
    ///     Err(_) => println!("Cannot fetch server"),
    ///     Ok(s) => println!("{s:?}")
    /// }
    /// ```
    /// 
    /// # Error
    /// 
    /// Returns an error if a server could not be found or if found server is not owned
    /// by the client user.
    pub async fn my_server(&self, name: &str) -> Result<OwnedServer, Error> {
        let id = handlers::servers::server_from_name(name).await?.id;

        let server_res = http::req_client_data::<OwnedServerRes>(
            &self,
            &format!("server/{id}/server_data")
        ).await?;

        Ok(server_res.server)
    }
}

/// Gets a `SimpleStats` struct from Minehut asynchronously. Gets simple Minehut
/// statistics.
/// 
/// # Examples
/// 
/// ```
/// async fn print_stats() {
///     // It is safe to assume this will not return an error.
///     // As such we will unwrap() the result.
///     let stats = minehut::simple_stats().await.unwrap();
/// 
///     println!("{} players are on", stats.player_count);
///     println!("{} hosted servers", stats.server_count);
/// }
/// ```
/// 
/// # Error
/// 
/// Returns a HTTP error if it cannot load page, usually a network error.
pub async fn simple_stats() -> Result<SimpleStats, Error> {
    http::req_data::<SimpleStats>("network/simple_stats").await
}

/// Gets a `PlayerDistribution` struct from Minehut asynchronously. Gets the player
/// distribution for Java and Bedrock on Minehut.
/// 
/// # Examples
/// 
/// ```
/// #[tokio::main]
/// async fn main() {
///     // It is safe to assume this will not return an error.
///     // As such, we will unwrap() the result.
///     let dist = minehut::player_distribution().await.unwrap();
/// 
///     println!("{} java players", dist.java_total);
///     println!("{} bedrock servers", dist.bedrock_player_server);
/// }
/// ```
/// 
/// # Error
/// 
/// Returns a HTTP error if it cannot load page, this is usally a network error.
pub async fn player_distribution() -> Result<PlayerDistribution, Error> {
    http::req_data::<PlayerDistribution>("network/players/distribution").await
}

/// Gets a `HomePageStats` from Minehut asynchronously. Returns the home page
/// statistics.
/// 
/// # Examples
/// 
/// ```
/// #[tokio::main]
/// async fn main() {
///     // It is safe to assume this will not return an error.
///     // As such, we will unwrap() the result.
///     let home = minehut::home_page_stats().await.unwrap();
/// 
///     println!("{} users, {} server", home.user_count, home.server_count);
/// }
/// ```
/// 
/// # Error
///  
/// Returns a HTTP error if it cannot load page, this is usally a network error.
pub async fn homepage_stats() -> Result<HomePageStats, Error> {
    http::req_data::<HomePageStats>("network/homepage_stats").await
}