diff --git a/src/db/person.rs b/src/db/person.rs index 39f41581..9b2561dd 100644 --- a/src/db/person.rs +++ b/src/db/person.rs @@ -192,6 +192,23 @@ impl DbPerson { Ok(()) } + pub async fn follow(pubkey: PublicKeyHex) -> Result<(), Error> { + let sql = "INSERT INTO PERSON (pubkey, followed) values (?, 1) \ + ON CONFLICT(pubkey) DO UPDATE SET followed=1"; + + spawn_blocking(move || { + let maybe_db = GLOBALS.db.blocking_lock(); + let db = maybe_db.as_ref().unwrap(); + + let mut stmt = db.prepare(sql)?; + stmt.execute((&pubkey.0,))?; + Ok::<(), Error>(()) + }) + .await??; + + Ok(()) + } + #[allow(dead_code)] pub async fn delete(criteria: &str) -> Result<(), Error> { let sql = format!("DELETE FROM person WHERE {}", criteria); diff --git a/src/overlord/mod.rs b/src/overlord/mod.rs index a22ded2b..f4dbd086 100644 --- a/src/overlord/mod.rs +++ b/src/overlord/mod.rs @@ -357,6 +357,14 @@ impl Overlord { } }); } + "follow_bech32" => { + let data: (String, String) = serde_json::from_str(&bus_message.json_payload)?; + Overlord::follow_bech32(data.0, data.1).await?; + } + "follow_hexkey" => { + let data: (String, String) = serde_json::from_str(&bus_message.json_payload)?; + Overlord::follow_hexkey(data.0, data.1).await?; + } _ => {} }, _ => {} @@ -455,9 +463,11 @@ impl Overlord { for relay in relays.iter() { // Save relay - let db_relay = DbRelay::new(relay.to_string())?; + let relay_url = Url::new_validated(relay)?; + let db_relay = DbRelay::new(relay_url.0)?; DbRelay::insert(db_relay).await?; + // Save person_relay DbPersonRelay::upsert_last_suggested_nip35( (*pubkey).into(), relay.0.clone(), @@ -470,4 +480,54 @@ impl Overlord { Ok(()) } + + async fn follow_bech32(bech32: String, relay: String) -> Result<(), Error> { + let pk = PublicKey::try_from_bech32_string(&bech32)?; + let pkhex: PublicKeyHex = pk.into(); + DbPerson::follow(pkhex.clone()).await?; + + debug!("Followed {}", &pkhex); + + // Save relay + let relay_url = Url::new_validated(&relay)?; + let db_relay = DbRelay::new(relay.to_string())?; + DbRelay::insert(db_relay).await?; + + // Save person_relay + DbPersonRelay::insert(DbPersonRelay { + person: pkhex.0.clone(), + relay: relay_url.0.clone(), + ..Default::default() + }) + .await?; + + info!("Setup 1 relay for {}", &pkhex); + + Ok(()) + } + + async fn follow_hexkey(hexkey: String, relay: String) -> Result<(), Error> { + let pk = PublicKey::try_from_hex_string(&hexkey)?; + let pkhex: PublicKeyHex = pk.into(); + DbPerson::follow(pkhex.clone()).await?; + + debug!("Followed {}", &pkhex); + + // Save relay + let relay_url = Url::new_validated(&relay)?; + let db_relay = DbRelay::new(relay.to_string())?; + DbRelay::insert(db_relay).await?; + + // Save person_relay + DbPersonRelay::insert(DbPersonRelay { + person: pkhex.0.clone(), + relay: relay_url.0.clone(), + ..Default::default() + }) + .await?; + + info!("Setup 1 relay for {}", &pkhex); + + Ok(()) + } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index a49ce43e..fc6a4a0b 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -64,6 +64,9 @@ struct GossipUi { draft: String, settings: Settings, nip35follow: String, + follow_bech32_pubkey: String, + follow_hex_pubkey: String, + follow_pubkey_at_relay: String, } impl GossipUi { @@ -116,6 +119,9 @@ impl GossipUi { draft: "".to_owned(), settings, nip35follow: "".to_owned(), + follow_bech32_pubkey: "".to_owned(), + follow_hex_pubkey: "".to_owned(), + follow_pubkey_at_relay: "".to_owned(), } } } diff --git a/src/ui/people.rs b/src/ui/people.rs index 4b617fbd..e0451d2c 100644 --- a/src/ui/people.rs +++ b/src/ui/people.rs @@ -2,7 +2,7 @@ use super::{GossipUi, Page}; use crate::comms::BusMessage; use crate::globals::GLOBALS; use eframe::egui; -use egui::{Context, RichText, ScrollArea, TextStyle, TopBottomPanel, Ui, Vec2}; +use egui::{Context, RichText, ScrollArea, TextEdit, TextStyle, TopBottomPanel, Ui, Vec2}; pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Frame, ui: &mut Ui) { TopBottomPanel::top("people_menu").show(ctx, |ui| { @@ -15,27 +15,89 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Fra }); if app.page == Page::PeopleFollow { - ui.add_space(24.0); + ui.add_space(30.0); - ui.add_space(8.0); - ui.heading("Follow someone"); - ui.add_space(18.0); + ui.heading("NOTICE: Gossip doesn't update the filters when you follow someone yet, so you have to restart the client to fetch their events. Will fix soon."); + ui.add_space(10.0); ui.separator(); + ui.add_space(10.0); + + ui.heading("NIP-35: Follow a DNS ID"); ui.horizontal(|ui| { ui.label("Enter user@domain"); - ui.text_edit_singleline(&mut app.nip35follow); - if ui.button("follow").clicked() { - let tx = GLOBALS.to_overlord.clone(); - let _ = tx.send(BusMessage { - target: "overlord".to_string(), - kind: "follow_nip35".to_string(), - json_payload: serde_json::to_string(&app.nip35follow).unwrap(), - }); - app.nip35follow = "".to_owned(); - } + ui.add(TextEdit::singleline(&mut app.nip35follow).hint_text("user@domain")); }); + if ui.button("follow").clicked() { + let tx = GLOBALS.to_overlord.clone(); + let _ = tx.send(BusMessage { + target: "overlord".to_string(), + kind: "follow_nip35".to_string(), + json_payload: serde_json::to_string(&app.nip35follow).unwrap(), + }); + app.nip35follow = "".to_owned(); + } + + ui.add_space(10.0); + ui.separator(); + ui.add_space(10.0); + + ui.heading("Follow a bech32 public key"); + + ui.horizontal(|ui| { + ui.label("Enter bech32 public key"); + ui.add(TextEdit::singleline(&mut app.follow_bech32_pubkey).hint_text("npub1...")); + }); + ui.horizontal(|ui| { + ui.label("Enter a relay URL where we can find them"); + ui.add(TextEdit::singleline(&mut app.follow_pubkey_at_relay).hint_text("wss://...")); + }); + if ui.button("follow").clicked() { + let tx = GLOBALS.to_overlord.clone(); + let _ = tx.send(BusMessage { + target: "overlord".to_string(), + kind: "follow_bech32".to_string(), + json_payload: serde_json::to_string(&( + &app.follow_bech32_pubkey, + &app.follow_pubkey_at_relay, + )) + .unwrap(), + }); + app.follow_bech32_pubkey = "".to_owned(); + app.follow_pubkey_at_relay = "".to_owned(); + } + + ui.add_space(10.0); + ui.separator(); + ui.add_space(10.0); + + ui.heading("Follow a hex public key"); + + ui.horizontal(|ui| { + ui.label("Enter hex-encoded public key"); + ui.add( + TextEdit::singleline(&mut app.follow_hex_pubkey).hint_text("0123456789abcdef..."), + ); + }); + ui.horizontal(|ui| { + ui.label("Enter a relay URL where we can find them"); + ui.add(TextEdit::singleline(&mut app.follow_pubkey_at_relay).hint_text("wss://...")); + }); + if ui.button("follow").clicked() { + let tx = GLOBALS.to_overlord.clone(); + let _ = tx.send(BusMessage { + target: "overlord".to_string(), + kind: "follow_hexkey".to_string(), + json_payload: serde_json::to_string(&( + &app.follow_hex_pubkey, + &app.follow_pubkey_at_relay, + )) + .unwrap(), + }); + app.follow_hex_pubkey = "".to_owned(); + app.follow_pubkey_at_relay = "".to_owned(); + } } else if app.page == Page::PeopleList { ui.add_space(24.0);