// src/server/mod.rs //! Сервер Futriix - полностью lock-free документо-ориентированная БД //! //! Основной модуль сервера, который инициализирует все компоненты системы: //! - Базу данных с lock-free архитектурой //! - Lua движок для выполнения скриптов //! - Менеджер шардинга и репликации //! - HTTP/HTTPS серверы //! - CSV менеджер для импорта/экспорта данных //! //! Архитектурные особенности: //! - Все операции выполняются без блокировок (lock-free) //! - Используются атомарные структуры данных //! - Поддержка транзакций через Software Transactional Memory //! - Интеграция с Lua для кастомной логики #![allow(dead_code)] use std::sync::Arc; use std::fs::OpenOptions; use std::io::Write; use crate::common::Result; use crate::common::config::Config; use crate::lua_shell::LuaShell; // Импортируем подмодули pub mod database; pub mod lua_engine; pub mod http; pub mod sharding; pub mod csv_import_export; /// Функция для логирования в файл /// Используется для отладки и аудита работы сервера /// Все сообщения записываются в файл futriix.log с временными метками fn log_to_file(message: &str) { if let Ok(mut file) = OpenOptions::new() .create(true) .append(true) .open("futriix.log") { 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()); } } /// Функция для вывода текста с ANSI цветом /// Использует escape-последовательности для цветного форматирования вывода #[allow(dead_code)] fn print_colored(text: &str, ansi_color: &str) { println!("{}{}\x1b[0m", ansi_color, text); } /// Конвертация HEX цвета в ANSI escape code /// Поддерживает формат #RRGGBB для установки произвольных цветов fn hex_to_ansi(hex_color: &str) -> String { let hex = hex_color.trim_start_matches('#'); if hex.len() == 6 { if let (Ok(r), Ok(g), Ok(b)) = ( u8::from_str_radix(&hex[0..2], 16), u8::from_str_radix(&hex[2..4], 16), u8::from_str_radix(&hex[4..6], 16), ) { return format!("\x1b[38;2;{};{};{}m", r, g, b); } } // Цвет по умолчанию: белый "\x1b[38;2;255;255;255m".to_string() } /// Основный сервер Futriix с полностью lock-free архитектурой /// Координирует работу всех компонентов системы и предоставляет /// единую точку входа для управления базой данных pub struct FutriixServer { config: Config, // Конфигурация сервера database: Arc, // Lock-free база данных lua_engine: lua_engine::LuaEngine, // Встроенный Lua интерпретатор sharding_manager: Arc, // Менеджер шардинга и репликации http_enabled: bool, // Флаг включения HTTP сервера csv_manager: Arc, // Менеджер CSV операций } impl FutriixServer { /// Создание нового сервера с lock-free архитектурой /// Инициализирует все компоненты системы на основе конфигурации pub async fn new(config_path: &str) -> Result { // Загрузка конфигурации из файла TOML let config = Config::load(config_path)?; // Инициализация компонентов с lock-free подходами let database = Arc::new(database::Database::new()); let lua_engine = lua_engine::LuaEngine::new()?; // Генерируем уникальный ID для текущего узла let node_id = format!("node_{}", uuid::Uuid::new_v4().to_string()[..8].to_string()); // Инициализация менеджера шардинга и репликации let sharding_manager = Arc::new(sharding::ShardingManager::new( config.sharding.virtual_nodes_per_node, config.replication.enabled, config.sharding.min_nodes_for_cluster, node_id, )); // Инициализация менеджера CSV let csv_manager = Arc::new(csv_import_export::CsvManager::new( database.clone(), config.csv.clone(), )); // Регистрация функций БД в Lua движке // Это позволяет выполнять Lua скрипты с доступом к базе данных lua_engine.register_db_functions(database.clone(), sharding_manager.clone())?; // Инициализация базы данных (создание системных коллекций и директорий) FutriixServer::initialize_database(database.clone())?; // Проверяем, включен ли HTTP режим в конфигурации let http_enabled = (config.server.http_port.is_some() && config.server.http) || (config.server.https_port.is_some() && config.server.https); Ok(Self { config, database, lua_engine, sharding_manager, http_enabled, csv_manager, }) } /// Инициализация базы данных с lock-free структурами /// Создает системные коллекции, директории для бэкапов и статических файлов fn initialize_database(db: Arc) -> Result<()> { // Создаем системные коллекции с lock-free доступом // Эти коллекции используются для внутренних нужд системы let _system_collection = db.get_collection("_system"); let _users_collection = db.get_collection("_users"); let _logs_collection = db.get_collection("_logs"); let _procedures_collection = db.get_collection("_procedures"); let _triggers_collection = db.get_collection("_triggers"); let _csv_imports_collection = db.get_collection("_csv_imports"); // Создаем директорию для бэкапов, если она не существует let backup_dir = "./futriix_backups"; if let Err(e) = std::fs::create_dir_all(backup_dir) { log_to_file(&format!("Warning: Failed to create backup directory '{}': {}", backup_dir, e)); } else { log_to_file(&format!("Backup directory created at: {}", backup_dir)); } // Создаем директорию для CSV файлов let csv_dir = "./futriix_csv"; if let Err(e) = std::fs::create_dir_all(csv_dir) { log_to_file(&format!("Warning: Failed to create CSV directory '{}': {}", csv_dir, e)); } else { log_to_file(&format!("CSV directory created at: {}", csv_dir)); } // Создаем поддиректории для CSV импорта и экспорта let import_dir = "./futriix_csv/import"; let export_dir = "./futriix_csv/export"; let _ = std::fs::create_dir_all(import_dir); let _ = std::fs::create_dir_all(export_dir); // Создаем директорию для статических файлов веб-интерфейса let static_dir = "static"; if let Err(e) = std::fs::create_dir_all(static_dir) { log_to_file(&format!("Warning: Failed to create static files directory '{}': {}", static_dir, e)); } else { log_to_file(&format!("Static files directory created at: {}", static_dir)); } // ИЗМЕНЕНИЕ: Создаем простой default.html для тестирования вместо index.html // Используем default.html как точку входа для веб-интерфейса Futriix let default_html_content = r#" Futriix Database Server
v1.0.0 • futriix 3i²
🚀
Server Status
Online
Ready to accept connections
🗄️
Database
Active
Lock-free architecture
⚙️
Lua Engine
Running
Script execution enabled
💾
Storage
Ready
CSV import/export available
System Information
Server Version
Futriix 1.0.0
Architecture
Wait-Free / Lock-Free
Protocol Support
HTTP/1.1, HTTP/2, HTTPS
Default Ports
HTTP: 9090, HTTPS: 8443
📊
Real-time Analytics
🔒
Atomic Transactions
🚀
High Performance
📝
Lua Scripting
🔄
Auto-Sharding
💾
CSV Import/Export
Server Time
Loading...

© 2025 Futriix Database Server. All rights reserved.

Built with Rust • Lock-Free Architecture • Enterprise Ready

"#; // ИЗМЕНЕНИЕ: Сохраняем как default.html вместо index.html // Это обеспечивает лучшую совместимость и избегает конфликтов с другими системами if let Err(e) = std::fs::write("static/default.html", default_html_content) { log_to_file(&format!("Warning: Failed to create default.html: {}", e)); } else { log_to_file("Created enhanced default.html in static directory"); log_to_file("Web interface will be available at: http://localhost:9090/default.html"); } let message = "Database initialized with system collections"; log_to_file(message); Ok(()) } /// Запуск сервера с lock-free архитектурой /// Координирует запуск HTTP серверов и интерактивной оболочки pub async fn run(&self) -> Result<()> { // Определяем режим работы и имя кластера let cluster_name = &self.config.cluster.name; log_to_file(&format!("Run: cluster (cluster: '{}')", cluster_name)); log_to_file("Futriix Database Server started"); log_to_file(&format!("Run: cluster (cluster: '{}')", cluster_name)); // Сначала запускаем HTTP серверы и ждем их запуска if self.http_enabled { self.start_http_servers().await?; } else { log_to_file("HTTP/HTTPS servers disabled in configuration"); } // Добавляем пустую строку после информации о серверах println!(); let mut lua_shell = LuaShell::new( self.lua_engine.clone(), self.database.clone(), self.sharding_manager.clone(), self.csv_manager.clone(), ); // Запуск интерактивной оболочки lua_shell.run().await?; Ok(()) } /// Запуск HTTP/HTTPS серверов с ожиданием их готовности /// Создает отдельные задачи для каждого сервера и управляет их жизненным циклом async fn start_http_servers(&self) -> Result<()> { let static_config = self::http::StaticFilesConfig::default(); let acl_config = self::http::AclConfig { enabled: self.config.acl.enabled, allowed_ips: self.config.acl.allowed_ips.clone(), denied_ips: self.config.acl.denied_ips.clone(), }; let mut http_server_handles = Vec::new(); // Запуск HTTP сервера, если настроен и включен if let Some(http_port) = self.config.server.http_port { if self.config.server.http { let http_addr = format!("{}:{}", self.config.server.host, http_port); let http_config = self::http::HttpConfig { enabled: true, port: http_port, http2_enabled: self.config.server.http2_enabled.unwrap_or(false), }; let db_clone = self.database.clone(); let static_config_clone = static_config.clone(); let acl_config_clone = acl_config.clone(); log_to_file(&format!("Starting HTTP server on {}", http_addr)); // Запускаем в фоновой задаче let handle = tokio::spawn(async move { match self::http::start_http_server(&http_addr, db_clone, static_config_clone, http_config, acl_config_clone).await { Ok(_) => { let message = format!("HTTP server started on {}", http_addr); log_to_file(&message); } Err(e) => { let message = format!("Failed to start HTTP server: {}", e); log_to_file(&message); } } }); http_server_handles.push(handle); } else { log_to_file("HTTP server disabled in configuration"); } } // Запуск HTTPS сервера, если настроен и включен if let Some(https_port) = self.config.server.https_port { if self.config.server.https && self.config.tls.enabled { let https_addr = format!("{}:{}", self.config.server.host, https_port); let tls_config = self::http::TlsConfig { enabled: self.config.tls.enabled, cert_path: self.config.tls.cert_path.clone(), key_path: self.config.tls.key_path.clone(), }; let db_clone = self.database.clone(); let static_config_clone = static_config.clone(); let acl_config_clone = acl_config.clone(); log_to_file(&format!("Starting HTTPS server on {}", https_addr)); let handle = tokio::spawn(async move { match self::http::start_https_server(&https_addr, db_clone, static_config_clone, tls_config, acl_config_clone).await { Ok(_) => { let message = format!("HTTPS server started on {}", https_addr); log_to_file(&message); } Err(e) => { let message = format!("Failed to start HTTPS server: {}", e); log_to_file(&message); } } }); http_server_handles.push(handle); } else { if !self.config.tls.enabled { log_to_file("HTTPS disabled: TLS not enabled in configuration"); } else { log_to_file("HTTPS server disabled in configuration"); } } } // Ждем небольшое время, чтобы серверы успели стартовать if !http_server_handles.is_empty() { log_to_file("Waiting for HTTP servers to start..."); tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; } Ok(()) } /// Получение менеджера шардинга для внешнего использования #[allow(dead_code)] pub fn get_sharding_manager(&self) -> Arc { self.sharding_manager.clone() } /// Получение менеджера CSV для внешнего использования #[allow(dead_code)] pub fn get_csv_manager(&self) -> Arc { self.csv_manager.clone() } /// Получение базы данных для внешнего использования #[allow(dead_code)] pub fn get_database(&self) -> Arc { self.database.clone() } /// Получение Lua движка для внешнего использования #[allow(dead_code)] pub fn get_lua_engine(&self) -> lua_engine::LuaEngine { self.lua_engine.clone() } }