diff --git a/.gitignore b/.gitignore index ea8c4bf..c46d3d6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +server.toml \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 9e158fe..24ef358 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -325,8 +325,10 @@ version = "0.1.0" dependencies = [ "rust_mc_proto", "serde", + "serde_default", "serde_json", "serde_with", + "toml", ] [[package]] @@ -350,6 +352,18 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_default" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "486b028b311aaaea83e0ba65a3e6e3cbef381e74e9d0bd6263faefd1fb503c1d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde_derive" version = "1.0.219" @@ -373,6 +387,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + [[package]] name = "serde_with" version = "3.12.0" @@ -457,6 +480,47 @@ dependencies = [ "time-core", ] +[[package]] +name = "toml" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +dependencies = [ + "indexmap 2.9.0", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -585,3 +649,12 @@ checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" dependencies = [ "windows-link", ] + +[[package]] +name = "winnow" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e27d6ad3dac991091e4d35de9ba2d2d00647c5d0fc26c5496dee55984ae111b" +dependencies = [ + "memchr", +] diff --git a/Cargo.toml b/Cargo.toml index 16f3fdb..23348d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,8 @@ edition = "2024" [dependencies] rust_mc_proto = "0.1.19" -serde = { version = "1.0.219", features = ["derive"] } # used in text component +serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" -serde_with = { version = "3.12.0", features = ["macros"] } \ No newline at end of file +serde_with = { version = "3.12.0", features = ["macros"] } +serde_default = "0.2.0" +toml = "0.8.22" diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..404fd73 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,31 @@ +use std::{fs, path::PathBuf}; + +use serde::{Deserialize, Serialize}; +use serde_default::DefaultFromSerde; + + +#[derive(Debug, DefaultFromSerde, Serialize, Deserialize, Clone)] +pub struct ServerConfig { + /// Хост где забиндить сервер + #[serde(default = "default_host")] pub host: String, + + /// Таймаут подключения в секундах + #[serde(default = "default_timeout")] pub timeout: u64, +} + +fn default_host() -> String { return "127.0.0.1:25565".to_string(); } +fn default_timeout() -> u64 { return 5; } + +impl ServerConfig { + pub fn load_from_file(path: PathBuf) -> Option { + if !fs::exists(&path).unwrap_or_default() { + let table = ServerConfig::default(); + fs::create_dir_all(&path.parent()?).ok()?; + fs::write(&path, toml::to_string_pretty(&table).ok()?).ok()?; + return Some(table); + } + let content = fs::read_to_string(&path).ok()?; + let table = toml::from_str::(&content).ok()?; + Some(table) + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 2a1c6ad..75c9869 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,36 +1,64 @@ -use std::{io::{Read, Write}, net::TcpListener, thread, time::Duration}; +use std::{env::args, io::{Read, Write}, net::TcpListener, path::PathBuf, sync::Arc, thread, time::Duration}; +use config::ServerConfig; use rust_mc_proto::{DataReader, DataWriter, MinecraftConnection, Packet}; use data::{ServerError, TextComponent}; use pohuy::Pohuy; -pub mod pohuy; +pub mod config; pub mod data; - -// Сделать настройку хоста через конфиг -pub const HOST: &str = "127.0.0.1:25565"; +pub mod pohuy; fn main() { - let Ok(server) = TcpListener::bind(HOST) else { - println!("Не удалось забиндить сервер на {}", HOST); + // Получение аргументов + let exec = args().next().expect("Неизвестная система"); + let args = args().skip(1).collect::>(); + + if args.len() > 1 { + println!("Использование: {exec} [путь до файла конфигурации]"); + return; + } + + // Берем путь из аргумента либо по дефолту берем "./server.toml" + let config_path = PathBuf::from(args.get(0).unwrap_or(&"server.toml".to_string())); + + // Чтение конфига, если ошибка - выводим + let config = match ServerConfig::load_from_file(config_path) { + Some(config) => config, + None => { + println!("Ошибка чтения конфигурации"); + return; + }, + }; + + // Делаем немутабельную потокобезопасную ссылку на конфиг + // Впринципе можно и просто клонировать сам конфиг в каждый сука поток ебать того рот ебать блять + // но мы этого делать не будем чтобы не было мемори лик лишнего + let config = Arc::new(config); + + // Биндим сервер где надо + let Ok(server) = TcpListener::bind(&config.host) else { + println!("Не удалось забиндить сервер на {}", &config.host); return; }; - println!("Сервер запущен на {}", HOST); + println!("Сервер запущен на {}", &config.host); while let Ok((stream, addr)) = server.accept() { + let config = config.clone(); + thread::spawn(move || { println!("Подключение: {}", addr); // Установка таймаутов на чтение и запись // По умолчанию пусть будет 5 секунд, надо будет сделать настройку через конфиг - stream.set_read_timeout(Some(Duration::from_secs(5))).pohuy(); - stream.set_write_timeout(Some(Duration::from_secs(5))).pohuy(); + stream.set_read_timeout(Some(Duration::from_secs(config.timeout))).pohuy(); + stream.set_write_timeout(Some(Duration::from_secs(config.timeout))).pohuy(); // Обработка подключения // Если ошибка -> выводим - match handle_connection(MinecraftConnection::new(&stream)) { + match handle_connection(config, MinecraftConnection::new(&stream)) { Ok(_) => {}, Err(error) => { println!("Ошибка подключения: {error:?}"); @@ -43,6 +71,7 @@ fn main() { } fn handle_connection( + _: Arc, // Конфиг сервера (возможно будет использоаться в будущем) mut conn: MinecraftConnection // Подключение ) -> Result<(), ServerError> { // Чтение рукопожатия