From f0d573f9912f112497fb173c59211b984f96df33 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Fri, 3 Feb 2023 21:21:19 +1300 Subject: [PATCH] Schema 21: person_relay.{read,write} + relay.{read,write,advertise} + a rename --- src/comms.rs | 2 +- src/db/mod.rs | 3 ++- src/db/person_relay.rs | 19 ++++++++++---- src/db/relay.rs | 59 ++++++++++++++++++++++++++++++------------ src/db/schema21.sql | 8 ++++++ src/globals.rs | 2 +- src/overlord/mod.rs | 21 ++++++++------- src/people.rs | 45 +++++++++++++++++++++----------- src/process.rs | 2 +- src/ui/feed/post.rs | 2 +- src/ui/relays/all.rs | 29 ++++++++++++++++----- 11 files changed, 135 insertions(+), 57 deletions(-) create mode 100644 src/db/schema21.sql diff --git a/src/comms.rs b/src/comms.rs index 14e4c6d0..f18bc0ce 100644 --- a/src/comms.rs +++ b/src/comms.rs @@ -25,7 +25,7 @@ pub enum ToOverlordMessage { RefreshFollowedMetadata, RankRelay(RelayUrl, u8), SaveSettings, - SetRelayPost(RelayUrl, bool), + SetRelayReadWrite(RelayUrl, bool, bool), SetThreadFeed(Id, Id, Option), Shutdown, UnlockKey(String), diff --git a/src/db/mod.rs b/src/db/mod.rs index c434f9d4..65bea272 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -103,7 +103,7 @@ macro_rules! apply_sql { } fn upgrade(db: &Connection, mut version: u16) -> Result<(), Error> { - let current_version = 20; + let current_version = 21; if version > current_version { panic!( "Database version {} is newer than this binary which expects version {}.", @@ -133,6 +133,7 @@ fn upgrade(db: &Connection, mut version: u16) -> Result<(), Error> { apply_sql!(db, version, 18, "schema18.sql"); apply_sql!(db, version, 19, "schema19.sql"); apply_sql!(db, version, 20, "schema20.sql"); + apply_sql!(db, version, 21, "schema21.sql"); tracing::info!("Database is at version {}", version); Ok(()) } diff --git a/src/db/person_relay.rs b/src/db/person_relay.rs index 7a244e03..739ce6cb 100644 --- a/src/db/person_relay.rs +++ b/src/db/person_relay.rs @@ -13,6 +13,8 @@ pub struct DbPersonRelay { pub last_suggested_nip23: Option, pub last_suggested_nip05: Option, pub last_suggested_bytag: Option, + pub read: bool, + pub write: bool, } impl DbPersonRelay { @@ -25,10 +27,11 @@ impl DbPersonRelay { let sql = format!( "SELECT person, relay, person_relay.last_fetched, \ last_suggested_kind2, last_suggested_kind3, last_suggested_nip23, \ - last_suggested_nip05, last_suggested_bytag \ + last_suggested_nip05, last_suggested_bytag, read, write \ FROM person_relay \ INNER JOIN relay ON person_relay.relay=relay.url \ - WHERE person IN ({}) ORDER BY person, relay.rank DESC, \ + WHERE person IN ({}) ORDER BY person, \ + person_relay.write DESC, relay.rank DESC, \ last_suggested_nip23 DESC, last_suggested_kind3 DESC, \ last_suggested_nip05 DESC, last_suggested_kind2 DESC, \ last_fetched DESC, last_suggested_bytag DESC", @@ -57,6 +60,8 @@ impl DbPersonRelay { last_suggested_nip23: row.get(5)?, last_suggested_nip05: row.get(6)?, last_suggested_bytag: row.get(7)?, + read: row.get(8)?, + write: row.get(9)?, }); } } @@ -71,8 +76,8 @@ impl DbPersonRelay { pub async fn insert(person_relay: DbPersonRelay) -> Result<(), Error> { let sql = "INSERT OR IGNORE INTO person_relay (person, relay, last_fetched, \ last_suggested_kind2, last_suggested_kind3, last_suggested_nip23, \ - last_suggested_nip05, last_suggested_bytag) \ - VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + last_suggested_nip05, last_suggested_bytag, read, write) \ + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; spawn_blocking(move || { let maybe_db = GLOBALS.db.blocking_lock(); @@ -88,6 +93,8 @@ impl DbPersonRelay { &person_relay.last_suggested_nip23, &person_relay.last_suggested_nip05, &person_relay.last_suggested_bytag, + &person_relay.read, + &person_relay.write, ))?; Ok::<(), Error>(()) }) @@ -229,7 +236,7 @@ impl DbPersonRelay { pub async fn get_best_relays(pubkey: PublicKeyHex) -> Result, Error> { let sql = "SELECT person, relay, last_suggested_nip23, last_suggested_kind3, \ last_suggested_nip05, last_fetched, last_suggested_kind2, \ - last_suggested_bytag \ + last_suggested_bytag, read, write \ FROM person_relay WHERE person=?"; let ranked_relays: Result, Error> = spawn_blocking(move || { @@ -253,6 +260,8 @@ impl DbPersonRelay { last_suggested_nip23: row.get(5)?, last_suggested_nip05: row.get(6)?, last_suggested_bytag: row.get(7)?, + read: row.get(8)?, + write: row.get(9)?, }; dbprs.push(dbpr); } diff --git a/src/db/relay.rs b/src/db/relay.rs index a5b9c9d5..06b412bc 100644 --- a/src/db/relay.rs +++ b/src/db/relay.rs @@ -11,7 +11,9 @@ pub struct DbRelay { pub rank: u64, pub last_connected_at: Option, pub last_general_eose_at: Option, - pub post: bool, + pub read: bool, + pub write: bool, + pub advertise: bool, } impl DbRelay { @@ -23,7 +25,9 @@ impl DbRelay { rank: 3, last_connected_at: None, last_general_eose_at: None, - post: false, + read: false, + write: false, + advertise: false, } } @@ -41,7 +45,7 @@ impl DbRelay { pub async fn fetch(criteria: Option<&str>) -> Result, Error> { let sql = "SELECT url, success_count, failure_count, rank, last_connected_at, \ - last_general_eose_at, post FROM relay" + last_general_eose_at, read, write, advertise FROM relay" .to_owned(); let sql = match criteria { None => sql, @@ -56,7 +60,6 @@ impl DbRelay { let mut rows = stmt.query([])?; let mut output: Vec = Vec::new(); while let Some(row) = rows.next()? { - let postint: u32 = row.get(6)?; let s: String = row.get(0)?; // just skip over invalid relay URLs if let Ok(url) = RelayUrl::try_from_str(&s) { @@ -67,7 +70,9 @@ impl DbRelay { rank: row.get(3)?, last_connected_at: row.get(4)?, last_general_eose_at: row.get(5)?, - post: (postint > 0), + read: row.get(6)?, + write: row.get(7)?, + advertise: row.get(8)?, }); } } @@ -90,15 +95,14 @@ impl DbRelay { pub async fn insert(relay: DbRelay) -> Result<(), Error> { let sql = "INSERT OR IGNORE INTO relay (url, success_count, failure_count, rank, \ - last_connected_at, last_general_eose_at, post) \ - VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"; + last_connected_at, last_general_eose_at, read, write, advertise) \ + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)"; spawn_blocking(move || { let maybe_db = GLOBALS.db.blocking_lock(); let db = maybe_db.as_ref().unwrap(); let mut stmt = db.prepare(sql)?; - let postint = i32::from(relay.post); stmt.execute(( &relay.url.0, &relay.success_count, @@ -106,7 +110,9 @@ impl DbRelay { &relay.rank, &relay.last_connected_at, &relay.last_general_eose_at, - &postint, + &relay.read, + &relay.write, + &relay.advertise, ))?; Ok::<(), Error>(()) }) @@ -117,21 +123,22 @@ impl DbRelay { pub async fn update(relay: DbRelay) -> Result<(), Error> { let sql = "UPDATE relay SET success_count=?, failure_count=?, rank=?, \ - last_connected_at=?, last_general_eose_at=?, post=? WHERE url=?"; + last_connected_at=?, last_general_eose_at=?, read=?, write=?, advertise=? WHERE url=?"; spawn_blocking(move || { let maybe_db = GLOBALS.db.blocking_lock(); let db = maybe_db.as_ref().unwrap(); let mut stmt = db.prepare(sql)?; - let postint = i32::from(relay.post); stmt.execute(( &relay.success_count, &relay.failure_count, &relay.rank, &relay.last_connected_at, &relay.last_general_eose_at, - &postint, + &relay.read, + &relay.write, + &relay.advertise, &relay.url.0, ))?; Ok::<(), Error>(()) @@ -162,13 +169,31 @@ impl DbRelay { Ok(()) } - pub async fn update_post(url: RelayUrl, post: bool) -> Result<(), Error> { - let sql = "UPDATE relay SET post = ? WHERE url = ?"; + pub async fn update_read_and_write( + url: RelayUrl, + read: bool, + write: bool, + ) -> Result<(), Error> { + let sql = "UPDATE relay SET read = ?, write = ? WHERE url = ?"; 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((&post, &url.0))?; + stmt.execute((&read, &write, &url.0))?; + Ok::<(), Error>(()) + }) + .await??; + + Ok(()) + } + + pub async fn update_advertise(url: RelayUrl, advertise: bool) -> Result<(), Error> { + let sql = "UPDATE relay SET advertise = ? WHERE url = ?"; + 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((&advertise, &url.0))?; Ok::<(), Error>(()) }) .await??; @@ -241,10 +266,10 @@ impl DbRelay { } pub async fn recommended_relay_for_reply(reply_to: Id) -> Result, Error> { - // Try to find a relay where the event was seen AND that I post to which + // Try to find a relay where the event was seen AND that I write to which // has a rank>1 let sql = "SELECT url FROM relay INNER JOIN event_seen ON relay.url=event_seen.relay \ - WHERE event_seen.event=? AND relay.post=1 AND relay.rank>1"; + WHERE event_seen.event=? AND relay.write=1 AND relay.rank>1"; let output: Option = spawn_blocking(move || { let maybe_db = GLOBALS.db.blocking_lock(); let db = maybe_db.as_ref().unwrap(); diff --git a/src/db/schema21.sql b/src/db/schema21.sql new file mode 100644 index 00000000..51975360 --- /dev/null +++ b/src/db/schema21.sql @@ -0,0 +1,8 @@ + +ALTER TABLE person_relay ADD COLUMN read INTEGER NOT NULL DEFAULT 0; +ALTER TABLE person_relay ADD COLUMN write INTEGER NOT NULL DEFAULT 0; +ALTER TABLE person RENAME COLUMN contact_list_last_received TO relay_list_last_received; +ALTER TABLE person ADD COLUMN relay_list_created_at INTEGER NOT NULL DEFAULT 0; +ALTER TABLE relay RENAME COLUMN post TO write; +ALTER TABLE relay ADD COLUMN read INTEGER NOT NULL DEFAULT 0; +ALTER TABLE relay ADD COLUMN advertise INTEGER NOT NULL DEFAULT 0; diff --git a/src/globals.rs b/src/globals.rs index b6255f58..713ef9c0 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -219,7 +219,7 @@ impl Globals { .relays .blocking_read() .iter() - .filter(|(_, r)| r.post) + .filter(|(_, r)| r.write) { profile.relays.push(url.to_unchecked_url()) } diff --git a/src/overlord/mod.rs b/src/overlord/mod.rs index 8e5149bd..dbb27db0 100644 --- a/src/overlord/mod.rs +++ b/src/overlord/mod.rs @@ -565,11 +565,12 @@ impl Overlord { GLOBALS.settings.read().await.save().await?; tracing::debug!("Settings saved."); } - ToOverlordMessage::SetRelayPost(relay_url, post) => { + ToOverlordMessage::SetRelayReadWrite(relay_url, read, write) => { if let Some(relay) = GLOBALS.relays.write().await.get_mut(&relay_url) { - relay.post = post; + relay.read = read; + relay.write = write; } - DbRelay::update_post(relay_url, post).await?; + DbRelay::update_read_and_write(relay_url, read, write).await?; } ToOverlordMessage::SetThreadFeed(id, referenced_by, previous_thread_parent) => { self.set_thread_feed(id, referenced_by, previous_thread_parent) @@ -649,6 +650,8 @@ impl Overlord { last_suggested_nip23: None, last_suggested_nip05: None, last_suggested_bytag: None, + read: true, + write: true, }) .await?; @@ -710,7 +713,7 @@ impl Overlord { .read() .await .iter() - .filter_map(|(_, r)| if r.post { Some(r.to_owned()) } else { None }) + .filter_map(|(_, r)| if r.write { Some(r.to_owned()) } else { None }) .collect(); for relay in relays { @@ -838,7 +841,7 @@ impl Overlord { .read() .await .iter() - .filter_map(|(_, r)| if r.post { Some(r.to_owned()) } else { None }) + .filter_map(|(_, r)| if r.write { Some(r.to_owned()) } else { None }) .collect(); for relay in relays { @@ -913,7 +916,7 @@ impl Overlord { .read() .await .iter() - .filter_map(|(_, r)| if r.post { Some(r.to_owned()) } else { None }) + .filter_map(|(_, r)| if r.write { Some(r.to_owned()) } else { None }) .collect(); for relay in relays { @@ -948,7 +951,7 @@ impl Overlord { .read() .await .iter() - .filter_map(|(_, r)| if r.post { Some(r.to_owned()) } else { None }) + .filter_map(|(_, r)| if r.write { Some(r.to_owned()) } else { None }) .collect(); for relay in relays { @@ -981,7 +984,7 @@ impl Overlord { .read() .await .iter() - .filter_map(|(_, r)| if r.post { Some(r.to_owned()) } else { None }) + .filter_map(|(_, r)| if r.write { Some(r.to_owned()) } else { None }) .collect(); for relay in relays { @@ -1025,7 +1028,7 @@ impl Overlord { .read() .await .iter() - .filter_map(|(_, r)| if r.post { Some(r.to_owned()) } else { None }) + .filter_map(|(_, r)| if r.write { Some(r.to_owned()) } else { None }) .collect(); for relay in relays { diff --git a/src/people.rs b/src/people.rs index 99841e63..a3d9f19f 100644 --- a/src/people.rs +++ b/src/people.rs @@ -24,7 +24,8 @@ pub struct DbPerson { pub followed: u8, pub followed_last_updated: i64, pub muted: u8, - pub contact_list_last_received: i64, + pub relay_list_last_received: i64, + pub relay_list_created_at: i64, } impl DbPerson { @@ -38,7 +39,8 @@ impl DbPerson { followed: 0, followed_last_updated: 0, muted: 0, - contact_list_last_received: 0, + relay_list_last_received: 0, + relay_list_created_at: 0, } } @@ -126,7 +128,7 @@ impl People { let mut output: Vec = Vec::new(); for person in self.people.iter().filter_map(|p| { if p.followed == 1 - && p.contact_list_last_received < one_day_ago + && p.relay_list_last_received < one_day_ago && among_these.contains(&p.pubkey) { Some(p) @@ -306,7 +308,8 @@ impl People { // who are muted, so they can be found and unmuted as necessary. let sql = "SELECT pubkey, metadata, metadata_at, nip05_valid, nip05_last_checked, \ - followed, followed_last_updated, muted, contact_list_last_received \ + followed, followed_last_updated, muted, relay_list_last_received, \ + relay_list_created_at \ FROM person WHERE followed=1 OR muted=1" .to_owned(); @@ -333,7 +336,8 @@ impl People { followed: row.get(5)?, followed_last_updated: row.get(6)?, muted: row.get(7)?, - contact_list_last_received: row.get(8)?, + relay_list_last_received: row.get(8)?, + relay_list_created_at: row.get(9)?, }); } Ok(output) @@ -814,22 +818,30 @@ impl People { Ok(()) } - pub async fn update_contact_list_last_received( + pub async fn update_relay_list_stamps( &self, pubkeyhex: PublicKeyHex, + mut created_at: i64, ) -> Result<(), Error> { let now = Unixtime::now().unwrap().0; if let Some(mut person) = self.people.get_mut(&pubkeyhex) { - person.contact_list_last_received = now; + created_at = created_at.max(person.relay_list_created_at); + person.relay_list_last_received = now; + person.relay_list_created_at = created_at; + } else { + tracing::warn!("FIXME: RelayList for person we don't have. We should create them."); + return Ok(()); } task::spawn_blocking(move || { let maybe_db = GLOBALS.db.blocking_lock(); let db = maybe_db.as_ref().unwrap(); - let mut stmt = - db.prepare("UPDATE person SET contact_list_last_received=? WHERE pubkey=?")?; - stmt.execute((&now, pubkeyhex.as_str()))?; + let mut stmt = db.prepare( + "UPDATE person SET relay_list_last_received=?, \ + relay_list_created_at=? WHERE pubkey=?", + )?; + stmt.execute((&now, &created_at, pubkeyhex.as_str()))?; Ok(()) }) .await? @@ -910,7 +922,8 @@ impl People { let sql = "SELECT pubkey, metadata, metadata_at, \ nip05_valid, nip05_last_checked, \ followed, followed_last_updated, muted, \ - contact_list_last_received FROM person" + relay_list_last_received, relay_list_created_at \ + FROM person" .to_owned(); let sql = match criteria { None => sql, @@ -940,7 +953,8 @@ impl People { followed: row.get(5)?, followed_last_updated: row.get(6)?, muted: row.get(7)?, - contact_list_last_received: row.get(8)?, + relay_list_last_received: row.get(8)?, + relay_list_created_at: row.get(9)?, }); } Ok(output) @@ -963,8 +977,8 @@ impl People { async fn fetch_many(pubkeys: &[&PublicKeyHex]) -> Result, Error> { let sql = format!( "SELECT pubkey, metadata, metadata_at, nip05_valid, nip05_last_checked, \ - followed, followed_last_updated, muted, contact_list_last_received \ - FROM person WHERE pubkey IN ({})", + followed, followed_last_updated, muted, relay_list_last_received, \ + relay_list_created_at FROM person WHERE pubkey IN ({})", repeat_vars(pubkeys.len()) ); @@ -1000,7 +1014,8 @@ impl People { followed: row.get(5)?, followed_last_updated: row.get(6)?, muted: row.get(7)?, - contact_list_last_received: row.get(8)?, + relay_list_last_received: row.get(8)?, + relay_list_created_at: row.get(9)?, }); } diff --git a/src/process.rs b/src/process.rs index 4f57b03b..dcdaa7b4 100644 --- a/src/process.rs +++ b/src/process.rs @@ -215,7 +215,7 @@ pub async fn process_new_event( if event.kind == EventKind::ContactList { GLOBALS .people - .update_contact_list_last_received(event.pubkey.into()) + .update_relay_list_stamps(event.pubkey.into(), event.created_at.0) .await?; if let Some(pubkey) = GLOBALS.signer.public_key() { diff --git a/src/ui/feed/post.rs b/src/ui/feed/post.rs index 6d4d9804..4d37d4da 100644 --- a/src/ui/feed/post.rs +++ b/src/ui/feed/post.rs @@ -23,7 +23,7 @@ pub(super) fn posting_area( } ui.label(" to post."); }); - } else if !GLOBALS.relays.blocking_read().iter().any(|(_, r)| r.post) { + } else if !GLOBALS.relays.blocking_read().iter().any(|(_, r)| r.write) { ui.horizontal_wrapped(|ui| { ui.label("You need to "); if ui.link("choose relays").clicked() { diff --git a/src/ui/relays/all.rs b/src/ui/relays/all.rs index 269fd2db..104e96f9 100644 --- a/src/ui/relays/all.rs +++ b/src/ui/relays/all.rs @@ -40,7 +40,7 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr // TBD time how long this takes. We don't want expensive code in the UI let mut relays = GLOBALS.relays.blocking_read().clone(); let mut relays: Vec = relays.drain().map(|(_, relay)| relay).collect(); - relays.sort_by(|a, b| b.post.cmp(&a.post).then(a.url.cmp(&b.url))); + relays.sort_by(|a, b| b.write.cmp(&a.write).then(a.url.cmp(&b.url))); ui.with_layout(Layout::bottom_up(Align::Center), |ui| { ui.add_space(18.0); @@ -62,6 +62,7 @@ fn relay_table(ui: &mut Ui, relays: &mut [DbRelay], id: &'static str) { .column(Column::auto().resizable(true)) .column(Column::auto().resizable(true)) .column(Column::auto().resizable(true)) + .column(Column::auto().resizable(true)) .column(Column::remainder()) .header(20.0, |mut header| { header.col(|ui| { @@ -81,7 +82,12 @@ fn relay_table(ui: &mut Ui, relays: &mut [DbRelay], id: &'static str) { .on_hover_text("This only counts events served after EOSE, as they mark where we can pick up from next time."); }); header.col(|ui| { - ui.heading("Write"); + ui.heading("Read") + .on_hover_text("Read for events with mentions of you on these relays. It is recommended to have a few." ); + }); + header.col(|ui| { + ui.heading("Write") + .on_hover_text("Write your events to these relays. It is recommended to have a few." ); }); header.col(|ui| { ui.heading("Read rank") @@ -112,14 +118,25 @@ fn relay_table(ui: &mut Ui, relays: &mut [DbRelay], id: &'static str) { } }); row.col(|ui| { - let mut post = relay.post; // checkbox needs a mutable state variable. - if ui.checkbox(&mut post, "") - .on_hover_text("If selected, posts you create will be sent to this relay. But you have to press [SAVE CHANGES] at the bottom of this page.") + let mut read = relay.read; // checkbox needs a mutable state variable. + if ui.checkbox(&mut read, "") + .on_hover_text("If selected, we will search for posts mentioning you on this relay.") .clicked() { let _ = GLOBALS .to_overlord - .send(ToOverlordMessage::SetRelayPost(relay.url.clone(), post)); + .send(ToOverlordMessage::SetRelayReadWrite(relay.url.clone(), read, relay.write)); + } + }); + row.col(|ui| { + let mut write = relay.write; // checkbox needs a mutable state variable. + if ui.checkbox(&mut write, "") + .on_hover_text("If selected, posts you create will be sent to this relay.") + .clicked() + { + let _ = GLOBALS + .to_overlord + .send(ToOverlordMessage::SetRelayReadWrite(relay.url.clone(), relay.read, write)); } }); row.col(|ui| {