Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src-tauri/src/cloud/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use serde::Serialize;
use std::sync::{Arc, Mutex};
use tauri::Manager;
use tokio::sync::Notify;

pub mod auth;
pub mod client;
Expand Down Expand Up @@ -32,6 +33,9 @@ pub struct CloudState {
pub queue_size: Mutex<u64>, // number of pending items
pub latest_snapshot: Mutex<Option<serde_json::Value>>,
pub latest_miners: Mutex<Option<serde_json::Value>>,
/// Notified on login so the sync loop runs an immediate cycle instead of
/// waiting up to 60s for the next tick. Mirrors the poller's force_poll.
pub login_notify: Notify,
}

impl CloudState {
Expand All @@ -46,6 +50,7 @@ impl CloudState {
queue_size: Mutex::new(0),
latest_snapshot: Mutex::new(None),
latest_miners: Mutex::new(None),
login_notify: Notify::new(),
}
}
}
Expand Down Expand Up @@ -85,9 +90,11 @@ pub async fn cloud_login(
auth::store_instance_id(&instance.id)?;
auth::store_instance_name(&instance.name)?;

// 4. Update state
// 4. Update state. Mark Connecting (not Connected yet) so the UI reflects
// that the first sync cycle is about to run; the sync loop flips it to
// Syncing during the push and Connected on success.
{
*state.status.lock().unwrap() = CloudSyncStatus::Connected;
*state.status.lock().unwrap() = CloudSyncStatus::Connecting;
*state.email.lock().unwrap() = Some(email.clone());
*state.instance_name.lock().unwrap() = Some(instance.name.clone());
*state.instance_id.lock().unwrap() = Some(instance.id.clone());
Expand Down Expand Up @@ -120,6 +127,10 @@ pub async fn cloud_login(
}
}

// 6. Wake the sync loop so it pushes now instead of waiting for the next
// 60s tick — gives the user immediate "Last sync" feedback after login.
state.login_notify.notify_one();

Ok(cloud_status_from_state(&state))
}

Expand Down
19 changes: 18 additions & 1 deletion src-tauri/src/cloud/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ pub async fn start_sync_loop(
let mut cycle: u64 = 0;

loop {
tokio::time::sleep(tokio::time::Duration::from_secs(60)).await;
// Wait for the regular interval or an immediate-sync signal (login).
tokio::select! {
_ = tokio::time::sleep(tokio::time::Duration::from_secs(60)) => {}
_ = cloud_state.login_notify.notified() => {
log::info!("Cloud sync: immediate cycle triggered by login");
}
}

// Check if logged in
let api_key = {
Expand All @@ -38,6 +44,7 @@ pub async fn start_sync_loop(

if let Some(payload) = snapshot {
log::info!("Cloud sync: pushing snapshot to cloud");
*cloud_state.status.lock().unwrap() = CloudSyncStatus::Syncing;
match client::push_snapshot(&api_key, &payload).await {
Ok(()) => {
let now_ms = chrono::Utc::now().timestamp_millis();
Expand Down Expand Up @@ -65,6 +72,7 @@ pub async fn start_sync_loop(

if let Some(payload) = miners {
log::info!("Cloud sync: pushing miner state to cloud");
*cloud_state.status.lock().unwrap() = CloudSyncStatus::Syncing;
match client::push_miners(&api_key, &payload).await {
Ok(()) => {
let now_ms = chrono::Utc::now().timestamp_millis();
Expand Down Expand Up @@ -146,6 +154,15 @@ pub async fn start_sync_loop(
*cloud_state.queue_size.lock().unwrap() = count;
}

// Settle the status: any leftover Connecting/Syncing (e.g. login with no
// data to push) resolves to Connected. Auth/Error states are preserved.
{
let mut st = cloud_state.status.lock().unwrap();
if matches!(*st, CloudSyncStatus::Connecting | CloudSyncStatus::Syncing) {
*st = CloudSyncStatus::Connected;
}
}

// --- 5. Periodic prune (every ~100 cycles ≈ 100 minutes) ---
if cycle % 100 == 0 {
if let Err(e) = queue::prune() {
Expand Down
Loading