First working POC
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tauri::{AppHandle, Emitter};
|
||||
use serde::Serialize;
|
||||
|
||||
use super::{AuthManager, User};
|
||||
|
||||
// Verification interval (5 minutes)
|
||||
const VERIFICATION_INTERVAL_MS: u64 = 300000;
|
||||
|
||||
/// Session verification result event emitted to frontend
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase", tag = "type")]
|
||||
pub enum SessionVerificationEvent {
|
||||
Verified { user: User },
|
||||
NeedsReauth { reason: String },
|
||||
NetworkError { message: String },
|
||||
}
|
||||
|
||||
/// Background session verifier
|
||||
pub struct SessionVerifier {
|
||||
auth_manager: Arc<AuthManager>,
|
||||
is_running: Arc<AtomicBool>,
|
||||
device_id: String,
|
||||
app_handle: Option<AppHandle>,
|
||||
}
|
||||
|
||||
impl SessionVerifier {
|
||||
/// Create a new session verifier
|
||||
pub fn new(auth_manager: Arc<AuthManager>, device_id: String) -> Self {
|
||||
Self {
|
||||
auth_manager,
|
||||
is_running: Arc::new(AtomicBool::new(false)),
|
||||
device_id,
|
||||
app_handle: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the Tauri app handle for event emission
|
||||
pub fn set_app_handle(&mut self, app_handle: AppHandle) {
|
||||
self.app_handle = Some(app_handle);
|
||||
}
|
||||
|
||||
/// Start periodic session verification
|
||||
pub async fn start(&self) {
|
||||
if self.is_running.swap(true, Ordering::SeqCst) {
|
||||
log::info!("[SessionVerifier] Already running");
|
||||
return;
|
||||
}
|
||||
|
||||
log::info!("[SessionVerifier] Starting background verification");
|
||||
|
||||
let auth_manager = Arc::clone(&self.auth_manager);
|
||||
let is_running = Arc::clone(&self.is_running);
|
||||
let device_id = self.device_id.clone();
|
||||
let app_handle = self.app_handle.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
// Initial verification after short delay
|
||||
tokio::time::sleep(Duration::from_millis(2000)).await;
|
||||
|
||||
while is_running.load(Ordering::SeqCst) {
|
||||
// Get current session
|
||||
let session = auth_manager.get_session().await;
|
||||
|
||||
if let Some(session) = session {
|
||||
log::debug!("[SessionVerifier] Verifying session for: {}", session.username);
|
||||
|
||||
// Verify the session
|
||||
match auth_manager
|
||||
.verify_session(
|
||||
&session.server_url,
|
||||
&session.user_id,
|
||||
&session.access_token,
|
||||
&device_id,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(user) => {
|
||||
log::info!("[SessionVerifier] Session verified successfully");
|
||||
|
||||
// Emit success event
|
||||
if let Some(app) = &app_handle {
|
||||
let event = SessionVerificationEvent::Verified { user };
|
||||
if let Err(e) = app.emit("auth:session-verified", event) {
|
||||
log::error!("[SessionVerifier] Failed to emit event: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Update session as verified
|
||||
let mut updated_session = session;
|
||||
updated_session.verified = true;
|
||||
updated_session.needs_reauth = false;
|
||||
auth_manager.set_session(Some(updated_session)).await;
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("[SessionVerifier] Verification failed: {}", e);
|
||||
|
||||
// Classify error
|
||||
let is_auth_error = e.contains("401") || e.contains("403");
|
||||
let is_network_error = e.contains("network")
|
||||
|| e.contains("timeout")
|
||||
|| e.contains("connection")
|
||||
|| e.contains("DNS");
|
||||
|
||||
if is_auth_error {
|
||||
// Token is invalid - need re-authentication
|
||||
log::warn!("[SessionVerifier] Session requires re-authentication");
|
||||
|
||||
if let Some(app) = &app_handle {
|
||||
let event = SessionVerificationEvent::NeedsReauth {
|
||||
reason: "Session expired".to_string(),
|
||||
};
|
||||
if let Err(e) = app.emit("auth:needs-reauth", event) {
|
||||
log::error!("[SessionVerifier] Failed to emit event: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Update session
|
||||
let mut updated_session = session;
|
||||
updated_session.verified = false;
|
||||
updated_session.needs_reauth = true;
|
||||
auth_manager.set_session(Some(updated_session)).await;
|
||||
} else if is_network_error {
|
||||
// Network error - keep using cached session
|
||||
log::info!("[SessionVerifier] Network error during verification, keeping cached session");
|
||||
|
||||
if let Some(app) = &app_handle {
|
||||
let event = SessionVerificationEvent::NetworkError {
|
||||
message: e.clone(),
|
||||
};
|
||||
if let Err(e) = app.emit("auth:network-error", event) {
|
||||
log::error!("[SessionVerifier] Failed to emit event: {}", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Unknown error - log but don't invalidate
|
||||
log::error!("[SessionVerifier] Unknown error during verification: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for next verification
|
||||
tokio::time::sleep(Duration::from_millis(VERIFICATION_INTERVAL_MS)).await;
|
||||
}
|
||||
|
||||
log::info!("[SessionVerifier] Stopped");
|
||||
});
|
||||
}
|
||||
|
||||
/// Stop periodic verification
|
||||
pub fn stop(&self) {
|
||||
log::info!("[SessionVerifier] Stopping background verification");
|
||||
self.is_running.store(false, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user