diff --git a/src/server/http.rs b/src/server/http.rs deleted file mode 100755 index c5fa5f5..0000000 --- a/src/server/http.rs +++ /dev/null @@ -1,374 +0,0 @@ -// src/server/http.rs -//! HTTP/HTTPS сервер с wait-free обработкой запросов - -#![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 crate::common::Result; -use crate::server::database::Database; - -/// Конфигурация статических файлов -#[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 -#[derive(Clone)] -pub struct TlsConfig { - pub enabled: bool, - 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, - pub port: u16, - pub http2_enabled: bool, -} - -/// Конфигурация ACL -#[derive(Clone)] -pub struct AclConfig { - pub enabled: bool, - pub allowed_ips: Vec, - pub denied_ips: Vec, -} - -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![], - } - } -} - -/// Wait-free обработчик HTTP запросов с поддержкой ACL -async fn handle_request( - req: Request, - db: Arc, - static_config: StaticFilesConfig, - acl_config: AclConfig, -) -> Result> { - // Проверка ACL, если включена - if acl_config.enabled { - if let Some(remote_addr) = req.extensions().get::() { - let ip = remote_addr.ip().to_string(); - - // Проверка запрещенных IP - if acl_config.denied_ips.contains(&ip) { - return Ok(Response::builder() - .status(StatusCode::FORBIDDEN) - .body(Body::from("Access denied")) - .unwrap()); - } - - // Проверка разрешенных IP (если список не пустой) - if !acl_config.allowed_ips.is_empty() && !acl_config.allowed_ips.contains(&ip) { - return Ok(Response::builder() - .status(StatusCode::FORBIDDEN) - .body(Body::from("Access denied")) - .unwrap()); - } - } - } - - let path = req.uri().path(); - - println!("HTTP Request: {} {}", req.method(), path); - - // Обработка API запросов - if path.starts_with("/api/") { - handle_api_request(req, db).await - } - // Обслуживание статических файлов - else if static_config.enabled { - handle_static_file(path, static_config).await - } - // Корневой путь - else if path == "/" { - // ВОЗВРАЩАЕМ ПРОСТОЙ HTML ДЛЯ КОРНЕВОГО ПУТИ - Ok(Response::builder() - .header("Content-Type", "text/html; charset=utf-8") - .body(Body::from(r#" - - - - Futriix Database Server - - - -

Futriix Database Server

-

Server is running successfully!

-

Try accessing /index.html for the main interface.

- - - "#)) - .unwrap()) - } - // 404 для остальных запросов - else { - Ok(Response::builder() - .status(StatusCode::NOT_FOUND) - .body(Body::from("Not Found")) - .unwrap()) - } -} - -/// Wait-free обработка API запросов -async fn handle_api_request( - _req: Request, - _db: Arc, -) -> Result> { - // TODO: Реализовать wait-free обработку CRUD операций через HTTP - Ok(Response::builder() - .header("Content-Type", "application/json") - .body(Body::from(r#"{"status": "ok", "message": "Futriix Server is running"}"#)) - .unwrap()) -} - -/// Wait-free обслуживание статических файлов -async fn handle_static_file( - path: &str, - config: StaticFilesConfig, -) -> Result> { - // Убираем начальный слеш из пути - let clean_path = path.trim_start_matches('/'); - - // Если путь пустой или корневой, используем index.html - let file_path = if clean_path.is_empty() || clean_path == "/" { - format!("{}/index.html", config.directory) - } else { - format!("{}/{}", config.directory, clean_path) - }; - - // ДОБАВЛЯЕМ ДЕБАГ-ЛОГИРОВАНИЕ - println!("Trying to serve static file: {}", file_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); - - println!("Successfully served static file: {} ({} bytes)", file_path, contents.len()); - - Ok(Response::builder() - .header("Content-Type", content_type) - .body(Body::from(contents)) - .unwrap()) - } - Err(e) => { - eprintln!("File not found: {} (error: {})", file_path, e); - - // ДОБАВЛЯЕМ ПРОСТОЙ HTML ДЛЯ ТЕСТИРОВАНИЯ, ЕСЛИ ФАЙЛ НЕ НАЙДЕН - if clean_path == "index.html" { - let fallback_html = r#" - - - - Futriix Database Server - - - -

Futriix Database Server

-

Welcome to Futriix Database Server!

-

Static file serving is working correctly.

-

Current time: PLACEHOLDER_TIME

-

Requested path: PLACEHOLDER_PATH

- - - "#.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 по расширению файла -fn get_content_type(file_path: &str) -> &'static str { - if file_path.ends_with(".html") { - "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 { - "text/plain; charset=utf-8" - } -} - -/// Запуск HTTP сервера с wait-free архитектурой -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 db_clone = db.clone(); - let static_clone = static_config.clone(); - let acl_clone = acl_config.clone(); - - // Создание wait-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(); - - 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(); - async move { - handle_request(req, db, static_config, acl_config).await - } - })) - } - }); - - println!("HTTP server starting on {}...", addr); - - // ЗАПУСКАЕМ СЕРВЕР И БЛОКИРУЕМСЯ НА ЕГО ВЫПОЛНЕНИИ - // Это гарантирует, что сервер продолжит работать - 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 сервера с wait-free архитектурой -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(()); - } - - // ПРОСТОЙ ВАРИАНТ БЕЗ TLS ДЛЯ ТЕСТИРОВАНИЯ - // В реальном коде здесь должна быть TLS конфигурация - println!("HTTPS server would start on {} (TLS configuration needed)", addr); - - // ЗАПУСКАЕМ ОБЫЧНЫЙ HTTP СЕРВЕР НА HTTPS ПОРТУ ДЛЯ ТЕСТИРОВАНИЯ - // Но используем тот же порт, чтобы не путать - let http_config = HttpConfig { - enabled: true, - port: 8443, // Используем HTTPS порт для тестирования - http2_enabled: false, - }; - - // ИСПРАВЛЕНИЕ ОШИБКИ: создаем owned копии всех данных для использования в async move - 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(); - - // Запускаем обычный HTTP сервер на HTTPS порту для тестирования - // Это временное решение до настройки TLS - 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(()) -} - -// Вспомогательная функция для логирования -fn log_to_file(message: &str) { - use std::fs::OpenOptions; - use std::io::Write; - - 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()); - } -}