use chrono::DateTime; use chrono::NaiveDateTime; use crate::daemon::attachment_store::AttachmentStore; use crate::daemon::models::Attachment; use kordophone::model::message::AttachmentMetadata; use kordophone::model::outgoing_message::OutgoingMessage; use std::collections::HashMap; #[derive(Clone, Debug)] pub enum Participant { Me, Remote { id: Option, display_name: String, }, } impl From for Participant { fn from(display_name: String) -> Self { Participant::Remote { id: None, display_name, } } } impl From<&str> for Participant { fn from(display_name: &str) -> Self { Participant::Remote { id: None, display_name: display_name.to_string(), } } } impl From for Participant { fn from(participant: kordophone_db::models::Participant) -> Self { match participant { kordophone_db::models::Participant::Me => Participant::Me, kordophone_db::models::Participant::Remote { id, display_name } => { Participant::Remote { id, display_name } } } } } impl Participant { pub fn display_name(&self) -> String { match self { Participant::Me => "(Me)".to_string(), Participant::Remote { display_name, .. } => display_name.clone(), } } } #[derive(Clone, Debug)] pub struct Message { pub id: String, pub sender: Participant, pub text: String, pub date: NaiveDateTime, pub attachments: Vec, } fn attachments_from( file_transfer_guids: &Vec, attachment_metadata: &Option>, ) -> Vec { file_transfer_guids .iter() .map(|guid| { let mut attachment = AttachmentStore::get_attachment_impl( &AttachmentStore::get_default_store_path(), guid, ); attachment.metadata = match attachment_metadata { Some(attachment_metadata) => attachment_metadata .get(guid) .cloned() .map(|metadata| metadata.into()), None => None, }; attachment }) .collect() } impl From for Message { fn from(message: kordophone_db::models::Message) -> Self { let attachments = attachments_from(&message.file_transfer_guids, &message.attachment_metadata); Self { id: message.id, sender: message.sender.into(), text: message.text, date: message.date, attachments, } } } impl From for kordophone_db::models::Message { fn from(message: Message) -> Self { Self { id: message.id, sender: match message.sender { Participant::Me => kordophone_db::models::Participant::Me, Participant::Remote { id, display_name } => { kordophone_db::models::Participant::Remote { id, display_name } } }, text: message.text, date: message.date, file_transfer_guids: message.attachments.iter().map(|a| a.guid.clone()).collect(), attachment_metadata: { let metadata_map: HashMap = message .attachments .iter() .filter_map(|a| { a.metadata .as_ref() .map(|m| (a.guid.clone(), m.clone().into())) }) .collect(); if metadata_map.is_empty() { None } else { Some(metadata_map) } }, } } } impl From for Message { fn from(message: kordophone::model::Message) -> Self { let attachments = attachments_from(&message.file_transfer_guids, &message.attachment_metadata); Self { id: message.guid, sender: match message.sender { Some(sender) => Participant::Remote { id: None, display_name: sender, }, None => Participant::Me, }, text: message.text, date: DateTime::from_timestamp( message.date.unix_timestamp(), message.date.unix_timestamp_nanos().try_into().unwrap_or(0), ) .unwrap() .naive_local(), attachments, } } } impl From<&OutgoingMessage> for Message { fn from(value: &OutgoingMessage) -> Self { Self { id: value.guid.to_string(), sender: Participant::Me, text: value.text.clone(), date: value.date, attachments: Vec::new(), // Outgoing messages don't have attachments initially } } }