diff --git a/src/functions/messages.rs b/src/functions/messages.rs index 609b3dc..922d2b9 100644 --- a/src/functions/messages.rs +++ b/src/functions/messages.rs @@ -1,8 +1,14 @@ use anyhow::Result; use nostr_sdk::prelude::*; -use crate::nips::nip17; +// Importiere das Message Struct aus nip17! +use crate::nips::nip17::{self, Message}; pub async fn send_private_message(client: &Client, receiver_pubkey: &str, message: &str) -> Result { let receiver = PublicKey::parse(receiver_pubkey)?; nip17::send_dm(client, receiver, message).await +} + +// Rückgabetyp ist Vec +pub async fn get_private_messages(client: &Client, contact_npub: &str) -> Result> { + nip17::get_dm_messages(client, contact_npub).await } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index fa9f556..8796d08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ use nostr_sdk::prelude::*; // Wir importieren die Funktionen, um Tipparbeit zu sparen use crate::functions::{new, messages, relays, get_contacts, create_contact}; +use crate::nips::nip17::Message; pub struct EasyNostr { client: Client, @@ -24,6 +25,10 @@ impl EasyNostr { messages::send_private_message(&self.client, receiver_pubkey, message).await } + pub async fn get_private_messages(&self, contact_npub: &str) -> Result> { + messages::get_private_messages(&self.client, contact_npub).await + } + /// Fügt Relays hinzu und verbindet pub async fn add_relays(&self, urls: Vec<&str>) -> Result<()> { relays::add_relays(&self.client, urls).await diff --git a/src/nips/nip17.rs b/src/nips/nip17.rs index e4bfa7f..41eeb68 100644 --- a/src/nips/nip17.rs +++ b/src/nips/nip17.rs @@ -1,7 +1,95 @@ use nostr_sdk::prelude::*; -use anyhow::Result; // <--- Hinzufügen +use anyhow::Result; +use std::time::Duration; +/// UI Message Struktur +#[derive(Debug, Clone)] +pub struct Message { + pub id: EventId, + pub sender: PublicKey, + pub content: String, + pub created_at: Timestamp, + pub is_incoming: bool, +} + +/// Direktnachricht senden pub async fn send_dm(client: &Client, receiver: PublicKey, message: &str) -> Result { let output = client.send_private_msg(receiver, message, None).await?; Ok(*output.id()) -} \ No newline at end of file +} + +/// Direktnachrichten abrufen +pub async fn get_dm_messages(client: &Client, contact_npub: &str) -> Result> { + let signer = client.signer().await?; + let my_pubkey = signer.get_public_key().await?; + let contact_pubkey = PublicKey::parse(contact_npub)?; + + // --- Einzelne Filter erstellen --- + let filter_in = Filter::new() + .kinds([Kind::GiftWrap, Kind::EncryptedDirectMessage]) + .pubkey(my_pubkey) + .since(Timestamp::now() - Duration::from_secs(60 * 60 * 24 * 30)) + .limit(500); + + let filter_out = Filter::new() + .kind(Kind::EncryptedDirectMessage) + .author(my_pubkey) + .pubkey(contact_pubkey) + .limit(100); + + // --- Abrufen: zwei einzelne fetches, dann Ergebnisse mergen --- + let mut events = client.fetch_events(filter_in, Duration::from_secs(10)).await?; + let more_events = client.fetch_events(filter_out, Duration::from_secs(10)).await?; + events.extend(more_events.into_iter()); + + let mut messages: Vec = Vec::new(); + + for event in events.iter() { + // === NIP-17 (Gift Wrap) Verarbeitung === + if event.kind == Kind::GiftWrap { + if let Ok(unwrapped) = client.unwrap_gift_wrap(event).await { + let rumor = unwrapped.rumor; + if rumor.pubkey == contact_pubkey && rumor.kind == Kind::TextNote { + messages.push(Message { + id: event.id, + sender: rumor.pubkey, + content: rumor.content.clone(), + created_at: rumor.created_at, + is_incoming: true, + }); + } + } + } + // === NIP-04 (Legacy) Verarbeitung === + else if event.kind == Kind::EncryptedDirectMessage { + // TagStandard::PublicKey ist ein Struct-Variant: Felder mit Struct-Syntax matchen + let has_contact_tag = event.tags.iter().any(|t| { + match t.as_standardized() { + Some(TagStandard::PublicKey { public_key, .. }) => *public_key == contact_pubkey, + _ => false, + } + }); + + let is_incoming = event.pubkey == contact_pubkey; + let is_outgoing = event.pubkey == my_pubkey && has_contact_tag; + + if is_incoming || is_outgoing { + let counterparty = if is_incoming { event.pubkey } else { contact_pubkey }; + if let Ok(content) = signer.nip04_decrypt(&counterparty, &event.content).await { + messages.push(Message { + id: event.id, + sender: event.pubkey, + content, + created_at: event.created_at, + is_incoming, + }); + } + } + } + } + + // Nachrichten chronologisch sortieren + messages.sort_by(|a, b| a.created_at.cmp(&b.created_at)); + + Ok(messages) +}