Skip to main content

dialog_lib/
watch.rs

1use crate::{Dialog, Note, Result};
2use nostr_sdk::prelude::*;
3use std::collections::HashSet;
4use tokio::sync::mpsc;
5
6impl Dialog {
7    pub async fn watch_notes(&self) -> Result<mpsc::Receiver<Note>> {
8        let (tx, rx) = mpsc::channel(100);
9
10        let client = self.client.clone();
11        let keys = self.keys.clone();
12        let pubkey = self.keys.public_key();
13
14        // Set up subscription
15        let filter = Filter::new()
16            .author(pubkey)
17            .kind(Kind::from(1059))
18            .since(Timestamp::now());
19
20        eprintln!("DEBUG: Creating subscription with filter: {filter:?}");
21        let output = self.client.subscribe(vec![filter], None).await?;
22        let sub_id = output.val;
23        eprintln!("DEBUG: Subscription created with id: {sub_id}");
24
25        tokio::spawn(async move {
26            let mut notifications = client.notifications();
27            let mut seen_ids = HashSet::new();
28
29            eprintln!("DEBUG: Watch task started, entering loop");
30            loop {
31                eprintln!("DEBUG: Waiting for notification...");
32                match notifications.recv().await {
33                    Ok(RelayPoolNotification::Message { message, .. }) => {
34                        if let RelayMessage::Event {
35                            subscription_id,
36                            event,
37                        } = message
38                        {
39                            eprintln!(
40                                "DEBUG: Got event from subscription: {subscription_id} (our id: {sub_id})",
41                            );
42                            if subscription_id == sub_id
43                                && event.kind == Kind::from(1059)
44                                && event.pubkey == pubkey
45                                && !seen_ids.contains(&event.id)
46                            {
47                                if let Ok(decrypted) = decrypt_event(&keys, &event) {
48                                    let note = Note {
49                                        id: event.id,
50                                        text: decrypted,
51                                        tags: extract_tags(&event),
52                                        created_at: event.created_at,
53                                        is_read: false,  // New notes are unread
54                                        is_synced: true, // If we got it from relay, it's synced
55                                    };
56
57                                    seen_ids.insert(event.id);
58                                    let _ = tx.send(note).await;
59                                    eprintln!("DEBUG: Sent note to channel");
60                                }
61                            }
62                        }
63                    }
64                    Ok(RelayPoolNotification::Event { event, .. }) => {
65                        // Try the old pattern too just in case
66                        eprintln!("DEBUG: Got direct event notification");
67                        if event.kind == Kind::from(1059)
68                            && event.pubkey == pubkey
69                            && !seen_ids.contains(&event.id)
70                        {
71                            if let Ok(decrypted) = decrypt_event(&keys, &event) {
72                                let note = Note {
73                                    id: event.id,
74                                    text: decrypted,
75                                    tags: extract_tags(&event),
76                                    created_at: event.created_at,
77                                    is_read: false,  // New notes are unread
78                                    is_synced: true, // If we got it from relay, it's synced
79                                };
80
81                                seen_ids.insert(event.id);
82                                let _ = tx.send(note).await;
83                            }
84                        }
85                    }
86                    Ok(other) => {
87                        eprintln!("DEBUG: Got other notification: {other:?}");
88                        continue;
89                    }
90                    Err(e) => {
91                        eprintln!("DEBUG: Error receiving notification: {e:?}");
92                        break;
93                    }
94                }
95            }
96            eprintln!("DEBUG: Watch loop exited!");
97        });
98
99        eprintln!("DEBUG: Returning receiver");
100        Ok(rx)
101    }
102}
103
104// Helper function to decrypt events
105fn decrypt_event(keys: &Keys, event: &Event) -> Result<String> {
106    let decrypted = nip44::decrypt(keys.secret_key(), &keys.public_key(), &event.content)?;
107    Ok(decrypted)
108}
109
110// Helper function to extract tags
111fn extract_tags(event: &Event) -> Vec<String> {
112    event
113        .tags
114        .iter()
115        .filter_map(|tag| {
116            if let Some(TagStandard::Hashtag(t)) = tag.as_standardized() {
117                Some(t.to_string())
118            } else {
119                None
120            }
121        })
122        .collect()
123}