2026-04-17 17:09:21 -05:00

232 lines
7.4 KiB
Rust

use forge_models::{PhoneEmail, PhoneMessage};
use std::collections::{HashMap, HashSet};
use std::sync::{Arc, RwLock};
pub trait PhoneRepository: Send + Sync {
fn init(&self, uid: &str) -> Result<(), String>;
fn add_contact(&self, uid: &str, contact_uid: &str) -> Result<bool, String>;
fn remove_contact(&self, uid: &str, contact_uid: &str) -> Result<bool, String>;
fn list_contacts(&self, uid: &str) -> Result<Vec<String>, String>;
fn remove_phone(&self, uid: &str) -> Result<(), String>;
fn append_message(&self, uid: &str, message: PhoneMessage) -> Result<(), String>;
fn list_messages(&self, uid: &str) -> Result<Vec<PhoneMessage>, String>;
fn mark_message_read(&self, uid: &str, message_id: &str) -> Result<bool, String>;
fn delete_message(&self, uid: &str, message_id: &str) -> Result<bool, String>;
fn append_email(&self, uid: &str, email: PhoneEmail) -> Result<(), String>;
fn list_emails(&self, uid: &str) -> Result<Vec<PhoneEmail>, String>;
fn mark_email_read(&self, uid: &str, email_id: &str) -> Result<bool, String>;
fn delete_email(&self, uid: &str, email_id: &str) -> Result<bool, String>;
fn next_sequence(&self) -> Result<u64, String>;
}
#[derive(Debug, Default)]
struct PhoneState {
contacts: HashMap<String, HashSet<String>>,
messages: HashMap<String, Vec<PhoneMessage>>,
emails: HashMap<String, Vec<PhoneEmail>>,
sequence: u64,
}
#[derive(Clone, Debug, Default)]
pub struct InMemoryPhoneRepository {
state: Arc<RwLock<PhoneState>>,
}
impl InMemoryPhoneRepository {
pub fn new() -> Self {
Self::default()
}
}
impl PhoneRepository for InMemoryPhoneRepository {
fn init(&self, uid: &str) -> Result<(), String> {
let mut state = self
.state
.write()
.map_err(|_| "Phone state lock poisoned.".to_string())?;
state.contacts.entry(uid.to_string()).or_default();
state.messages.entry(uid.to_string()).or_default();
state.emails.entry(uid.to_string()).or_default();
Ok(())
}
fn add_contact(&self, uid: &str, contact_uid: &str) -> Result<bool, String> {
let mut state = self
.state
.write()
.map_err(|_| "Phone contact state lock poisoned.".to_string())?;
Ok(state
.contacts
.entry(uid.to_string())
.or_default()
.insert(contact_uid.to_string()))
}
fn remove_contact(&self, uid: &str, contact_uid: &str) -> Result<bool, String> {
let mut state = self
.state
.write()
.map_err(|_| "Phone contact state lock poisoned.".to_string())?;
Ok(state
.contacts
.entry(uid.to_string())
.or_default()
.remove(contact_uid))
}
fn list_contacts(&self, uid: &str) -> Result<Vec<String>, String> {
let mut contacts = self
.state
.read()
.map_err(|_| "Phone contact state lock poisoned.".to_string())?
.contacts
.get(uid)
.map(|contacts| contacts.iter().cloned().collect::<Vec<_>>())
.unwrap_or_default();
contacts.sort();
Ok(contacts)
}
fn remove_phone(&self, uid: &str) -> Result<(), String> {
let mut state = self
.state
.write()
.map_err(|_| "Phone state lock poisoned.".to_string())?;
state.contacts.remove(uid);
state.messages.remove(uid);
state.emails.remove(uid);
Ok(())
}
fn append_message(&self, uid: &str, message: PhoneMessage) -> Result<(), String> {
self.state
.write()
.map_err(|_| "Phone message state lock poisoned.".to_string())?
.messages
.entry(uid.to_string())
.or_default()
.push(message);
Ok(())
}
fn list_messages(&self, uid: &str) -> Result<Vec<PhoneMessage>, String> {
let mut messages = self
.state
.read()
.map_err(|_| "Phone message state lock poisoned.".to_string())?
.messages
.get(uid)
.cloned()
.unwrap_or_default();
messages.sort_by(|left, right| {
left.timestamp
.partial_cmp(&right.timestamp)
.unwrap_or(std::cmp::Ordering::Equal)
});
Ok(messages)
}
fn mark_message_read(&self, uid: &str, message_id: &str) -> Result<bool, String> {
let mut state = self
.state
.write()
.map_err(|_| "Phone message state lock poisoned.".to_string())?;
let Some(messages) = state.messages.get_mut(uid) else {
return Ok(false);
};
let mut found = false;
for message in messages {
if message.id == message_id {
message.read = true;
found = true;
}
}
Ok(found)
}
fn delete_message(&self, uid: &str, message_id: &str) -> Result<bool, String> {
let mut state = self
.state
.write()
.map_err(|_| "Phone message state lock poisoned.".to_string())?;
let Some(messages) = state.messages.get_mut(uid) else {
return Ok(false);
};
let original_len = messages.len();
messages.retain(|message| message.id != message_id);
Ok(messages.len() != original_len)
}
fn append_email(&self, uid: &str, email: PhoneEmail) -> Result<(), String> {
self.state
.write()
.map_err(|_| "Phone email state lock poisoned.".to_string())?
.emails
.entry(uid.to_string())
.or_default()
.push(email);
Ok(())
}
fn list_emails(&self, uid: &str) -> Result<Vec<PhoneEmail>, String> {
let mut emails = self
.state
.read()
.map_err(|_| "Phone email state lock poisoned.".to_string())?
.emails
.get(uid)
.cloned()
.unwrap_or_default();
emails.sort_by(|left, right| {
right
.timestamp
.partial_cmp(&left.timestamp)
.unwrap_or(std::cmp::Ordering::Equal)
});
Ok(emails)
}
fn mark_email_read(&self, uid: &str, email_id: &str) -> Result<bool, String> {
let mut state = self
.state
.write()
.map_err(|_| "Phone email state lock poisoned.".to_string())?;
let Some(emails) = state.emails.get_mut(uid) else {
return Ok(false);
};
let mut found = false;
for email in emails {
if email.id == email_id {
email.read = true;
found = true;
}
}
Ok(found)
}
fn delete_email(&self, uid: &str, email_id: &str) -> Result<bool, String> {
let mut state = self
.state
.write()
.map_err(|_| "Phone email state lock poisoned.".to_string())?;
let Some(emails) = state.emails.get_mut(uid) else {
return Ok(false);
};
let original_len = emails.len();
emails.retain(|email| email.id != email_id);
Ok(emails.len() != original_len)
}
fn next_sequence(&self) -> Result<u64, String> {
let mut state = self
.state
.write()
.map_err(|_| "Phone sequence lock poisoned.".to_string())?;
state.sequence += 1;
Ok(state.sequence)
}
}