Skip to main content

#
jellytau_lib/auth/
session_verifier.rs

    1use serde::Serialize;
    2use std::sync::atomic::{AtomicBool, Ordering};
    3use std::sync::Arc;
    4use std::time::Duration;
    5use tauri::{AppHandle, Emitter};
    6
    7use super::{AuthManager, User};
    8
    9// Verification interval (5 minutes)
    10const VERIFICATION_INTERVAL_MS: u64 = 300000;
    11
    12/// Session verification result event emitted to frontend
    13#[derive(Debug, Clone, Serialize)]
    14#[serde(rename_all = "camelCase", tag = "type")]
    15pub enum SessionVerificationEvent {
    16    Verified { user: User },
    17    NeedsReauth { reason: String },
    18    NetworkError { message: String },
    19}
    20
    21/// Background session verifier
    22pub struct SessionVerifier {
    23    auth_manager: Arc<AuthManager>,
    24    is_running: Arc<AtomicBool>,
    25    device_id: String,
    26    app_handle: Option<AppHandle>,
    27}
    28
    29impl SessionVerifier {
    30    /// Create a new session verifier
    31    pub fn new(auth_manager: Arc<AuthManager>, device_id: String) -> Self {
    32        Self {
    33            auth_manager,
    34            is_running: Arc::new(AtomicBool::new(false)),
    35            device_id,
    36            app_handle: None,
    37        }
    38    }
    39
    40    /// Set the Tauri app handle for event emission
    41    pub fn set_app_handle(&mut self, app_handle: AppHandle) {
    42        self.app_handle = Some(app_handle);
    43    }
    44
    45    /// Start periodic session verification
    46    pub async fn start(&self) {
    47        if self.is_running.swap(true, Ordering::SeqCst) {
    48            log::info!("[SessionVerifier] Already running");
    49            return;
    50        }
    51
    52        log::info!("[SessionVerifier] Starting background verification");
    53
    54        let auth_manager = Arc::clone(&self.auth_manager);
    55        let is_running = Arc::clone(&self.is_running);
    56        let device_id = self.device_id.clone();
    57        let app_handle = self.app_handle.clone();
    58
    59        tokio::spawn(async move {
    60            // Initial verification after short delay
    61            tokio::time::sleep(Duration::from_millis(2000)).await;
    62
    63            while is_running.load(Ordering::SeqCst) {
    64                // Get current session
    65                let session = auth_manager.get_session().await;
    66
    67                if let Some(session) = session {
    68                    log::debug!(
    69                        "[SessionVerifier] Verifying session for: {}",
    70                        session.username
    71                    );
    72
    73                    // Verify the session
    74                    match auth_manager
    75                        .verify_session(
    76                            &session.server_url,
    77                            &session.user_id,
    78                            &session.access_token,
    79                            &device_id,
    80                        )
    81                        .await
    82                    {
    83                        Ok(user) => {
    84                            log::info!("[SessionVerifier] Session verified successfully");
    85
    86                            // Emit success event
    87                            if let Some(app) = &app_handle {
    88                                let event = SessionVerificationEvent::Verified { user };
    89                                if let Err(e) = app.emit("auth:session-verified", event) {
    90                                    log::error!("[SessionVerifier] Failed to emit event: {}", e);
    91                                }
    92                            }
    93
    94                            // Update session as verified
    95                            let mut updated_session = session;
    96                            updated_session.verified = true;
    97                            updated_session.needs_reauth = false;
    98                            auth_manager.set_session(Some(updated_session)).await;
    99                        }
    100                        Err(e) => {
    101                            log::warn!("[SessionVerifier] Verification failed: {}", e);
    102
    103                            // Classify error
    104                            let is_auth_error = e.contains("401") || e.contains("403");
    105                            let is_network_error = e.contains("network")
    106                                || e.contains("timeout")
    107                                || e.contains("connection")
    108                                || e.contains("DNS");
    109
    110                            if is_auth_error {
    111                                // Token is invalid - need re-authentication
    112                                log::warn!("[SessionVerifier] Session requires re-authentication");
    113
    114                                if let Some(app) = &app_handle {
    115                                    let event = SessionVerificationEvent::NeedsReauth {
    116                                        reason: "Session expired".to_string(),
    117                                    };
    118                                    if let Err(e) = app.emit("auth:needs-reauth", event) {
    119                                        log::error!(
    120                                            "[SessionVerifier] Failed to emit event: {}",
    121                                            e
    122                                        );
    123                                    }
    124                                }
    125
    126                                // Update session
    127                                let mut updated_session = session;
    128                                updated_session.verified = false;
    129                                updated_session.needs_reauth = true;
    130                                auth_manager.set_session(Some(updated_session)).await;
    131                            } else if is_network_error {
    132                                // Network error - keep using cached session
    133                                log::info!("[SessionVerifier] Network error during verification, keeping cached session");
    134
    135                                if let Some(app) = &app_handle {
    136                                    let event = SessionVerificationEvent::NetworkError {
    137                                        message: e.clone(),
    138                                    };
    139                                    if let Err(e) = app.emit("auth:network-error", event) {
    140                                        log::error!(
    141                                            "[SessionVerifier] Failed to emit event: {}",
    142                                            e
    143                                        );
    144                                    }
    145                                }
    146                            } else {
    147                                // Unknown error - log but don't invalidate
    148                                log::error!(
    149                                    "[SessionVerifier] Unknown error during verification: {}",
    150                                    e
    151                                );
    152                            }
    153                        }
    154                    }
    155                }
    156
    157                // Wait for next verification
    158                tokio::time::sleep(Duration::from_millis(VERIFICATION_INTERVAL_MS)).await;
    159            }
    160
    161            log::info!("[SessionVerifier] Stopped");
    162        });
    163    }
    164
    165    /// Stop periodic verification
    166    pub fn stop(&self) {
    167        log::info!("[SessionVerifier] Stopping background verification");
    168        self.is_running.store(false, Ordering::SeqCst);
    169    }
    170}