infrarust 1.2.0

A Rust universal Minecraft proxy
Documentation
use std::collections::HashMap;
use std::sync::Arc;

use crate::cli::command::{Command, CommandFuture};
use crate::cli::format as fmt;
use crate::core::shared_component::SharedComponent;
use tracing::debug;

pub struct PlayersCommand {
    shared: Arc<SharedComponent>,
}

impl PlayersCommand {
    pub fn new(shared: Arc<SharedComponent>) -> Self {
        Self { shared }
    }

    async fn format_player_list(&self) -> String {
        let mut result = String::new();
        let supervisor = self.shared.actor_supervisor();
        let actors = supervisor.get_all_actors().await;

        if actors.is_empty() {
            return fmt::warning("No players connected.").to_string();
        }

        let mut players_by_config: HashMap<String, Vec<(String, String, uuid::Uuid)>> =
            HashMap::new();

        for (config_id, pairs) in actors {
            for pair in pairs {
                if !pair.username.is_empty()
                    && !pair.shutdown.load(std::sync::atomic::Ordering::SeqCst)
                {
                    let addr = match pair.client.get_peer_addr().await {
                        Ok(addr) => addr.to_string(),
                        Err(_) => "unknown".to_string(),
                    };

                    players_by_config
                        .entry(config_id.clone())
                        .or_default()
                        .push((pair.username.clone(), addr, pair.session_id));
                }
            }
        }

        let tota_players = players_by_config.values().map(|v| v.len()).sum::<usize>();
        result.push_str(&format!("{}\n\n", fmt::header("Connected Players")));

        for (config_id, players) in players_by_config {
            result.push_str(&format!(
                "{} {} {}\n",
                fmt::sub_header("Server"),
                fmt::entity(&config_id),
                fmt::secondary(&format!("({} players)", players.len()))
            ));

            for (i, (username, addr, session_id)) in players.iter().enumerate() {
                result.push_str(&format!(
                    "  {}. {} - {} {}\n",
                    i + 1,
                    fmt::entity(username),
                    fmt::secondary(addr),
                    fmt::id(&format!("(session: {})", session_id))
                ));
            }
            result.push('\n');
        }
        result.push_str(&format!(
            "{} \n",
            fmt::header(&format!("Total Players ({})", &tota_players.to_string()))
        ));
        result
    }
}

impl Command for PlayersCommand {
    fn name(&self) -> &'static str {
        "list"
    }

    fn description(&self) -> &'static str {
        "Lists all connected players by server"
    }

    fn execute(&self, _args: Vec<String>) -> CommandFuture {
        debug!("Executing players command");
        let shared = self.shared.clone();

        Box::pin(async move {
            let players_cmd = PlayersCommand { shared };
            players_cmd.format_player_list().await
        })
    }
}