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}