p2p_chat/storage/mailbox/
mod.rs

1//! This module defines the storage interface and implementation for the mailbox.
2//!
3//! The mailbox stores encrypted messages for recipients until they can be fetched.
4mod operations;
5
6use crate::crypto::StorageEncryption;
7use crate::types::EncryptedMessage;
8use anyhow::Result;
9use async_trait::async_trait;
10use sled::Db;
11use uuid::Uuid;
12
13/// A trait for managing mailbox operations.
14#[async_trait]
15pub trait MailboxStore {
16    /// Stores an encrypted message for a recipient.
17    ///
18    /// # Arguments
19    ///
20    /// * `recipient_hash` - The hash of the recipient's public key.
21    /// * `msg` - The `EncryptedMessage` to store.
22    ///
23    /// # Errors
24    ///
25    /// This function will return an error if the message cannot be stored.
26    async fn store_message(&self, recipient_hash: [u8; 32], msg: EncryptedMessage) -> Result<()>;
27
28    /// Fetches messages for a recipient.
29    ///
30    /// # Arguments
31    ///
32    /// * `recipient_hash` - The hash of the recipient's public key.
33    /// * `limit` - The maximum number of messages to fetch.
34    ///
35    /// # Returns
36    ///
37    /// A `Vec` of `EncryptedMessage`s for the recipient.
38    ///
39    /// # Errors
40    ///
41    /// This function will return an error if the messages cannot be fetched.
42    async fn fetch_messages(
43        &self,
44        recipient_hash: [u8; 32],
45        limit: usize,
46    ) -> Result<Vec<EncryptedMessage>>;
47
48    /// Deletes messages for a recipient.
49    ///
50    /// # Arguments
51    ///
52    /// * `recipient_hash` - The hash of the recipient's public key.
53    /// * `msg_ids` - A `Vec` of message IDs to delete.
54    ///
55    /// # Returns
56    ///
57    /// The number of messages that were deleted.
58    ///
59    /// # Errors
60    ///
61    /// This function will return an error if the messages cannot be deleted.
62    async fn delete_messages(&self, recipient_hash: [u8; 32], msg_ids: Vec<Uuid>) -> Result<usize>;
63
64    /// Cleans up expired messages from the mailbox.
65    ///
66    /// # Arguments
67    ///
68    /// * `max_age` - The maximum age for messages to be retained.
69    ///
70    /// # Errors
71    ///
72    /// This function will return an error if cleanup fails.
73    async fn cleanup_expired(&self, max_age: std::time::Duration) -> Result<()>;
74}
75
76/// A `MailboxStore` implementation using `sled` for storage.
77pub struct SledMailboxStore {
78    pub(crate) tree: sled::Tree,
79    pub(crate) encryption: Option<StorageEncryption>,
80    pub(crate) max_storage_per_user: usize,
81}
82
83impl SledMailboxStore {
84    /// Creates a new `SledMailboxStore`.
85    ///
86    /// # Arguments
87    ///
88    /// * `db` - The `sled::Db` instance to use for storage.
89    /// * `encryption` - The optional `StorageEncryption` to use for encrypting messages.
90    /// * `max_storage_per_user` - The maximum number of messages to store per user.
91    ///
92    /// # Errors
93    ///
94    /// This function will return an error if the `mailbox` tree cannot be opened.
95    pub fn new(
96        db: Db,
97        encryption: Option<StorageEncryption>,
98        max_storage_per_user: usize,
99    ) -> Result<Self> {
100        let tree = db.open_tree("mailbox")?;
101        Ok(Self {
102            tree,
103            encryption,
104            max_storage_per_user,
105        })
106    }
107
108    /// Creates a unique key for a message in the mailbox.
109    pub(crate) fn make_message_key(&self, recipient_hash: &[u8; 32], msg_id: &Uuid) -> Vec<u8> {
110        let mut key = Vec::new();
111        key.extend_from_slice(recipient_hash);
112        key.extend_from_slice(msg_id.as_bytes());
113        key
114    }
115
116    /// Serializes an `EncryptedMessage` and encrypts it if encryption is enabled.
117    pub(crate) fn serialize_message(&self, msg: &EncryptedMessage) -> Result<Vec<u8>> {
118        let serialized = serde_json::to_vec(msg)?;
119
120        if let Some(ref encryption) = self.encryption {
121            encryption.encrypt_value(&serialized)
122        } else {
123            Ok(serialized)
124        }
125    }
126
127    /// Decrypts and deserializes an `EncryptedMessage`.
128    pub(crate) fn deserialize_message(&self, data: &[u8]) -> Result<EncryptedMessage> {
129        let decrypted = if let Some(ref encryption) = self.encryption {
130            encryption.decrypt_value(data)?
131        } else {
132            data.to_vec()
133        };
134
135        Ok(serde_json::from_slice(&decrypted)?)
136    }
137}