From 3b95f15566dd75d0951657bb15584d0aa918fdc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=A1?= =?UTF-8?q?=D0=B0=D1=84=D1=80=D0=BE=D0=BD=D0=BE=D0=B2?= Date: Tue, 20 Jan 2026 21:42:46 +0000 Subject: [PATCH] Added blue-color in all Unix-like terminals --- src/main.rs | 224 ++++++++++------------------------------------------ 1 file changed, 40 insertions(+), 184 deletions(-) diff --git a/src/main.rs b/src/main.rs index f745259..958739a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,16 @@ //! //! Точка входа в приложение, инициализирует сервер и запускает его. //! Использует wait-free архитектуру с lock-free структурами данных. +//! +//! Основные функции: +//! 1. Парсинг аргументов командной строки +//! 2. Загрузка конфигурации из файла +//! 3. Инициализация и запуск сервера +//! 4. Логирование в файл и консоль +//! 5. Обработка сигналов завершения работы +//! +//! Примечание: Этот файл является альтернативной версией main.rs +//! для специфичных сценариев развертывания. mod common; mod server; @@ -15,14 +25,15 @@ use std::io::Write; use crate::common::FutriixError; /// Функция для логирования в файл +/// Записывает сообщения в файл futriix.log с временными метками fn log_to_file(message: &str) { match OpenOptions::new() - .create(true) - .append(true) + .create(true) // Создаем файл если не существует + .append(true) // Добавляем в конец файла .open("futriix.log") { Ok(mut file) => { - // ИСПРАВЛЕНИЕ: Используем системное время с миллисекундами + // Используем системное время с миллисекундами let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f").to_string(); let log_message = format!("[{}] {}\n", timestamp, message); let _ = file.write_all(log_message.as_bytes()); @@ -32,25 +43,28 @@ fn log_to_file(message: &str) { } /// Простая структура для аргументов командной строки +/// Хранит параметры конфигурации сервера struct Args { - config: String, - debug: bool, - http_port: Option, - https_port: Option, - host: Option, + config: String, // Путь к файлу конфигурации + debug: bool, // Режим отладки + http_port: Option, // Порт HTTP сервера (опционально) + https_port: Option, // Порт HTTPS сервера (опционально) + host: Option, // Хост для привязки (опционально) } /// Простой парсер аргументов командной строки +/// Обрабатывает параметры запуска сервера fn parse_args() -> Args { let mut args = Args { - config: "config.toml".to_string(), + config: "config.toml".to_string(), // Значение по умолчанию debug: false, http_port: None, https_port: None, host: None, }; - let mut iter = env::args().skip(1); + let mut iter = env::args().skip(1); // Пропускаем имя программы + while let Some(arg) = iter.next() { match arg.as_str() { "--config" | "-c" => { @@ -81,6 +95,7 @@ fn parse_args() -> Args { } } _ => { + // Обработка аргументов в формате --key=value if arg.starts_with("--config=") { args.config = arg.trim_start_matches("--config=").to_string(); } else if arg.starts_with("-c=") { @@ -94,17 +109,13 @@ fn parse_args() -> Args { } /// Функция для вывода текста с ANSI цветом +/// Используется для цветного вывода в консоль fn print_colored(text: &str, ansi_color: &str) { println!("{}{}\x1b[0m", ansi_color, text); } -/// Функция для вывода текста с цветом #00bfff для проекта futriix -fn print_futriix(text: &str) { - let futriix_color = "\x1b[38;2;0;191;255m"; // ANSI код для #00bfff - println!("{}{}\x1b[0m", futriix_color, text); -} - /// Конвертация HEX цвета в ANSI escape code +/// Преобразует цвет в формате #RRGGBB в ANSI escape последовательность fn hex_to_ansi(hex_color: &str) -> String { let hex = hex_color.trim_start_matches('#'); @@ -118,170 +129,22 @@ fn hex_to_ansi(hex_color: &str) -> String { } } + // Цвет по умолчанию: белый "\x1b[38;2;255;255;255m".to_string() } -/// Функция для получения цвета #00bfff как строки ANSI кода для проекта futriix -fn get_futriix_color() -> String { - "\x1b[38;2;0;191;255m".to_string() -} - -/// Структура для хранения информации о дистрибутиве Linux -#[derive(Debug)] -struct LinuxDistribution { - name: String, - version: String, - pretty_name: String, -} - -impl LinuxDistribution { - /// Создает строку с полным именем дистрибутива и версией - fn full_name(&self) -> String { - if !self.version.is_empty() { - format!("{} {}", self.name, self.version) - } else { - self.name.clone() - } - } -} - -/// Получение информации о дистрибутиве Linux -/// Читает информацию из файлов /etc/os-release или /etc/lsb-release -fn get_linux_distribution() -> LinuxDistribution { - // Инициализируем структуру значениями по умолчанию - let mut distro = LinuxDistribution { - name: "Linux".to_string(), - version: String::new(), - pretty_name: "Linux".to_string(), - }; - - // Попробуем прочитать /etc/os-release (современные дистрибутивы) - if let Ok(content) = std::fs::read_to_string("/etc/os-release") { - for line in content.lines() { - if line.starts_with("PRETTY_NAME=") { - // Убираем PRETTY_NAME= и кавычки - let name = line.trim_start_matches("PRETTY_NAME="); - distro.pretty_name = name.trim_matches('"').to_string(); - } else if line.starts_with("NAME=") { - let name = line.trim_start_matches("NAME="); - distro.name = name.trim_matches('"').to_string(); - } else if line.starts_with("VERSION=") || line.starts_with("VERSION_ID=") { - // Предпочитаем VERSION_ID для номеров версий, но используем VERSION если есть - let version_line = if line.starts_with("VERSION_ID=") { - line.trim_start_matches("VERSION_ID=") - } else { - line.trim_start_matches("VERSION=") - }; - distro.version = version_line.trim_matches('"').to_string(); - } - } - - // Если нашли pretty_name, но не нашли отдельное имя - используем pretty_name - if distro.name == "Linux" && distro.pretty_name != "Linux" { - // Попробуем извлечь имя и версию из pretty_name - let pretty = &distro.pretty_name; - if let Some(pos) = pretty.find(char::is_numeric) { - distro.name = pretty[..pos].trim().to_string(); - distro.version = pretty[pos..].trim().to_string(); - } else { - distro.name = pretty.clone(); - } - } - } - - // Если не нашли версию в /etc/os-release, попробуем /etc/lsb-release - if distro.version.is_empty() { - if let Ok(content) = std::fs::read_to_string("/etc/lsb-release") { - for line in content.lines() { - if line.starts_with("DISTRIB_DESCRIPTION=") { - let name = line.trim_start_matches("DISTRIB_DESCRIPTION="); - distro.pretty_name = name.trim_matches('"').to_string(); - - // Попробуем извлечь версию из описания - let desc = &distro.pretty_name; - if let Some(pos) = desc.find(char::is_numeric) { - distro.name = desc[..pos].trim().to_string(); - distro.version = desc[pos..] - .chars() - .take_while(|c| c.is_numeric() || *c == '.') - .collect::(); - } - } else if line.starts_with("DISTRIB_ID=") && distro.name == "Linux" { - let name = line.trim_start_matches("DISTRIB_ID="); - distro.name = name.trim_matches('"').to_string(); - } else if line.starts_with("DISTRIB_RELEASE=") { - let version = line.trim_start_matches("DISTRIB_RELEASE="); - distro.version = version.trim_matches('"').to_string(); - } - } - } - } - - // Если все еще не нашли версию, попробуем прочитать /etc/issue - if distro.version.is_empty() { - if let Ok(content) = std::fs::read_to_string("/etc/issue") { - // Берем первую строку - if let Some(first_line) = content.lines().next() { - let line = first_line.trim(); - - // Ищем номер версии в строке - if let Some(pos) = line.find(char::is_numeric) { - distro.name = line[..pos].trim().to_string(); - // Извлекаем версию (первые цифры до пробела) - let version_part = &line[pos..]; - distro.version = version_part - .chars() - .take_while(|c| c.is_numeric() || *c == '.') - .collect::(); - } else { - distro.name = line.to_string(); - } - - // Если pretty_name еще не установлен, используем имя из issue - if distro.pretty_name == "Linux" { - distro.pretty_name = distro.name.clone(); - } - } - } - } - - // Для Arch Linux, которая не всегда показывает версию в os-release - if distro.name.to_lowercase().contains("arch") && distro.version.is_empty() { - // Архивные версии Arch Linux не имеют номеров версий, но можно проверить наличие файла pacman - if std::path::Path::new("/etc/pacman.conf").exists() { - distro.version = "Rolling Release".to_string(); - } - } - - // Убираем возможные дублирования имени в версии - if !distro.version.is_empty() && distro.version.starts_with(&distro.name) { - distro.version = distro.version.trim_start_matches(&distro.name).trim().to_string(); - } - - // Очищаем версию от нечисловых символов в конце - if !distro.version.is_empty() { - let cleaned_version: String = distro.version - .chars() - .take_while(|c| c.is_numeric() || *c == '.') - .collect(); - if !cleaned_version.is_empty() { - distro.version = cleaned_version; - } - } - - distro -} - +/// Основная функция - точка входа в приложение +/// Инициализирует и запускает сервер Futriix #[tokio::main] async fn main() -> Result<(), FutriixError> { // Инициализация логирования в файл log_to_file("Starting Futriix server"); - // Вывод приветственного сообщения с цветом #00bfff для проекта futriix - let futriix_color = get_futriix_color(); + // Вывод приветственного сообщения с цветом #00bfff перед загрузкой конфигурации + let color_code = hex_to_ansi("#00bfff"); println!(); // Добавляем пустую строку перед фразой - print_futriix("Futriix Database Server"); - print_futriix("futriix 3i²(by 26.11.2025)"); + print_colored("Futriix Database Server", &color_code); + print_colored("futriix 3i²(by 26.11.2025)", &color_code); println!(); // Добавляем пустую строку после фразы // Парсим аргументы командной строки @@ -289,37 +152,30 @@ async fn main() -> Result<(), FutriixError> { let config_path = args.config; let message = format!("Loading configuration from: {}", config_path); - print_futriix(&message); - - // Добавляем пустую строку после сообщения о загрузке конфигурации - println!(); - - // Выводим информацию о дистрибутиве Linux с версией - let distro = get_linux_distribution(); - print_futriix(&format!("Running on: {}", distro.full_name())); - + println!("{}", message); log_to_file(&message); - log_to_file(&format!("Linux distribution: {} {}", distro.name, distro.version)); // Создание и запуск сервера match server::FutriixServer::new(&config_path).await { Ok(server) => { log_to_file("Server created successfully"); + + // Запускаем основной цикл сервера if let Err(e) = server.run().await { let error_message = format!("Server error: {}", e); eprintln!("{}", error_message); log_to_file(&error_message); - std::process::exit(1); + std::process::exit(1); // Завершаем с ошибкой } } Err(e) => { let error_message = format!("Failed to create server: {}", e); eprintln!("{}", error_message); log_to_file(&error_message); - std::process::exit(1); + std::process::exit(1); // Завершаем с ошибкой } } log_to_file("Futriix server stopped"); Ok(()) -} +} \ No newline at end of file