.
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
use std::cmp::Reverse;
|
||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||
use std::hash::{DefaultHasher, Hash, Hasher};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, LazyLock, RwLock};
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{Context as AnyhowContext, Error, anyhow};
|
||||
use anyhow::{Error, anyhow};
|
||||
use common::EventExt;
|
||||
use fuzzy_matcher::FuzzyMatcher;
|
||||
use fuzzy_matcher::skim::SkimMatcherV2;
|
||||
@@ -301,7 +300,7 @@ impl ChatRegistry {
|
||||
Signal::Eose => {
|
||||
this.update(cx, |this, cx| {
|
||||
this.tracking.store(false, Ordering::Release);
|
||||
this.sort(cx);
|
||||
this.get_rooms(cx);
|
||||
})?;
|
||||
}
|
||||
Signal::Error(failed) => {
|
||||
@@ -642,37 +641,21 @@ impl ChatRegistry {
|
||||
let client = nostr.read(cx).client();
|
||||
|
||||
cx.background_spawn(async move {
|
||||
// Get contacts
|
||||
let contacts = client
|
||||
.database()
|
||||
.contacts_public_keys(public_key)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
|
||||
// Construct authored filter
|
||||
let authored_filter = Filter::new()
|
||||
// Query all cached rumor events (works with both old and new cache formats)
|
||||
let filter = Filter::new()
|
||||
.kind(Kind::ApplicationSpecificData)
|
||||
.custom_tag(SingleLetterTag::lowercase(Alphabet::A), public_key);
|
||||
.custom_tag(SingleLetterTag::lowercase(Alphabet::K), "14");
|
||||
let events = client.database().query(filter).await?;
|
||||
|
||||
// Get all authored events
|
||||
let authored = client.database().query(authored_filter).await?;
|
||||
|
||||
// Construct addressed filter
|
||||
let addressed_filter = Filter::new()
|
||||
.kind(Kind::ApplicationSpecificData)
|
||||
.custom_tag(SingleLetterTag::lowercase(Alphabet::P), public_key);
|
||||
|
||||
// Get all addressed events
|
||||
let addressed = client.database().query(addressed_filter).await?;
|
||||
|
||||
// Merge authored and addressed events
|
||||
let events = authored.merge(addressed);
|
||||
|
||||
// Collect results
|
||||
let mut rooms: HashSet<Room> = HashSet::new();
|
||||
let mut grouped: HashMap<u64, Vec<UnsignedEvent>> = HashMap::new();
|
||||
|
||||
// Process each event and group by room hash
|
||||
for raw in events.into_iter() {
|
||||
if let Ok(rumor) = UnsignedEvent::from_json(&raw.content)
|
||||
&& rumor.tags.public_keys().peekable().peek().is_some()
|
||||
@@ -767,6 +750,11 @@ async fn extract_rumor(
|
||||
let unwrapped = try_unwrap_with(signer, gift_wrap).await?;
|
||||
let mut rumor = unwrapped.rumor;
|
||||
|
||||
// Verify rumor author matches the seal sender (as per mobile implementation)
|
||||
if rumor.pubkey != unwrapped.sender {
|
||||
return Err(anyhow!("Rumor author does not match seal sender"));
|
||||
}
|
||||
|
||||
// Generate event id for the rumor if it doesn't have one
|
||||
rumor.ensure_id();
|
||||
|
||||
@@ -807,39 +795,20 @@ async fn try_unwrap_with(
|
||||
|
||||
/// Stores an unwrapped event in local database with reference to original
|
||||
async fn set_rumor(client: &Client, id: EventId, rumor: &UnsignedEvent) -> Result<(), Error> {
|
||||
let rumor_id = rumor.id.context("Rumor is missing an event id")?;
|
||||
let author = rumor.pubkey;
|
||||
let conversation = conversation_id(rumor);
|
||||
let room_id = rumor.uniq_id().to_string();
|
||||
|
||||
let mut tags = rumor.tags.clone().to_vec();
|
||||
let tags = vec![
|
||||
Tag::identifier(id),
|
||||
Tag::public_key(rumor.pubkey),
|
||||
Tag::custom("r", [room_id]),
|
||||
Tag::custom("k", ["14"]),
|
||||
];
|
||||
|
||||
// Add a unique identifier
|
||||
tags.push(Tag::identifier(id));
|
||||
|
||||
// Add a reference to the rumor's author
|
||||
tags.push(Tag::custom("a", [author]));
|
||||
|
||||
// Add a conversation id
|
||||
tags.push(Tag::custom("c", [conversation.to_string()]));
|
||||
|
||||
// Add a reference to the rumor's id
|
||||
tags.push(Tag::event(rumor_id));
|
||||
|
||||
// Add references to the rumor's participants
|
||||
for receiver in rumor.tags.public_keys() {
|
||||
tags.push(Tag::custom("P", [receiver]));
|
||||
}
|
||||
|
||||
// Convert rumor to json
|
||||
let content = rumor.as_json();
|
||||
|
||||
// Construct the event
|
||||
let event = EventBuilder::new(Kind::ApplicationSpecificData, content)
|
||||
let event = EventBuilder::new(Kind::ApplicationSpecificData, rumor.as_json())
|
||||
.tags(tags)
|
||||
.finalize_async(&*LOCAL_KEYS)
|
||||
.await?;
|
||||
|
||||
// Save the event to the database
|
||||
client.database().save_event(&event).await?;
|
||||
|
||||
Ok(())
|
||||
@@ -847,10 +816,7 @@ async fn set_rumor(client: &Client, id: EventId, rumor: &UnsignedEvent) -> Resul
|
||||
|
||||
/// Retrieves a previously unwrapped event from local database
|
||||
async fn get_rumor(client: &Client, gift_wrap: EventId) -> Result<UnsignedEvent, Error> {
|
||||
let filter = Filter::new()
|
||||
.kind(Kind::ApplicationSpecificData)
|
||||
.identifier(gift_wrap)
|
||||
.limit(1);
|
||||
let filter = Filter::new().identifier(gift_wrap).limit(1);
|
||||
|
||||
if let Some(event) = client.database().query(filter).await?.first_owned() {
|
||||
UnsignedEvent::from_json(event.content).map_err(|e| anyhow!(e))
|
||||
@@ -858,15 +824,3 @@ async fn get_rumor(client: &Client, gift_wrap: EventId) -> Result<UnsignedEvent,
|
||||
Err(anyhow!("Event is not cached yet."))
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the conversation ID for a given rumor (message).
|
||||
fn conversation_id(rumor: &UnsignedEvent) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
let mut pubkeys: Vec<PublicKey> = rumor.tags.public_keys().collect();
|
||||
pubkeys.push(rumor.pubkey);
|
||||
pubkeys.sort();
|
||||
pubkeys.dedup();
|
||||
pubkeys.hash(&mut hasher);
|
||||
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
@@ -398,12 +398,12 @@ impl Room {
|
||||
pub fn get_messages(&self, cx: &App) -> Task<Result<Vec<UnsignedEvent>, Error>> {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let client = nostr.read(cx).client();
|
||||
let conversation_id = self.id.to_string();
|
||||
let room_id = self.id.to_string();
|
||||
|
||||
cx.background_spawn(async move {
|
||||
let filter = Filter::new()
|
||||
.kind(Kind::ApplicationSpecificData)
|
||||
.custom_tag(SingleLetterTag::lowercase(Alphabet::C), conversation_id);
|
||||
.custom_tag(SingleLetterTag::lowercase(Alphabet::R), room_id);
|
||||
|
||||
let messages = client
|
||||
.database()
|
||||
@@ -411,10 +411,6 @@ impl Room {
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter_map(|event| UnsignedEvent::from_json(&event.content).ok())
|
||||
.filter(|event| {
|
||||
// Only process private direct messages and file messages
|
||||
event.kind == Kind::PrivateDirectMessage || event.kind == Kind::Custom(15)
|
||||
})
|
||||
.sorted_by_key(|message| message.created_at)
|
||||
.collect();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user