diff --git a/src/main.rs b/src/main.rs index 39f3844d..5715be9d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ mod error; mod feed_event; mod globals; mod overlord; +mod process; mod relationship; mod settings; mod ui; diff --git a/src/process.rs b/src/process.rs new file mode 100644 index 00000000..4c2abbf9 --- /dev/null +++ b/src/process.rs @@ -0,0 +1,199 @@ +use crate::db::{DbEvent, DbEventHashtag, DbEventRelationship, DbEventSeen, DbEventTag, DbPerson}; +use crate::error::Error; +use crate::globals::{Globals, GLOBALS}; +use crate::relationship::Relationship; +use nostr_types::{Event, EventKind, Metadata, Unixtime, Url}; + +// This processes a new event, saving the results into the database +// and also populating the GLOBALS maps. +#[allow(dead_code)] +pub async fn process_new_event(event: &Event, from_relay: bool, seen_on: Option) -> Result<(), Error> { + // Save the event into the database + if from_relay { + // Convert a nostr Event into a DbEvent + let db_event = DbEvent { + id: event.id.into(), + raw: serde_json::to_string(&event)?, + pubkey: event.pubkey.into(), + created_at: event.created_at.0, + kind: event.kind.into(), + content: event.content.clone(), + ots: event.ots.clone(), + }; + + // Save into event table + DbEvent::insert(db_event).await?; + } + + // Save event_seen data + if from_relay { + if let Some(url) = seen_on { + let db_event_seen = DbEventSeen { + event: event.id.as_hex_string(), + relay: url.0, + when_seen: Unixtime::now()?.0 as u64, + }; + DbEventSeen::replace(db_event_seen).await?; + } + } + + // Insert the event into globals map + { + let mut events = GLOBALS.events.lock().await; + let _ = events.insert(event.id, event.clone()); + } + + // Save the tags into event_tag table + if from_relay { + for (seq, tag) in event.tags.iter().enumerate() { + // convert to vec of strings + let v: Vec = serde_json::from_str(&serde_json::to_string(&tag)?)?; + + let db_event_tag = DbEventTag { + event: event.id.as_hex_string(), + seq: seq as u64, + label: v.get(0).cloned(), + field0: v.get(1).cloned(), + field1: v.get(2).cloned(), + field2: v.get(3).cloned(), + field3: v.get(4).cloned(), + }; + DbEventTag::insert(db_event_tag).await?; + } + } + + // Save event relationships + { + // replies to + if let Some((id, maybe_url)) = event.replies_to() { + if from_relay { + let db_event_relationship = DbEventRelationship { + original: event.id.as_hex_string(), + referring: id.as_hex_string(), + relationship: "reply".to_string(), + content: None, + }; + db_event_relationship.insert().await?; + } + + // Insert desired event if relevant + if !GLOBALS.events.lock().await.contains_key(&id) { + Globals::store_desired_event(id, maybe_url).await; + } + + // Insert into relationships + Globals::add_relationship(id, event.id, Relationship::Reply).await; + + // Update last_reply + Globals::update_last_reply(id, event.created_at); + } + + // reacts to + if let Some((id, reaction, maybe_url)) = event.reacts_to() { + if from_relay { + let db_event_relationship = DbEventRelationship { + original: event.id.as_hex_string(), + referring: id.as_hex_string(), + relationship: "reaction".to_string(), + content: Some(reaction.clone()), + }; + db_event_relationship.insert().await?; + } + + // Insert desired event if relevant + if !GLOBALS.events.lock().await.contains_key(&id) { + Globals::store_desired_event(id, maybe_url).await; + } + + // Insert into relationships + Globals::add_relationship(id, event.id, Relationship::Reaction(reaction)).await; + } + + // deletes + if let Some((ids, reason)) = event.deletes() { + for id in ids { + if from_relay { + let db_event_relationship = DbEventRelationship { + original: event.id.as_hex_string(), + referring: id.as_hex_string(), + relationship: "deletion".to_string(), + content: Some(reason.clone()), + // FIXME: this table should have one more column for optional data + }; + db_event_relationship.insert().await?; + } + + // since it is a delete, we don't actually desire the event. + + // Insert into relationships + Globals::add_relationship(id, event.id, Relationship::Deletion(reason.clone())) + .await; + } + } + } + + // Save event_hashtags + if from_relay { + let hashtags = event.hashtags(); + for hashtag in hashtags { + let db_event_hashtag = DbEventHashtag { + event: event.id.as_hex_string(), + hashtag: hashtag.clone(), + }; + db_event_hashtag.insert().await?; + } + } + + // If metadata, update person + if event.kind == EventKind::Metadata { + let metadata: Metadata = serde_json::from_str(&event.content)?; + let metadata2 = metadata.clone(); + + if from_relay { + DbPerson::update_metadata(event.pubkey.into(), metadata.clone(), event.created_at) + .await?; + } + + { + let mut people = GLOBALS.people.lock().await; + people + .entry(event.pubkey) + .and_modify(|person| { + if let Some(metadata_at) = person.metadata_at { + if event.created_at.0 <= metadata_at { + // Old metadata. Ignore it + return; + } + } + + // Update the metadata + person.name = metadata.name; + person.about = metadata.about; + person.picture = metadata.picture; + if person.dns_id != metadata.nip05 { + person.dns_id = metadata.nip05; + person.dns_id_valid = 0; // changed, so reset to invalid + person.dns_id_last_checked = None; // we haven't checked this one yet + } + person.metadata_at = Some(event.created_at.0); + }) + .or_insert_with(|| { + let mut person = DbPerson::new(event.pubkey.into()); + person.name = metadata2.name; + person.about = metadata2.about; + person.picture = metadata2.picture; + person.dns_id = metadata2.nip05; + person.dns_id_valid = 0; + person.dns_id_last_checked = None; // we haven't checked this one yet + person.metadata_at = Some(event.created_at.0); + person + }); + } + } + + // FIXME: Handle EventKind::RecommendedRelay + + // FIXME: Handle EventKind::ContactList + + Ok(()) +}