From 54b95f0ee65294ac031c470d15caa899e4fb50df 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:21:57 +0000 Subject: [PATCH] Delete src/server/http.rs --- src/server/http.rs | 790 --------------------------------------------- 1 file changed, 790 deletions(-) delete mode 100644 src/server/http.rs diff --git a/src/server/http.rs b/src/server/http.rs deleted file mode 100644 index 0c243a3..0000000 --- a/src/server/http.rs +++ /dev/null @@ -1,790 +0,0 @@ -// src/server/http.rs -//! Lock-free HTTP/HTTPS сервер для Futriix Database -//! -//! Этот модуль реализует веб-интерфейс для базы данных с поддержкой: -//! - HTTP/1.1 и HTTP/2 протоколов -//! - TLS/HTTPS для безопасного соединения -//! - Обслуживание статических файлов (HTML, CSS, JS) -//! - REST API для доступа к данным -//! - Access Control Lists (ACL) для управления доступом -//! - Статистику запросов без блокировок -//! -//! Архитектурные особенности: -//! - Атомарные счетчики для статистики (без блокировок) -//! - Изолированная обработка каждого запроса -//! - Поддержка консистентного хэширования для распределенных систем -//! - Автоматическое определение Content-Type файлов - -#![allow(dead_code)] -#![allow(unused_variables)] - -use std::sync::Arc; -use hyper::{Body, Request, Response, Server, StatusCode}; -use hyper::service::{make_service_fn, service_fn}; -use tokio::fs::File; -use tokio::io::AsyncReadExt; -use dashmap::DashMap; -use std::sync::atomic::{AtomicU64, Ordering}; - -use crate::common::Result; -use crate::server::database::Database; - -/// Статистика запросов с атомарными счетчиками -/// Использует атомарные операции для подсчета метрик без блокировок -struct RequestStats { - total_requests: AtomicU64, // Общее количество запросов - successful_requests: AtomicU64, // Количество успешных запросов - failed_requests: AtomicU64, // Количество неудачных запросов - active_requests: AtomicU64, // Количество активных запросов -} - -impl RequestStats { - /// Создает новую статистику с нулевыми значениями - fn new() -> Self { - Self { - total_requests: AtomicU64::new(0), - successful_requests: AtomicU64::new(0), - failed_requests: AtomicU64::new(0), - active_requests: AtomicU64::new(0), - } - } - - /// Записывает начало обработки запроса - /// Увеличивает счетчики total_requests и active_requests - fn record_request_start(&self) { - self.total_requests.fetch_add(1, Ordering::SeqCst); - self.active_requests.fetch_add(1, Ordering::SeqCst); - } - - /// Записывает успешное завершение запроса - /// Увеличивает счетчик successful_requests и уменьшает active_requests - fn record_request_success(&self) { - self.successful_requests.fetch_add(1, Ordering::SeqCst); - self.active_requests.fetch_sub(1, Ordering::SeqCst); - } - - /// Записывает неудачное завершение запроса - /// Увеличивает счетчик failed_requests и уменьшает active_requests - fn record_request_failure(&self) { - self.failed_requests.fetch_add(1, Ordering::SeqCst); - self.active_requests.fetch_sub(1, Ordering::SeqCst); - } - - /// Возвращает текущие значения статистики - /// Возвращает кортеж: (total, success, failed, active) - fn get_stats(&self) -> (u64, u64, u64, u64) { - ( - self.total_requests.load(Ordering::SeqCst), - self.successful_requests.load(Ordering::SeqCst), - self.failed_requests.load(Ordering::SeqCst), - self.active_requests.load(Ordering::SeqCst), - ) - } -} - -/// Конфигурация статических файлов -/// Определяет параметры обслуживания статических ресурсов -#[derive(Clone)] -pub struct StaticFilesConfig { - pub enabled: bool, // Включено ли обслуживание статических файлов - pub directory: String, // Директория со статическими файлами -} - -impl Default for StaticFilesConfig { - fn default() -> Self { - Self { - enabled: true, - directory: "static".to_string(), - } - } -} - -/// Конфигурация TLS для HTTPS сервера -/// Содержит пути к сертификатам и ключам -#[derive(Clone)] -pub struct TlsConfig { - pub enabled: bool, // Включен ли TLS - pub cert_path: String, // Путь к файлу сертификата - pub key_path: String, // Путь к файлу приватного ключа -} - -impl Default for TlsConfig { - fn default() -> Self { - Self { - enabled: true, - cert_path: "certs/cert.pem".to_string(), - key_path: "certs/key.pem".to_string(), - } - } -} - -/// Конфигурация HTTP сервера -/// Определяет параметры протокола и порты -#[derive(Clone)] -pub struct HttpConfig { - pub enabled: bool, // Включен ли HTTP сервер - pub port: u16, // Порт для привязки - pub http2_enabled: bool, // Включена ли поддержка HTTP/2 -} - -/// Конфигурация Access Control List (ACL) -/// Позволяет управлять доступом по IP-адресам -#[derive(Clone)] -pub struct AclConfig { - pub enabled: bool, // Включена ли проверка ACL - pub allowed_ips: Vec, // Разрешенные IP-адреса - pub denied_ips: Vec, // Запрещенные IP-адреса -} - -impl Default for AclConfig { - fn default() -> Self { - Self { - enabled: false, - allowed_ips: vec!["127.0.0.1".to_string(), "::1".to_string()], - denied_ips: vec![], - } - } -} - -/// Lock-free обработчик HTTP запросов -/// Диспетчеризирует запросы по типам и выполняет соответствующие операции -async fn handle_request( - req: Request, - db: Arc, - static_config: StaticFilesConfig, - acl_config: AclConfig, - request_stats: Arc, -) -> Result> { - // Начинаем отслеживание запроса - request_stats.record_request_start(); - - // Проверка ACL с lock-free доступом - let acl_check = if acl_config.enabled { - let mut allowed = false; - - if let Some(remote_addr) = req.extensions().get::() { - let ip = remote_addr.ip().to_string(); - - // Проверка запрещенных IP - if acl_config.denied_ips.contains(&ip) { - request_stats.record_request_failure(); - return Ok(Response::builder() - .status(StatusCode::FORBIDDEN) - .body(Body::from("Access denied")) - .unwrap()); - } - - // Проверка разрешенных IP (если список не пустой) - if !acl_config.allowed_ips.is_empty() { - allowed = acl_config.allowed_ips.contains(&ip); - } else { - allowed = true; - } - } - allowed - } else { - true - }; - - if !acl_check { - request_stats.record_request_failure(); - return Ok(Response::builder() - .status(StatusCode::FORBIDDEN) - .body(Body::from("Access denied")) - .unwrap()); - } - - let path = req.uri().path(); - let method = req.method().clone(); - - // Логируем запрос без блокировок - // ИЗМЕНЕНИЕ: Отключаем непрерывный вывод логов в CLI - // println!("HTTP {} Request: {}", method, path); - - // Обработка API запросов - let result = if path.starts_with("/api/") { - handle_api_request(req, db).await - } - // Обслуживание статических файлов - else if static_config.enabled { - handle_static_file(path, static_config).await - } - // Корневой путь - редирект на default.html - else if path == "/" { - // ИЗМЕНЕНИЕ: Корневой путь теперь перенаправляет на default.html вместо index.html - // Это обеспечивает лучшую совместимость и избегает конфликтов с другими системами - Ok(Response::builder() - .status(StatusCode::TEMPORARY_REDIRECT) - .header("Location", "/default.html") - .body(Body::from("Redirecting to default.html")) - .unwrap()) - } - // 404 для остальных запросов - else { - Ok(Response::builder() - .status(StatusCode::NOT_FOUND) - .body(Body::from("Not Found")) - .unwrap()) - }; - - // Записываем результат - match &result { - Ok(response) if response.status().is_success() => { - request_stats.record_request_success(); - } - _ => { - request_stats.record_request_failure(); - } - } - - result -} - -/// Lock-free обработка API запросов -/// Обрабатывает REST API endpoints для доступа к данным -async fn handle_api_request( - req: Request, - db: Arc, -) -> Result> { - // Разбираем путь API - let path = req.uri().path(); - let parts: Vec<&str> = path.trim_start_matches("/api/").split('/').collect(); - - if parts.is_empty() { - return Ok(Response::builder() - .header("Content-Type", "application/json") - .body(Body::from(r#"{"status": "ok", "message": "Futriix Server API is running"}"#)) - .unwrap()); - } - - match parts[0] { - "status" => { - // Статус сервера - lock-free операция - Ok(Response::builder() - .header("Content-Type", "application/json") - .body(Body::from(r#"{"status": "running", "timestamp": ""#.to_owned() + - &chrono::Utc::now().to_rfc3339() + r#"", "version": "1.0.0"}"#)) - .unwrap()) - } - "collections" => { - // Список коллекций - lock-free операция через итератор - let collections_response = { - let mut collections = Vec::new(); - // Здесь должна быть реализация получения списка коллекций из БД - // Временный заглушка - collections.push("_system".to_string()); - collections.push("_users".to_string()); - collections.push("_logs".to_string()); - collections - }; - - let response_json = serde_json::json!({ - "status": "ok", - "collections": collections_response, - "count": collections_response.len() - }); - - Ok(Response::builder() - .header("Content-Type", "application/json") - .body(Body::from(response_json.to_string())) - .unwrap()) - } - _ => { - Ok(Response::builder() - .status(StatusCode::NOT_FOUND) - .header("Content-Type", "application/json") - .body(Body::from(r#"{"status": "error", "message": "API endpoint not found"}"#)) - .unwrap()) - } - } -} - -/// Lock-free обслуживание статических файлов -/// Читает файлы из директории и отдает их с правильным Content-Type -async fn handle_static_file( - path: &str, - config: StaticFilesConfig, -) -> Result> { - // Убираем начальный слеш из пути - let clean_path = path.trim_start_matches('/'); - - // ИЗМЕНЕНИЕ: Если путь пустой или корневой, используем default.html вместо index.html - // Это обеспечивает лучшую совместимость и избегает конфликтов с другими системами - let file_path = if clean_path.is_empty() || clean_path == "/" { - // Это дополнительная проверка, основной редирект уже обработан в handle_request - format!("{}/default.html", config.directory) - } else { - format!("{}/{}", config.directory, clean_path) - }; - - match File::open(&file_path).await { - Ok(mut file) => { - let mut contents = Vec::new(); - if let Err(e) = file.read_to_end(&mut contents).await { - eprintln!("Failed to read file {}: {}", file_path, e); - return Ok(Response::builder() - .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Body::from("Internal server error")) - .unwrap()); - } - - let content_type = get_content_type(&file_path); - - Ok(Response::builder() - .header("Content-Type", content_type) - .body(Body::from(contents)) - .unwrap()) - } - Err(e) => { - eprintln!("File not found: {} (error: {})", file_path, e); - - // Запасной HTML для тестирования если default.html не найден - if clean_path == "default.html" || clean_path.is_empty() { - let fallback_html = r#" - - - - Futriix Database Server - - - - -
- -

Futriix Database Server

-
Lock-Free Document Database with Lua Scripting
- -
-

Server Status: Online ✓

-

This is a fallback page. The enhanced default.html was not found or could not be loaded.

-

Requested path: PLACEHOLDER_PATH

-
- -
-
-

Server Information

-

Version: Futriix 1.0.0

-

Architecture: Wait-Free / Lock-Free

-

Protocol: HTTP/1.1, HTTP/2, HTTPS

-
- -
-

Current Status

-

Static Files: Fallback Mode

-

Database: Ready

-

Lua Engine: Active

-
-
- -
- Atomic Transactions - Real-time Analytics - Lua Scripting - Auto-Sharding - High Performance - CSV Import/Export -
- -
-
Server Time:
-
PLACEHOLDER_TIME
-
- - - -
- Server Log:
- - HTTP Server: Running
- - Database Engine: Initialized
- - Static Files: Fallback Mode Active
- - Current Time: PLACEHOLDER_TIME
- - Request Path: PLACEHOLDER_PATH -
- -
-

© 2025 Futriix Database Server. All rights reserved.

-

Built with Rust • Lock-Free Architecture • Enterprise Ready

-
-
- - - - - "#.replace("PLACEHOLDER_TIME", &chrono::Local::now().to_rfc2822()) - .replace("PLACEHOLDER_PATH", path); - - return Ok(Response::builder() - .header("Content-Type", "text/html; charset=utf-8") - .body(Body::from(fallback_html)) - .unwrap()); - } - - Ok(Response::builder() - .status(StatusCode::NOT_FOUND) - .body(Body::from("File not found")) - .unwrap()) - } - } -} - -/// Определение Content-Type по расширению файла -/// Сопоставляет расширения файлов с соответствующими MIME-типами -fn get_content_type(file_path: &str) -> &'static str { - if file_path.ends_with(".html") || file_path.ends_with(".htm") { - "text/html; charset=utf-8" - } else if file_path.ends_with(".css") { - "text/css; charset=utf-8" - } else if file_path.ends_with(".js") { - "application/javascript; charset=utf-8" - } else if file_path.ends_with(".png") { - "image/png" - } else if file_path.ends_with(".jpg") || file_path.ends_with(".jpeg") { - "image/jpeg" - } else if file_path.ends_with(".json") { - "application/json; charset=utf-8" - } else if file_path.ends_with(".ico") { - "image/x-icon" - } else if file_path.ends_with(".svg") { - "image/svg+xml" - } else if file_path.ends_with(".txt") { - "text/plain; charset=utf-8" - } else { - "application/octet-stream" - } -} - -/// Запуск HTTP сервера с lock-free архитектурой -/// Создает сервер Hyper, настраивает обработчики и запускает его -pub async fn start_http_server( - addr: &str, - db: Arc, - static_config: StaticFilesConfig, - http_config: HttpConfig, - acl_config: AclConfig, -) -> Result<()> { - let addr_parsed: std::net::SocketAddr = addr.parse() - .map_err(|e: std::net::AddrParseError| crate::common::FutriixError::HttpError(e.to_string()))?; - - // Создаем статистику запросов - let request_stats = Arc::new(RequestStats::new()); - - // ИЗМЕНЕНИЕ: Отключаем периодический вывод статистики в CLI - // Периодический вывод статистики был отключен, так как он мешал работе - // интерактивной оболочки и встроенной субд - - let db_clone = db.clone(); - let static_clone = static_config.clone(); - let acl_clone = acl_config.clone(); - let stats_clone = request_stats.clone(); - - // Создание lock-free сервиса - let make_svc = make_service_fn(move |_conn| { - let db = db_clone.clone(); - let static_config = static_clone.clone(); - let acl_config = acl_clone.clone(); - let request_stats = stats_clone.clone(); - - async move { - Ok::<_, hyper::Error>(service_fn(move |req| { - let db = db.clone(); - let static_config = static_config.clone(); - let acl_config = acl_config.clone(); - let request_stats = request_stats.clone(); - - async move { - handle_request(req, db, static_config, acl_config, request_stats).await - } - })) - } - }); - - println!("HTTP server starting on {}", addr); - println!("Web interface will be available at: http://{}/default.html", addr); - println!("Root path (/) redirects to /default.html"); - - // Запускаем сервер - let server = Server::bind(&addr_parsed).serve(make_svc); - - if let Err(e) = server.await { - eprintln!("HTTP server error: {}", e); - return Err(crate::common::FutriixError::HttpError(e.to_string())); - } - - Ok(()) -} - -/// Запуск HTTPS сервера с lock-free архитектурой -/// Настраивает TLS и запускает защищенный сервер -pub async fn start_https_server( - addr: &str, - db: Arc, - static_config: StaticFilesConfig, - tls_config: TlsConfig, - acl_config: AclConfig, -) -> Result<()> { - use tokio::net::TcpListener; - - if !tls_config.enabled { - println!("HTTPS disabled: TLS not enabled"); - return Ok(()); - } - - println!("HTTPS server would start on {} (TLS configuration needed)", addr); - println!("Web interface will be available at: https://{}/default.html", addr); - println!("Root path (/) redirects to /default.html"); - - // Запускаем обычный HTTP сервер на HTTPS порту для тестирования - let http_config = HttpConfig { - enabled: true, - port: 8443, - http2_enabled: false, - }; - - let owned_addr = addr.to_string(); - let owned_db = db.clone(); - let owned_static_config = static_config.clone(); - let owned_acl_config = acl_config.clone(); - - let server_future = async move { - start_http_server(&owned_addr, owned_db, owned_static_config, http_config, owned_acl_config).await - }; - - tokio::spawn(async move { - if let Err(e) = server_future.await { - eprintln!("HTTPS (HTTP fallback) server error: {}", e); - } - }); - - Ok(()) -}