mcserver 0.6.2

A command line interface tool which simplifies minecraft server management with zellij and mcrcon
#[cfg(not(disable_tokenization))]
use proc_macro2::TokenStream;

#[cfg(not(disable_tokenization))]
use quote::{ToTokens, quote};

use serde::{Deserialize, Serialize};
use std::{
    collections::HashMap,
    ffi::OsStr,
    fmt::{self, Debug, Formatter},
};

pub trait AllowedConfigValue {}
impl AllowedConfigValue for String {}
impl AllowedConfigValue for &'static str {}

#[derive(Debug, Deserialize)]
pub struct StaticConfig<T = &'static str>
where
    T: AllowedConfigValue,
{
    pub contact: T,
    pub dynamic_config_path: T,
}

#[cfg(not(disable_tokenization))]
impl ToTokens for StaticConfig<String> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let contact = &self.contact;
        let dynamic_config_path = &self.dynamic_config_path;
        tokens.extend(quote! {
            StaticConfig {
                contact: #contact,
                dynamic_config_path: #dynamic_config_path,
            }
        });
    }
}

#[derive(Clone, Deserialize, PartialEq, Serialize)]
pub struct Password(pub String);

impl AsRef<OsStr> for Password {
    fn as_ref(&self) -> &OsStr {
        OsStr::new(&self.0)
    }
}

#[cfg(not(disable_tokenization))]
impl ToTokens for Password {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let password = &self.0;
        tokens.extend(quote! {#password})
    }
}

impl Debug for Password {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "(hidden)")
    }
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct RconConfig {
    pub server_address: Option<String>,
    pub port: Option<u16>,
    pub password: Option<Password>,
}

#[cfg(not(disable_tokenization))]
impl ToTokens for RconConfig {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let server_address = match self.server_address.as_ref() {
            Some(server_address) => quote! {
                Some(String::from(#server_address))
            },
            None => quote! { None },
        };

        let port = match self.port {
            Some(port) => quote! { Some(#port) },
            None => quote! { None },
        };

        let password = match self.password.as_ref() {
            Some(password) => quote! { Some(Password(String::from(#password))) },
            None => quote! { None },
        };

        tokens.extend(quote! {
            RconConfig {
                server_address: #server_address,
                port: #port,
                password: #password,
            }
        })
    }
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct DynamicConfig {
    pub default_java_args: String,
    pub nogui: bool,
    pub servers_directory: String,
    pub default_server: String,
    pub rcon: HashMap<String, RconConfig>,
}

#[cfg(not(disable_tokenization))]
impl ToTokens for DynamicConfig {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let default_java_args = &self.default_java_args;
        let nogui = &self.nogui;
        let servers_directory = &self.servers_directory;
        let default_server = &self.default_server;

        let key_value_pairs = self.rcon.iter().map(|(k, v)| {
            quote! { ( String::from(#k), #v )}
        });

        tokens.extend(quote! {
            pub static DEFAULT_DYNAMIC_CONFIG: std::sync::OnceLock<DynamicConfig> = std::sync::OnceLock::new();

            pub fn get_default_dynamic_config() -> &'static DynamicConfig {
                use std::collections::HashMap;
                DEFAULT_DYNAMIC_CONFIG.get_or_init(||
                    DynamicConfig {
                        default_java_args: String::from(#default_java_args),
                        nogui: #nogui,
                        servers_directory: String::from(#servers_directory),
                        default_server: String::from(#default_server),
                        rcon: HashMap::from([
                            #(#key_value_pairs),*
                        ]),
                    }
                )
            }
        });
    }
}