diff --git a/Cargo.lock b/Cargo.lock index 8226a6d9..77188d19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1679,6 +1679,7 @@ dependencies = [ name = "gossip" version = "0.3.1-unstable" dependencies = [ + "async-recursion", "base64 0.13.1", "dirs", "eframe", diff --git a/Cargo.toml b/Cargo.toml index 3b56e34c..99bf111e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +async-recursion = "1.0" base64 = "0.13" dirs = "4.0" eframe = { version = "0.20", features = [ "dark-light", "persistence" ] } diff --git a/src/globals.rs b/src/globals.rs index 5071f15b..b5e5e760 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -2,7 +2,9 @@ use crate::comms::BusMessage; use crate::db::{DbPerson, DbPersonRelay, DbRelay}; use crate::error::Error; use crate::feed_event::FeedEvent; +use crate::relationship::Relationship; use crate::settings::Settings; +use async_recursion::async_recursion; use nostr_types::{Event, EventKind, Id, Metadata, PublicKey, PublicKeyHex, Tag, Unixtime, Url}; use rusqlite::Connection; use std::collections::HashMap; @@ -31,6 +33,18 @@ pub struct Globals { /// All nostr event related data, keyed by the event Id pub feed_events: Mutex>, + /// All nostr events, keyed by the event Id + /// This will replace feed_events. + pub events: Mutex>, + + /// All relationships between events + /// This will also replace feed_events. + pub relationships: Mutex>>, + + /// The date of the latest reply. Only reply relationships count, not reactions, + /// deletions, or quotes + pub last_reply: Mutex>, + /// Desired events, referred to by others, with possible URLs where we can /// get them. We may already have these, but if not we should ask for them. pub desired_events: Mutex>>, @@ -61,6 +75,9 @@ lazy_static! { to_overlord, from_minions: Mutex::new(Some(from_minions)), feed_events: Mutex::new(HashMap::new()), + events: Mutex::new(HashMap::new()), + relationships: Mutex::new(HashMap::new()), + last_reply: Mutex::new(HashMap::new()), desired_events: Mutex::new(HashMap::new()), people: Mutex::new(HashMap::new()), need_password: AtomicBool::new(false), @@ -136,6 +153,83 @@ impl Globals { feed.iter().map(|e| e.id).collect() } + + #[allow(dead_code)] + pub async fn store_desired_event(id: Id, url: Option) { + let mut desired_events = GLOBALS.desired_events.lock().await; + desired_events + .entry(id) + .and_modify(|urls| { + if let Some(ref u) = url { + urls.push(u.to_owned()); + } + }) + .or_insert_with(|| if let Some(u) = url { vec![u] } else { vec![] }); + } + + #[allow(dead_code)] + pub async fn add_relationship(id: Id, related: Id, relationship: Relationship) { + let r = (related, relationship); + let mut relationships = GLOBALS.relationships.lock().await; + relationships + .entry(id) + .and_modify(|vec| { + if !vec.contains(&r) { + vec.push(r.clone()); + } + }) + .or_insert_with(|| vec![r]); + } + + #[allow(dead_code)] + #[async_recursion] + pub async fn update_last_reply(id: Id, time: Unixtime) { + { + let mut last_reply = GLOBALS.last_reply.lock().await; + last_reply + .entry(id) + .and_modify(|lasttime| { + if time > *lasttime { + *lasttime = time; + } + }) + .or_insert_with(|| time); + } // drops lock + + // Recurse upwards + if let Some(event) = GLOBALS.events.lock().await.get(&id).cloned() { + if let Some((id, _maybe_url)) = event.replies_to() { + Self::update_last_reply(id, event.created_at).await; + } + } + } + + // FIXME - this allows people to react many times to the same event, and + // it counts them all! + #[allow(dead_code)] + pub async fn get_reactions(id: Id) -> HashMap { + let mut output: HashMap = HashMap::new(); + + if let Some(relationships) = GLOBALS.relationships.lock().await.get(&id).cloned() { + for (_id, relationship) in relationships.iter() { + if let Relationship::Reaction(reaction) = relationship { + if let Some(ch) = reaction.chars().next() { + output + .entry(ch) + .and_modify(|count| *count += 1) + .or_insert_with(|| 1); + } else { + output + .entry('+') // if empty, presumed to be an upvote + .and_modify(|count| *count += 1) + .or_insert_with(|| 1); + } + } + } + } + + output + } } pub async fn add_event(event: &Event) -> Result<(), Error> {