diff options
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 99 |
1 files changed, 97 insertions, 2 deletions
diff --git a/src/main.rs b/src/main.rs index e7a11a9..a96b41b 100644 --- a/src/main.rs +++ b/src/main.rs | |||
| @@ -1,3 +1,98 @@ | |||
| 1 | fn main() { | 1 | mod auth; |
| 2 | println!("Hello, world!"); | 2 | mod config; |
| 3 | mod db; | ||
| 4 | mod docker; | ||
| 5 | mod models; | ||
| 6 | mod rcon; | ||
| 7 | mod routes; | ||
| 8 | |||
| 9 | use tracing_subscriber::EnvFilter; | ||
| 10 | |||
| 11 | use crate::db::Database; | ||
| 12 | use crate::docker::DockerManager; | ||
| 13 | use crate::routes::AppState; | ||
| 14 | |||
| 15 | #[tokio::main] | ||
| 16 | async fn main() { | ||
| 17 | tracing_subscriber::fmt() | ||
| 18 | .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into())) | ||
| 19 | .init(); | ||
| 20 | |||
| 21 | let config = config::Config::load().unwrap_or_else(|e| { | ||
| 22 | eprintln!("Configuration error: {e}"); | ||
| 23 | eprintln!("Please create a config.toml file based on the example."); | ||
| 24 | std::process::exit(1); | ||
| 25 | }); | ||
| 26 | |||
| 27 | if !config.server_directory.exists() { | ||
| 28 | eprintln!( | ||
| 29 | "Server directory does not exist: {}", | ||
| 30 | config.server_directory.display() | ||
| 31 | ); | ||
| 32 | eprintln!("Please create it or update config.toml."); | ||
| 33 | std::process::exit(1); | ||
| 34 | } | ||
| 35 | |||
| 36 | let db_path = config.server_directory.join("mcui.db"); | ||
| 37 | let db = Database::open(&db_path).unwrap_or_else(|e| { | ||
| 38 | eprintln!("Failed to open database: {e}"); | ||
| 39 | std::process::exit(1); | ||
| 40 | }); | ||
| 41 | |||
| 42 | bootstrap_superuser(&db, &config); | ||
| 43 | |||
| 44 | let docker = DockerManager::new(config.clone()).unwrap_or_else(|e| { | ||
| 45 | eprintln!("Failed to connect to Docker: {e}"); | ||
| 46 | eprintln!("Is the Docker daemon running and accessible?"); | ||
| 47 | std::process::exit(1); | ||
| 48 | }); | ||
| 49 | |||
| 50 | let state = AppState { | ||
| 51 | config: config.clone(), | ||
| 52 | db: db.clone(), | ||
| 53 | docker, | ||
| 54 | }; | ||
| 55 | |||
| 56 | let router = routes::build_router(state); | ||
| 57 | |||
| 58 | let addr = format!("127.0.0.1:{}", config.webui_port); | ||
| 59 | tracing::info!("Starting Minecraft UI on http://{addr}"); | ||
| 60 | |||
| 61 | let listener = tokio::net::TcpListener::bind(&addr) | ||
| 62 | .await | ||
| 63 | .unwrap_or_else(|e| { | ||
| 64 | eprintln!("Failed to bind to {addr}: {e}"); | ||
| 65 | std::process::exit(1); | ||
| 66 | }); | ||
| 67 | |||
| 68 | axum::serve(listener, router).await.unwrap_or_else(|e| { | ||
| 69 | eprintln!("Server error: {e}"); | ||
| 70 | }); | ||
| 71 | } | ||
| 72 | |||
| 73 | fn bootstrap_superuser(db: &Database, config: &config::Config) { | ||
| 74 | let conn = db.conn(); | ||
| 75 | let count: i32 = conn | ||
| 76 | .query_row("SELECT COUNT(*) FROM accounts", [], |row| row.get(0)) | ||
| 77 | .unwrap_or(0); | ||
| 78 | drop(conn); | ||
| 79 | |||
| 80 | if count == 0 { | ||
| 81 | let hash = auth::hash_password(&config.initial_superuser_password) | ||
| 82 | .expect("Failed to hash initial password"); | ||
| 83 | |||
| 84 | let conn = db.conn(); | ||
| 85 | conn.execute( | ||
| 86 | "INSERT INTO accounts (username, password, is_superuser, password_change_required) | ||
| 87 | VALUES (?1, ?2, 1, 1)", | ||
| 88 | rusqlite::params![config.initial_superuser, hash], | ||
| 89 | ) | ||
| 90 | .expect("Failed to create initial superuser"); | ||
| 91 | drop(conn); | ||
| 92 | |||
| 93 | tracing::info!( | ||
| 94 | "Created initial superuser '{}' (password change required on first login)", | ||
| 95 | config.initial_superuser | ||
| 96 | ); | ||
| 97 | } | ||
| 3 | } | 98 | } |
