From 3253b4bcde97472007aaf4048e4e190551b22662 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: Thu, 11 Dec 2025 22:19:22 +0000 Subject: [PATCH] application-server logs save in "futriix.log" now --- src/main.rs | 278 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 src/main.rs diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..50d3cf3 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,278 @@ +// src/main.rs +//! Главный модуль сервера Futriix +//! +//! Точка входа в приложение, инициализирует сервер и запускает его. +//! Использует wait-free архитектуру с lock-free структурами данных. +//! +//! Особенности: +//! - Логирование в файл с временными метками и миллисекундами +//! - Парсинг аргументов командной строки +//! - Цветной вывод с поддержкой ANSI кодов +//! - Инициализация и запуск сервера +//! - Обработка ошибок и graceful shutdown + +mod common; // Модуль общих утилит и типов ошибок +mod server; // Основной модуль сервера +mod lua_shell; // Интерактивная Lua оболочка + +use std::env; // Работа с переменными окружения +use std::fs::OpenOptions; // Открытие файлов с различными опциями +use std::io::Write; // Запись в файлы + +use crate::common::FutriixError; // Основной тип ошибки системы + +/// Функция для логирования в файл +/// Записывает сообщения в файл futriix.log с временными метками +/// Используется для отладки и аудита работы сервера +/// +/// # Аргументы +/// * `message` - Сообщение для записи в лог +/// +/// # Пример использования +/// ```rust +/// log_to_file("Сервер запускается"); +/// ``` +fn log_to_file(message: &str) { + // Открываем файл лога с опциями: создавать если не существует, дописывать в конец + match OpenOptions::new() + .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()); + } + Err(e) => eprintln!("Failed to write to log file: {}", e), + } +} + +/// Структура для хранения аргументов командной строки +/// Содержит параметры конфигурации и флаги отладки +/// +/// # Поля +/// * `config` - Путь к файлу конфигурации +/// * `debug` - Флаг режима отладки +/// * `http_port` - Порт HTTP сервера (опционально) +/// * `https_port` - Порт HTTPS сервера (опционально) +/// * `host` - Хост для привязки сервера (опционально) +struct Args { + config: String, // Путь к файлу конфигурации + debug: bool, // Флаг режима отладки + http_port: Option, // Порт HTTP сервера (опционально) + https_port: Option,// Порт HTTPS сервера (опционально) + host: Option, // Хост для привязки сервера (опционально) +} + +/// Парсер аргументов командной строки +/// Поддерживает короткие и длинные формы аргументов +/// Возвращает структуру Args с распарсенными значениями +/// +/// # Поддерживаемые аргументы +/// * `--config`, `-c` - Путь к файлу конфигурации +/// * `--debug`, `-d` - Включение режима отладки +/// * `--http-port` - Порт HTTP сервера +/// * `--https-port` - Порт HTTPS сервера +/// * `--host` - Хост для привязки сервера +/// +/// # Пример использования +/// ```bash +/// futriix --config my_config.toml --debug --http-port 8080 +/// ``` +fn parse_args() -> Args { + // Инициализируем структуру со значениями по умолчанию + let mut args = Args { + config: "config.toml".to_string(), // Конфигурация по умолчанию + debug: false, // Режим отладки выключен по умолчанию + http_port: None, // Порт HTTP не задан + https_port: None, // Порт HTTPS не задан + host: None, // Хост не задан + }; + + // Создаем итератор по аргументам командной строки, пропуская первый (имя программы) + let mut iter = env::args().skip(1); + + // Обрабатываем аргументы по одному + while let Some(arg) = iter.next() { + match arg.as_str() { + // Обработка аргумента конфигурации (длинная и короткая форма) + "--config" | "-c" => { + // Следующий аргумент - значение пути к конфигурации + if let Some(value) = iter.next() { + args.config = value; + } + } + // Включение режима отладки + "--debug" | "-d" => { + args.debug = true; + } + // Установка порта HTTP сервера + "--http-port" => { + if let Some(value) = iter.next() { + if let Ok(port) = value.parse() { + args.http_port = Some(port); + } + } + } + // Установка порта HTTPS сервера + "--https-port" => { + if let Some(value) = iter.next() { + if let Ok(port) = value.parse() { + args.https_port = Some(port); + } + } + } + // Установка хоста для привязки сервера + "--host" => { + if let Some(value) = iter.next() { + args.host = Some(value); + } + } + // Обработка аргументов в формате ключ=значение + _ => { + if arg.starts_with("--config=") { + // Формат: --config=путь/к/конфигурации.toml + args.config = arg.trim_start_matches("--config=").to_string(); + } else if arg.starts_with("-c=") { + // Формат: -c=путь/к/конфигурации.toml + args.config = arg.trim_start_matches("-c=").to_string(); + } + // Неизвестные аргументы игнорируются + } + } + } + + args +} + +/// Функция для вывода текста с ANSI цветом +/// Использует escape-последовательности для цветного форматирования +/// Параметр ansi_color должен содержать ANSI escape code +/// +/// # Аргументы +/// * `text` - Текст для вывода +/// * `ansi_color` - ANSI escape code для установки цвета +/// +/// # Пример использования +/// ```rust +/// print_colored("Hello World!", "\x1b[38;2;255;0;0m"); +/// ``` +fn print_colored(text: &str, ansi_color: &str) { + // Выводим цветной текст и сбрасываем цвет в конце + println!("{}{}\x1b[0m", ansi_color, text); +} + +/// Конвертация HEX цвета в ANSI escape code +/// Принимает строку в формате #RRGGBB или RRGGBB +/// Возвращает ANSI escape sequence для установки цвета текста +/// +/// # Аргументы +/// * `hex_color` - HEX цвет в формате #RRGGBB или RRGGBB +/// +/// # Возвращаемое значение +/// * `String` - ANSI escape sequence для установки цвета +/// +/// # Пример использования +/// ```rust +/// let ansi_color = hex_to_ansi("#00bfff"); // Голубой цвет +/// ``` +fn hex_to_ansi(hex_color: &str) -> String { + // Убираем символ # если он есть + let hex = hex_color.trim_start_matches('#'); + + // Проверяем, что строка имеет правильную длину (6 символов для RRGGBB) + if hex.len() == 6 { + // Парсим компоненты цвета: красный, зеленый, синий + if let (Ok(r), Ok(g), Ok(b)) = ( + u8::from_str_radix(&hex[0..2], 16), // Красный (первые 2 символа) + u8::from_str_radix(&hex[2..4], 16), // Зеленый (следующие 2 символа) + u8::from_str_radix(&hex[4..6], 16), // Синий (последние 2 символа) + ) { + // Формируем ANSI escape sequence для установки RGB цвета + return format!("\x1b[38;2;{};{};{}m", r, g, b); + } + } + + // В случае ошибки парсинга возвращаем белый цвет по умолчанию + "\x1b[38;2;255;255;255m".to_string() +} + +/// Точка входа в приложение Futriix +/// Инициализирует сервер, парсит аргументы командной строки и запускает систему +/// +/// # Возвращаемое значение +/// * `Result<(), FutriixError>` - Результат выполнения, содержащий ошибку если что-то пошло не так +/// +/// # Пример использования +/// ```bash +/// cargo run -- --config my_config.toml +/// ``` +#[tokio::main] +async fn main() -> Result<(), FutriixError> { + // Инициализация логирования в файл + // Записываем стартовое сообщение в лог + log_to_file("Starting Futriix server"); + + // Вывод приветственного сообщения с цветом #00bfff перед загрузкой конфигурации + // Используем голубой цвет для брендинга Futriix + let color_code = hex_to_ansi("#00bfff"); + + // Добавляем пустую строку для лучшей читаемости + println!(); + + // Выводим название сервера и версию цветным текстом + print_colored("Futriix Database Server", &color_code); + print_colored("futriix 3i²(by 26.11.2025)", &color_code); + + // Добавляем пустую строку после приветствия + println!(); + + // Парсим аргументы командной строки + let args = parse_args(); + let config_path = args.config; + + // Логируем и выводим информацию о загружаемой конфигурации + let message = format!("Loading configuration from: {}", config_path); + println!("{}", message); + log_to_file(&message); + + // Создание и запуск сервера с использованием async/await + 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); + + // Завершаем процесс с кодом ошибки 1 + std::process::exit(1); + } + } + Err(e) => { + // Обрабатываем ошибку создания сервера + let error_message = format!("Failed to create server: {}", e); + eprintln!("{}", error_message); + log_to_file(&error_message); + + // Завершаем процесс с кодом ошибки 1 + std::process::exit(1); + } + } + + // Логируем завершение работы сервера + log_to_file("Futriix server stopped"); + + // Успешное завершение программы + Ok(()) +}