somnytoo 1.1.0

Binary protocol server for secure communications
Documentation
use std::time::{Instant, Duration};
use tokio::sync::RwLock;
use std::sync::Arc;

#[derive(Debug, Clone)]
pub struct HealthStatus {
    pub is_healthy: bool,
    pub last_check: Instant,
    pub last_error: Option<String>,
    pub consecutive_failures: u32,
    pub component_status: Vec<ComponentStatus>,
}

impl HealthStatus {
    // ✅ ИСПРАВЛЕНО: Добавляем метод new
    pub fn new() -> Self {
        Self {
            is_healthy: false,
            last_check: Instant::now(),
            last_error: None,
            consecutive_failures: 0,
            component_status: Vec::new(),
        }
    }
}

#[derive(Debug, Clone)]
pub struct ComponentStatus {
    pub name: String,
    pub is_healthy: bool,
    pub response_time: Duration,
    pub last_error: Option<String>,
}

pub struct HealthChecker {
    check_interval: Duration,
    last_check: Arc<RwLock<Option<Instant>>>,
    health_status: Arc<RwLock<HealthStatus>>,
    consecutive_failures: Arc<std::sync::atomic::AtomicU32>,
}

impl HealthChecker {
    pub fn new(check_interval: Duration) -> Self {
        Self {
            check_interval,
            last_check: Arc::new(RwLock::new(None)),
            health_status: Arc::new(RwLock::new(HealthStatus::new())), // ✅ ИСПРАВЛЕНО: используем new()
            consecutive_failures: Arc::new(std::sync::atomic::AtomicU32::new(0)),
        }
    }

    // ✅ ИСПРАВЛЕНО: Переименовываем perform_health_check в check_health
    pub async fn check_health(&self) -> Result<HealthStatus, String> {
        let mut status = HealthStatus::new();
        status.last_check = Instant::now();

        // ✅ РЕАЛЬНАЯ ЛОГИКА: проверяем различные компоненты системы
        let components = self.check_components().await;
        status.component_status = components;

        // Определяем общий статус здоровья
        status.is_healthy = status.component_status.iter()
            .all(|component| component.is_healthy);

        if !status.is_healthy {
            status.consecutive_failures = self.consecutive_failures.fetch_add(1, std::sync::atomic::Ordering::Relaxed) + 1;
            status.last_error = Some("One or more components are unhealthy".to_string());
        } else {
            self.consecutive_failures.store(0, std::sync::atomic::Ordering::Relaxed);
            status.consecutive_failures = 0;
            status.last_error = None;
        }

        // Сохраняем статус
        {
            let mut health_status = self.health_status.write().await;
            *health_status = status.clone();
        }

        // Обновляем время последней проверки
        {
            let mut last_check = self.last_check.write().await;
            *last_check = Some(Instant::now());
        }

        Ok(status)
    }

    async fn check_components(&self) -> Vec<ComponentStatus> {
        let mut components = Vec::new();

        // ✅ РЕАЛЬНАЯ ЛОГИКА: проверка различных компонентов системы
        // В реальной реализации здесь будут проверки подключения к БД,
        // кэша, реплик и других компонентов

        // Заглушки для демонстрации
        components.push(ComponentStatus {
            name: "database".to_string(),
            is_healthy: true,
            response_time: Duration::from_millis(10),
            last_error: None,
        });

        components.push(ComponentStatus {
            name: "cache".to_string(),
            is_healthy: true,
            response_time: Duration::from_millis(5),
            last_error: None,
        });

        components.push(ComponentStatus {
            name: "replicas".to_string(),
            is_healthy: true,
            response_time: Duration::from_millis(15),
            last_error: None,
        });

        components
    }

    // ✅ ИСПРАВЛЕНО: Используем check_health вместо perform_health_check
    pub async fn start_periodic_checks(self: Arc<Self>) -> tokio::task::JoinHandle<()> {
        let checker = self.clone();
        let check_interval = self.check_interval;

        tokio::spawn(async move {
            let mut interval = tokio::time::interval(check_interval);
            println!("[HealthChecker] Starting periodic checks with interval: {:?}", check_interval);

            loop {
                interval.tick().await;

                // ✅ ИСПРАВЛЕНО: Используем check_health
                match checker.check_health().await {
                    Ok(health) => {
                        if health.is_healthy {
                            checker.consecutive_failures.store(0, std::sync::atomic::Ordering::Relaxed);
                            println!("[HealthChecker] Health check passed - all systems operational");
                        } else {
                            let failures = checker.consecutive_failures.fetch_add(1, std::sync::atomic::Ordering::Relaxed) + 1;
                            println!("[HealthChecker] Health check failed {} times consecutively", failures);
                        }
                    }
                    Err(e) => {
                        let failures = checker.consecutive_failures.fetch_add(1, std::sync::atomic::Ordering::Relaxed) + 1;
                        println!("[HealthChecker] Health check error ({}): {}", failures, e);
                    }
                }
            }
        })
    }

    // ✅ ДОБАВЛЕНО: Метод для получения текущего статуса
    pub async fn get_current_status(&self) -> HealthStatus {
        let health_status = self.health_status.read().await;
        health_status.clone()
    }

    // ✅ ДОБАВЛЕНО: Метод для получения интервала проверки
    pub fn get_check_interval(&self) -> Duration {
        self.check_interval
    }

    // ✅ ДОБАВЛЕНО: Метод для изменения интервала на лету
    pub fn set_check_interval(&mut self, interval: Duration) {
        self.check_interval = interval;
        println!("[HealthChecker] Check interval updated to: {:?}", interval);
    }

    // ✅ ДОБАВЛЕНО: Проверка необходимости проверки с учетом интервала
    pub async fn should_perform_check(&self) -> bool {
        let last_check = self.last_check.read().await;
        match *last_check {
            Some(time) => Instant::now().duration_since(time) >= self.check_interval,
            None => true, // Никогда не проверяли
        }
    }

    // ✅ ДОБАВЛЕНО: Принудительная проверка
    pub async fn force_check(&self) -> Result<HealthStatus, String> {
        self.check_health().await
    }

    // ✅ ДОБАВЛЕНО: Получение статистики ошибок
    pub fn get_consecutive_failures(&self) -> u32 {
        self.consecutive_failures.load(std::sync::atomic::Ordering::Relaxed)
    }
}