diff --git a/backend/app/models/file_lock.py b/backend/app/models/file_lock.py index 8e8698c..09cf7c7 100644 --- a/backend/app/models/file_lock.py +++ b/backend/app/models/file_lock.py @@ -2,8 +2,9 @@ from datetime import datetime, timezone, timedelta from app.extensions import db -# Lock expires after 5 minutes without heartbeat -LOCK_TIMEOUT_MINUTES = 5 +# Lock expires after 15 minutes without heartbeat +# Client sends heartbeat every 10 seconds and refreshes JWT every 10 minutes +LOCK_TIMEOUT_MINUTES = 15 class FileLock(db.Model): diff --git a/clients/desktop/src-tauri/src/lib.rs b/clients/desktop/src-tauri/src/lib.rs index f110cee..9c89628 100644 --- a/clients/desktop/src-tauri/src/lib.rs +++ b/clients/desktop/src-tauri/src/lib.rs @@ -481,19 +481,35 @@ fn start_background_sync( } }); - // Heartbeat every 60s + check if opened files are still in use + // Heartbeat + token refresh + check if opened files still in use let app_hb = app.clone(); let api_hb = api.clone(); std::thread::spawn(move || { let rt = tokio::runtime::Runtime::new().unwrap(); + let mut api_mut = api_hb.clone(); + let mut token_refresh_counter = 0u32; + loop { std::thread::sleep(Duration::from_secs(10)); let state = app_hb.state::(); + // Refresh JWT token every 10 minutes (before 15 min expiry) + token_refresh_counter += 10; + if token_refresh_counter >= 600 { + token_refresh_counter = 0; + if let Ok(new_token) = rt.block_on(api_mut.refresh_token()) { + // Update the shared API instance with new token + if let Some(ref mut api) = *state.api.lock().unwrap() { + api.access_token = new_token; + } + eprintln!("[Auth] Token refreshed"); + } + } + // Heartbeat for locked files let locked = state.locked_files.lock().unwrap().clone(); for file_id in &locked { - let _ = rt.block_on(api_hb.heartbeat(*file_id)); + let _ = rt.block_on(api_mut.heartbeat(*file_id)); } // Check if opened files are still in use by another process