agentmux_srv/backend/storage/
lan_peer_uid_pins.rs1use rusqlite::params;
11
12use super::error::StoreError;
13use super::store::Store;
14
15use agentmux_common::time::now_secs;
16
17impl Store {
18 pub fn lan_peer_uid_pin_get_or_set(
23 &self,
24 agent_id: &str,
25 uid: &str,
26 observed_key_b64: &str,
27 ) -> Result<String, StoreError> {
28 let name = agent_id.to_lowercase();
29 let conn = self.conn.lock().unwrap();
30 conn.execute(
31 "INSERT OR IGNORE INTO db_lan_peer_uid_pins (agent_id, uid, public_key, first_seen_at) \
32 VALUES (?1, ?2, ?3, ?4)",
33 params![name, uid, observed_key_b64, now_secs()],
34 )?;
35 let mut stmt = conn.prepare("SELECT public_key FROM db_lan_peer_uid_pins WHERE agent_id = ?1 AND uid = ?2")?;
36 stmt.query_row(params![name, uid], |row| row.get(0)).map_err(Into::into)
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 fn object_store() -> Store {
45 Store::open(std::path::Path::new(":memory:")).unwrap()
46 }
47
48 #[test]
49 fn the_first_key_for_a_name_and_uid_is_pinned_and_a_later_one_is_not() {
50 let store = object_store();
51 assert_eq!(store.lan_peer_uid_pin_get_or_set("Korp", "uid-1", "key-a").unwrap(), "key-a");
52 assert_eq!(store.lan_peer_uid_pin_get_or_set("korp", "uid-1", "key-b").unwrap(), "key-a");
53 }
54
55 #[test]
56 fn the_same_uid_under_another_name_pins_separately() {
57 let store = object_store();
58 store.lan_peer_uid_pin_get_or_set("korp", "uid-1", "key-a").unwrap();
59 assert_eq!(store.lan_peer_uid_pin_get_or_set("lark", "uid-1", "key-b").unwrap(), "key-b");
60 assert_eq!(store.lan_peer_uid_pin_get_or_set("korp", "uid-2", "key-c").unwrap(), "key-c");
61 }
62}