p2p_chat/sync/engine/mailbox/
processing.rs

1//! This module contains logic for processing messages fetched from mailboxes.
2use anyhow::Result;
3use tracing::{debug, error, trace};
4use uuid::Uuid;
5use std::ops::Deref;
6
7use crate::cli::UiNotification;
8use crate::types::{ChatRequest, DeliveryConfirmation, DeliveryStatus, EncryptedMessage, Message};
9
10use super::super::SyncEngine;
11
12impl SyncEngine {
13    /// Processes a list of encrypted messages fetched from mailboxes.
14    ///
15    /// This function iterates through the messages, decrypts them, marks them as seen,
16    /// stores them in the history, sends delivery confirmations, and notifies the UI.
17    ///
18    /// # Arguments
19    ///
20    /// * `messages` - A `Vec` of `EncryptedMessage`s fetched from a mailbox.
21    ///
22    /// # Returns
23    ///
24    /// A `Vec` of `Uuid`s representing the IDs of messages that were successfully processed.
25    ///
26    /// # Errors
27    ///
28    /// This function will return an error if message decryption, storage, or processing fails.
29    pub async fn process_mailbox_messages(
30        &self,
31        messages: Vec<EncryptedMessage>,
32    ) -> Result<Vec<Uuid>> {
33        let mut processed_msg_ids = Vec::new();
34
35        for encrypted_msg in messages {
36            // Skip messages that have already been seen.
37            if self.seen.is_seen(&encrypted_msg.id).await? {
38                trace!(
39                    "Message {} already seen, adding to ACK list",
40                    encrypted_msg.id
41                );
42                processed_msg_ids.push(encrypted_msg.id);
43                continue;
44            }
45
46            // Reconstruct the message from the encrypted version.
47            let message = self
48                .reconstruct_message_from_mailbox(&encrypted_msg)
49                .await?;
50
51            // Store the message in history.
52            if let Err(e) = self.history.store_message(message.clone()).await {
53                error!(
54                    "Failed to store mailbox message {} in history: {}",
55                    encrypted_msg.id, e
56                );
57                continue;
58            }
59
60            // Mark the message as seen.
61            if let Err(e) = self.seen.mark_seen(encrypted_msg.id).await {
62                error!("Failed to mark message {} as seen: {}", encrypted_msg.id, e);
63            }
64
65            // Send delivery confirmation back to sender.
66            let confirmation = DeliveryConfirmation {
67                original_message_id: encrypted_msg.id,
68                timestamp: chrono::Utc::now().timestamp_millis(),
69            };
70
71            let confirmation_request = ChatRequest::DeliveryConfirmation { confirmation };
72
73            if let Some(ref network) = self.network {
74                let network_clone = network.clone();
75                let sender = encrypted_msg.sender;
76                tokio::spawn(async move {
77                    if let Err(e) = network_clone.send_chat_request(sender, confirmation_request).await {
78                        debug!("Failed to send delivery confirmation from mailbox: {}", e);
79                    }
80                });
81            }
82
83            // Notify the UI about the new message.
84            if let Err(e) = self.ui_notify_tx.send(UiNotification::NewMessage(message.clone())) {
85                trace!("UI notify channel closed while reporting message: {}", e);
86            }
87
88            // Also send to web UI if available.
89            if let Some(ref web_tx) = self.web_notify_tx {
90                let _ = web_tx.send(UiNotification::NewMessage(message));
91            }
92
93            processed_msg_ids.push(encrypted_msg.id);
94        }
95
96        Ok(processed_msg_ids)
97    }
98
99    /// Reconstructs a `Message` from an `EncryptedMessage` fetched from a mailbox.
100    ///
101    /// This involves using the local identity's HPKE context to decrypt the content.
102    ///
103    /// # Arguments
104    ///
105    /// * `encrypted_msg` - The `EncryptedMessage` to reconstruct.
106    ///
107    /// # Returns
108    ///
109    /// The reconstructed `Message`.
110    ///
111    /// # Errors
112    ///
113    /// This function will return an error if decryption fails.
114    pub async fn reconstruct_message_from_mailbox(
115        &self,
116        encrypted_msg: &EncryptedMessage,
117    ) -> Result<Message> {
118        let plaintext_content = self.identity.deref().decrypt_from(
119            &encrypted_msg.sender_pub_key,
120            &encrypted_msg.encrypted_content,
121        )?;
122
123        Ok(Message {
124            id: encrypted_msg.id,
125            sender: encrypted_msg.sender,
126            recipient: self.identity.peer_id, // Our peer_id is the recipient
127            timestamp: encrypted_msg.timestamp,
128            content: plaintext_content,
129            nonce: encrypted_msg.nonce,
130            delivery_status: DeliveryStatus::Delivered, // Mark as delivered upon processing
131        })
132    }
133}