Skip to main content

max / goingson

2.3 KB · 75 lines History Blame Raw
1 //! Sync state helpers: key-value store and device registration.
2
3 use std::collections::HashMap;
4 use goingson_core::CoreError;
5 use sqlx::SqlitePool;
6 use synckit_client::SyncKitClient;
7 use tracing::info;
8 use uuid::Uuid;
9
10 pub async fn get_sync_state(pool: &SqlitePool, key: &str) -> Result<String, CoreError> {
11 let row: Option<(String,)> =
12 sqlx::query_as("SELECT value FROM sync_state WHERE key = ?")
13 .bind(key)
14 .fetch_optional(pool)
15 .await
16 .map_err(CoreError::database)?;
17
18 Ok(row.map(|r| r.0).unwrap_or_default())
19 }
20
21 pub async fn get_sync_states_batch(pool: &SqlitePool, keys: &[&str]) -> Result<HashMap<String, String>, CoreError> {
22 if keys.is_empty() {
23 return Ok(HashMap::new());
24 }
25
26 let placeholders = keys.iter().map(|_| "?").collect::<Vec<_>>().join(",");
27 let query = format!("SELECT key, value FROM sync_state WHERE key IN ({})", placeholders);
28
29 let mut q = sqlx::query_as::<_, (String, String)>(&query);
30 for key in keys {
31 q = q.bind(*key);
32 }
33
34 let rows = q.fetch_all(pool).await.map_err(CoreError::database)?;
35 Ok(rows.into_iter().collect())
36 }
37
38 pub async fn set_sync_state(pool: &SqlitePool, key: &str, value: &str) -> Result<(), CoreError> {
39 sqlx::query("INSERT OR REPLACE INTO sync_state (key, value) VALUES (?, ?)")
40 .bind(key)
41 .bind(value)
42 .execute(pool)
43 .await
44 .map_err(CoreError::database)?;
45 Ok(())
46 }
47
48 pub async fn ensure_device_registered(
49 pool: &SqlitePool,
50 client: &SyncKitClient,
51 ) -> Result<Uuid, CoreError> {
52 let stored = get_sync_state(pool, "device_id").await?;
53 if !stored.is_empty() {
54 return stored
55 .parse::<Uuid>()
56 .map_err(|e| CoreError::parse(format!("invalid stored device_id: {}", e)));
57 }
58
59 let hostname = std::env::var("HOSTNAME")
60 .or_else(|_| std::env::var("COMPUTERNAME"))
61 .unwrap_or_else(|_| "GoingsOn Desktop".to_string());
62
63 let platform = std::env::consts::OS.to_string();
64
65 let device = client
66 .register_device(&hostname, &platform)
67 .await
68 .map_err(|e| CoreError::sync(format!("device registration failed: {}", e)))?;
69
70 set_sync_state(pool, "device_id", &device.id.to_string()).await?;
71 info!("Registered device: {} ({})", device.device_name, device.id);
72
73 Ok(device.id)
74 }
75