From ce30a8732c21a1c936ac560b5c94576df2e26b22 Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 12 Jul 2026 22:06:54 +0200 Subject: remove unused code, also, third stable --- src/docker.rs | 39 ++------------------------------------- src/models/mod.rs | 13 ------------- src/rcon.rs | 8 +------- src/routes/backups.rs | 2 -- src/routes/instances.rs | 36 ++++++++++++++++++++++++++++-------- src/routes/players.rs | 2 -- 6 files changed, 31 insertions(+), 69 deletions(-) (limited to 'src') diff --git a/src/docker.rs b/src/docker.rs index b18bb47..6b8640a 100644 --- a/src/docker.rs +++ b/src/docker.rs @@ -1,7 +1,7 @@ use bollard::Docker; use bollard::container::{ - Config as ContainerConfig, CreateContainerOptions, ListContainersOptions, - RemoveContainerOptions, StartContainerOptions, StopContainerOptions, + Config as ContainerConfig, CreateContainerOptions, RemoveContainerOptions, + StartContainerOptions, StopContainerOptions, }; use bollard::image::CreateImageOptions; use bollard::models::HostConfig; @@ -17,47 +17,12 @@ pub struct DockerManager { config: Config, } -#[derive(Debug, Clone)] -pub enum ContainerStatus { - Running, - Stopped, - Starting, - NotFound, - Error(String), -} - impl DockerManager { pub fn new(config: Config) -> Result { let client = Docker::connect_with_local_defaults()?; Ok(Self { client, config }) } - pub async fn container_status(&self) -> ContainerStatus { - let mut filters = HashMap::new(); - filters.insert("name".to_string(), vec!["mc".to_string()]); - - let options = ListContainersOptions { - all: true, - filters, - ..Default::default() - }; - - match self.client.list_containers(Some(options)).await { - Ok(containers) => { - if containers.is_empty() { - ContainerStatus::NotFound - } else { - match containers[0].state.as_deref() { - Some("running") => ContainerStatus::Running, - Some("exited") | Some("stopped") => ContainerStatus::Stopped, - _ => ContainerStatus::Starting, - } - } - } - Err(e) => ContainerStatus::Error(e.to_string()), - } - } - pub async fn start_container(&self, instance: &Instance) -> Result<(), String> { tracing::info!("Pulling itzg/minecraft-server:latest image..."); self.pull_image().await?; diff --git a/src/models/mod.rs b/src/models/mod.rs index c847ea3..0b083ff 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -29,16 +29,3 @@ pub struct Instance { pub created_at: String, pub updated_at: String, } - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Backup { - pub id: i64, - pub instance_id: i64, - pub filename: String, - pub created_at: String, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PlayerEntry { - pub username: String, -} diff --git a/src/rcon.rs b/src/rcon.rs index b91fe9b..eb3b72a 100644 --- a/src/rcon.rs +++ b/src/rcon.rs @@ -112,22 +112,16 @@ impl RconClient { .map_err(|e| RconError::Response(format!("Failed to read payload: {e}")))?; let request_id = i32::from_le_bytes([payload[0], payload[1], payload[2], payload[3]]); - let packet_type = i32::from_le_bytes([payload[4], payload[5], payload[6], payload[7]]); let body_bytes = &payload[8..payload.len() - 2]; let body = String::from_utf8_lossy(body_bytes).to_string(); - Ok(RconPacket { - request_id, - packet_type, - body, - }) + Ok(RconPacket { request_id, body }) } } #[derive(Debug)] struct RconPacket { request_id: i32, - packet_type: i32, body: String, } diff --git a/src/routes/backups.rs b/src/routes/backups.rs index 6b4dd49..6f7617e 100644 --- a/src/routes/backups.rs +++ b/src/routes/backups.rs @@ -22,7 +22,6 @@ struct BackupListTemplate { instance_name: String, instance_id: i64, backups: Vec, - message: Option, } struct BackupRow { @@ -78,7 +77,6 @@ async fn list_backups( instance_name, instance_id, backups, - message: None, }; Ok(Html(template.render().unwrap_or_default())) diff --git a/src/routes/instances.rs b/src/routes/instances.rs index e4f62f0..8dd6a62 100644 --- a/src/routes/instances.rs +++ b/src/routes/instances.rs @@ -19,7 +19,6 @@ struct InstanceListTemplate { is_superuser: bool, password_change_required: bool, instances: Vec, - has_active: bool, } #[derive(Template)] @@ -42,7 +41,6 @@ struct EditInstanceTemplate { instance: Instance, current_seed: Option, max_memory_mb: u32, - error: Option, } struct InstanceInfo { @@ -119,7 +117,6 @@ async fn list_instances( .filter_map(|r| r.ok()) .collect(); - let has_active = instances.iter().any(|i| i.is_active); drop(stmt); drop(conn); @@ -128,7 +125,6 @@ async fn list_instances( is_superuser: account.is_superuser, password_change_required: account.password_change_required, instances, - has_active, }; Ok(Html(template.render().unwrap_or_default())) @@ -283,7 +279,6 @@ async fn edit_form( instance, current_seed, max_memory_mb: state.config.max_memory_mb, - error: None, }; Ok(Html(template.render().unwrap_or_default())) @@ -428,6 +423,7 @@ async fn activate_instance( // Pull image + start container in background so the UI stays responsive let docker = state.docker.clone(); let db = state.db.clone(); + let rcon_pw = instance.rcon_password.clone(); tokio::spawn(async move { { let conn = db.conn(); @@ -439,9 +435,33 @@ async fn activate_instance( } match docker.start_container(&instance).await { Ok(()) => { + { + let conn = db.conn(); + conn.execute( + "UPDATE instances SET container_state = 'booting' WHERE is_active = 1", + [], + ) + .ok(); + } + // Wait for Minecraft to be ready via RCON + let rcon = crate::rcon::RconClient::new(rcon_pw); + for _ in 0..30 { + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + if rcon.send_command_async("list".into()).await.is_ok() { + let conn = db.conn(); + conn.execute( + "UPDATE instances SET container_state = 'running' WHERE is_active = 1", + [], + ) + .ok(); + tracing::info!("Server is ready (RCON responded)"); + return; + } + } + tracing::error!("Server did not become ready within 60 seconds"); let conn = db.conn(); conn.execute( - "UPDATE instances SET container_state = 'running' WHERE is_active = 1", + "UPDATE instances SET container_state = 'error' WHERE is_active = 1", [], ) .ok(); @@ -458,7 +478,7 @@ async fn activate_instance( } }); - Ok(Redirect::to("/")) + Ok(Redirect::to("/instances")) } async fn deactivate_instance( @@ -475,7 +495,7 @@ async fn deactivate_instance( .ok(); drop(conn); - Ok(Redirect::to("/")) + Ok(Redirect::to("/instances")) } fn generate_rcon_password() -> String { diff --git a/src/routes/players.rs b/src/routes/players.rs index b98a39d..5c90efb 100644 --- a/src/routes/players.rs +++ b/src/routes/players.rs @@ -20,7 +20,6 @@ struct PlayerManagementTemplate { whitelist: Vec, ops: Vec, bans: Vec, - message: Option, } #[derive(Debug, Deserialize)] @@ -70,7 +69,6 @@ async fn manage_players( whitelist, ops, bans, - message: None, }; Ok(Html(template.render().unwrap_or_default())) -- cgit v1.2.3