use iroh::EndpointAddr; use rusqlite::params; use time::{OffsetDateTime, format_description::well_known::Rfc3339}; use crate::{domain::FolderId, storage::StateStore}; #[derive(Clone, Debug)] pub struct PeerInfo { pub device_id: String, pub endpoint: EndpointAddr, pub last_seen: OffsetDateTime, } impl StateStore { pub fn peers(&self, folder_id: FolderId) -> anyhow::Result> { let mut statement = self .connection .prepare("SELECT endpoint FROM known_peers WHERE folder_id = ?1 ORDER BY device_id")?; statement .query_map(params![folder_id.to_string()], |row| { row.get::<_, String>(0) })? .collect::, _>>()? .into_iter() .map(|endpoint| serde_json::from_str(&endpoint).map_err(Into::into)) .collect() } pub fn save_peer(&self, folder_id: FolderId, endpoint: &EndpointAddr) -> anyhow::Result<()> { self.connection.execute( "INSERT INTO known_peers (folder_id, device_id, endpoint, last_seen) VALUES (?1, ?2, ?3, ?4) ON CONFLICT(folder_id, device_id) DO UPDATE SET endpoint = excluded.endpoint, last_seen = excluded.last_seen", params![folder_id.to_string(), endpoint.id.to_string(), serde_json::to_string(endpoint)?, OffsetDateTime::now_utc().format(&Rfc3339)?], )?; Ok(()) } pub fn peer_info(&self, folder_id: FolderId) -> anyhow::Result> { let mut statement = self.connection.prepare("SELECT device_id, endpoint, last_seen FROM known_peers WHERE folder_id = ?1 ORDER BY device_id")?; statement .query_map(params![folder_id.to_string()], |row| { Ok(( row.get::<_, String>(0)?, row.get::<_, String>(1)?, row.get::<_, String>(2)?, )) })? .collect::, _>>()? .into_iter() .map(peer_info_from_values) .collect() } } fn peer_info_from_values(values: (String, String, String)) -> anyhow::Result { Ok(PeerInfo { device_id: values.0, endpoint: serde_json::from_str(&values.1)?, last_seen: OffsetDateTime::parse(&values.2, &Rfc3339)?, }) }