use std::time::Duration; use async_std::net::TcpStream; use async_std::prelude::*; use rust_rcon::{Connection, Error as RconError}; use tokio::time; use crate::config::Config; use crate::proxy; /// Minecraft RCON quirk. /// /// Wait this time between RCON operations. /// The Minecraft RCON implementation is very broken and brittle, this is used in the hopes to /// improve reliability. const QUIRK_RCON_GRACE_TIME: Duration = Duration::from_millis(200); /// An RCON client. pub struct Rcon { con: Connection, } impl Rcon { /// Connect to a host. pub async fn connect( config: &Config, addr: &str, pass: &str, ) -> Result> { // Connect to our TCP stream let mut stream = TcpStream::connect(addr).await?; // Add proxy header if config.rcon.send_proxy_v2 { trace!(target: "lazymc::rcon", "Sending local proxy header for RCON connection"); stream.write_all(&proxy::local_proxy_header()?).await?; } // Start connection let con = Connection::builder() .enable_minecraft_quirks(true) .connect_stream(stream, pass) .await?; Ok(Self { con }) } /// Connect to a host from the given configuration. pub async fn connect_config(config: &Config) -> Result> { // RCON address let mut addr = config.server.address; addr.set_port(config.rcon.port); let addr = addr.to_string(); Self::connect(config, &addr, &config.rcon.password).await } /// Send command over RCON. pub async fn cmd(&mut self, cmd: &str) -> Result { // Minecraft quirk time::sleep(QUIRK_RCON_GRACE_TIME).await; // Actually send RCON command debug!(target: "lazymc::rcon", "Sending RCON: {}", cmd); self.con.cmd(cmd).await } /// Close connection. pub async fn close(self) { // Minecraft quirk time::sleep(QUIRK_RCON_GRACE_TIME).await; } }