plumb all known attachments via dbus if known
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1048,6 +1048,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"chrono",
|
||||||
"dbus",
|
"dbus",
|
||||||
"dbus-codegen",
|
"dbus-codegen",
|
||||||
"dbus-crossroads",
|
"dbus-crossroads",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.98"
|
anyhow = "1.0.98"
|
||||||
async-trait = "0.1.88"
|
async-trait = "0.1.88"
|
||||||
|
chrono = "0.4.38"
|
||||||
dbus = "0.9.7"
|
dbus = "0.9.7"
|
||||||
dbus-crossroads = "0.5.2"
|
dbus-crossroads = "0.5.2"
|
||||||
dbus-tokio = "0.7.6"
|
dbus-tokio = "0.7.6"
|
||||||
|
|||||||
@@ -65,8 +65,16 @@
|
|||||||
'text' (string): Message body text
|
'text' (string): Message body text
|
||||||
'date' (int64): Message timestamp
|
'date' (int64): Message timestamp
|
||||||
'sender' (string): Sender display name
|
'sender' (string): Sender display name
|
||||||
'file_transfer_guids' (string, optional): JSON array of file transfer GUIDs
|
'attachments' (array of dictionaries): List of attachments
|
||||||
'attachment_metadata' (string, optional): JSON string of attachment metadata"/>
|
'guid' (string): Attachment GUID
|
||||||
|
'path' (string): Attachment path
|
||||||
|
'preview_path' (string): Preview attachment path
|
||||||
|
'downloaded' (boolean): Whether the attachment is downloaded
|
||||||
|
'preview_downloaded' (boolean): Whether the preview is downloaded
|
||||||
|
'metadata' (dictionary, optional): Attachment metadata
|
||||||
|
'attribution_info' (dictionary, optional): Attribution info
|
||||||
|
'width' (int32, optional): Width
|
||||||
|
'height' (int32, optional): Height"/>
|
||||||
</arg>
|
</arg>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use kordophone_db::database::DatabaseAccess;
|
|||||||
|
|
||||||
use crate::daemon::events::Event;
|
use crate::daemon::events::Event;
|
||||||
use crate::daemon::events::Reply;
|
use crate::daemon::events::Reply;
|
||||||
|
use crate::daemon::models::Attachment;
|
||||||
use crate::daemon::Daemon;
|
use crate::daemon::Daemon;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -26,23 +27,6 @@ mod target {
|
|||||||
pub static ATTACHMENTS: &str = "attachments";
|
pub static ATTACHMENTS: &str = "attachments";
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Attachment {
|
|
||||||
pub guid: String,
|
|
||||||
pub base_path: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Attachment {
|
|
||||||
pub fn get_path(&self, preview: bool) -> PathBuf {
|
|
||||||
self.base_path.with_extension(if preview { "preview" } else { "full" })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_downloaded(&self, preview: bool) -> bool {
|
|
||||||
std::fs::exists(&self.get_path(preview))
|
|
||||||
.expect(format!("Wasn't able to check for the existence of an attachment file path at {}", &self.get_path(preview).display()).as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum AttachmentStoreEvent {
|
pub enum AttachmentStoreEvent {
|
||||||
// Get the attachment info for a given attachment guid.
|
// Get the attachment info for a given attachment guid.
|
||||||
@@ -75,8 +59,13 @@ pub struct AttachmentStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AttachmentStore {
|
impl AttachmentStore {
|
||||||
pub fn new(data_dir: &PathBuf, database: Arc<Mutex<Database>>, daemon_event_sink: Sender<Event>) -> AttachmentStore {
|
pub fn get_default_store_path() -> PathBuf {
|
||||||
let store_path = data_dir.join("attachments");
|
let data_dir = Daemon::get_data_dir().expect("Unable to get data path");
|
||||||
|
data_dir.join("attachments")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(database: Arc<Mutex<Database>>, daemon_event_sink: Sender<Event>) -> AttachmentStore {
|
||||||
|
let store_path = Self::get_default_store_path();
|
||||||
log::info!(target: target::ATTACHMENTS, "Attachment store path: {}", store_path.display());
|
log::info!(target: target::ATTACHMENTS, "Attachment store path: {}", store_path.display());
|
||||||
|
|
||||||
// Create the attachment store if it doesn't exist
|
// Create the attachment store if it doesn't exist
|
||||||
@@ -98,11 +87,16 @@ impl AttachmentStore {
|
|||||||
self.event_sink.take().unwrap()
|
self.event_sink.take().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_attachment(&self, guid: &String, preview: bool) -> Attachment {
|
fn get_attachment(&self, guid: &String) -> Attachment {
|
||||||
let base_path = self.store_path.join(guid);
|
Self::get_attachment_impl(&self.store_path, guid)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_attachment_impl(store_path: &PathBuf, guid: &String) -> Attachment {
|
||||||
|
let base_path = store_path.join(guid);
|
||||||
Attachment {
|
Attachment {
|
||||||
guid: guid.to_owned(),
|
guid: guid.to_owned(),
|
||||||
base_path: base_path,
|
base_path: base_path,
|
||||||
|
metadata: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +141,7 @@ impl AttachmentStore {
|
|||||||
|
|
||||||
match event {
|
match event {
|
||||||
AttachmentStoreEvent::QueueDownloadAttachment(guid, preview) => {
|
AttachmentStoreEvent::QueueDownloadAttachment(guid, preview) => {
|
||||||
let attachment = self.get_attachment(&guid, preview);
|
let attachment = self.get_attachment(&guid);
|
||||||
if !attachment.is_downloaded(preview) {
|
if !attachment.is_downloaded(preview) {
|
||||||
self.download_attachment(&attachment, preview).await.unwrap_or_else(|e| {
|
self.download_attachment(&attachment, preview).await.unwrap_or_else(|e| {
|
||||||
log::error!(target: target::ATTACHMENTS, "Error downloading attachment: {}", e);
|
log::error!(target: target::ATTACHMENTS, "Error downloading attachment: {}", e);
|
||||||
@@ -158,7 +152,7 @@ impl AttachmentStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AttachmentStoreEvent::GetAttachmentInfo(guid, reply) => {
|
AttachmentStoreEvent::GetAttachmentInfo(guid, reply) => {
|
||||||
let attachment = self.get_attachment(&guid, false);
|
let attachment = self.get_attachment(&guid);
|
||||||
reply.send(attachment).unwrap();
|
reply.send(attachment).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ use uuid::Uuid;
|
|||||||
|
|
||||||
use kordophone::model::ConversationID;
|
use kordophone::model::ConversationID;
|
||||||
use kordophone::model::OutgoingMessage;
|
use kordophone::model::OutgoingMessage;
|
||||||
use kordophone_db::models::{Conversation, Message};
|
use kordophone_db::models::Conversation;
|
||||||
|
|
||||||
use crate::daemon::settings::Settings;
|
use crate::daemon::settings::Settings;
|
||||||
use crate::daemon::Attachment;
|
use crate::daemon::{Attachment, Message};
|
||||||
|
|
||||||
pub type Reply<T> = oneshot::Sender<T>;
|
pub type Reply<T> = oneshot::Sender<T>;
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use uuid::Uuid;
|
|||||||
|
|
||||||
use kordophone_db::{
|
use kordophone_db::{
|
||||||
database::{Database, DatabaseAccess},
|
database::{Database, DatabaseAccess},
|
||||||
models::{Conversation, Message},
|
models::Conversation,
|
||||||
};
|
};
|
||||||
|
|
||||||
use kordophone::api::http_client::HTTPAPIClient;
|
use kordophone::api::http_client::HTTPAPIClient;
|
||||||
@@ -41,8 +41,11 @@ mod post_office;
|
|||||||
use post_office::Event as PostOfficeEvent;
|
use post_office::Event as PostOfficeEvent;
|
||||||
use post_office::PostOffice;
|
use post_office::PostOffice;
|
||||||
|
|
||||||
|
mod models;
|
||||||
|
pub use models::Attachment;
|
||||||
|
pub use models::Message;
|
||||||
|
|
||||||
mod attachment_store;
|
mod attachment_store;
|
||||||
pub use attachment_store::Attachment;
|
|
||||||
pub use attachment_store::AttachmentStore;
|
pub use attachment_store::AttachmentStore;
|
||||||
pub use attachment_store::AttachmentStoreEvent;
|
pub use attachment_store::AttachmentStoreEvent;
|
||||||
|
|
||||||
@@ -147,8 +150,7 @@ impl Daemon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attachment store
|
// Attachment store
|
||||||
let data_path = Self::get_data_dir().expect("Unable to get data path");
|
let mut attachment_store = AttachmentStore::new(self.database.clone(), self.event_sender.clone());
|
||||||
let mut attachment_store = AttachmentStore::new(&data_path, self.database.clone(), self.event_sender.clone());
|
|
||||||
self.attachment_store_sink = Some(attachment_store.get_event_sink());
|
self.attachment_store_sink = Some(attachment_store.get_event_sink());
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
attachment_store.run().await;
|
attachment_store.run().await;
|
||||||
@@ -270,7 +272,7 @@ impl Daemon {
|
|||||||
self.database
|
self.database
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
.with_repository(|r| r.insert_message(&conversation_id, message))
|
.with_repository(|r| r.insert_message(&conversation_id, message.into()))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -355,6 +357,7 @@ impl Daemon {
|
|||||||
r.get_messages_for_conversation(&conversation_id)
|
r.get_messages_for_conversation(&conversation_id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
.map(|m| m.into()) // Convert db::Message to daemon::Message
|
||||||
.chain(outgoing_messages.into_iter().map(|m| m.into()))
|
.chain(outgoing_messages.into_iter().map(|m| m.into()))
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
|
|||||||
64
kordophoned/src/daemon/models/attachment.rs
Normal file
64
kordophoned/src/daemon/models/attachment.rs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AttachmentMetadata {
|
||||||
|
pub attribution_info: Option<AttributionInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AttributionInfo {
|
||||||
|
pub width: Option<u32>,
|
||||||
|
pub height: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Attachment {
|
||||||
|
pub guid: String,
|
||||||
|
pub base_path: PathBuf,
|
||||||
|
pub metadata: Option<AttachmentMetadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Attachment {
|
||||||
|
pub fn get_path(&self, preview: bool) -> PathBuf {
|
||||||
|
self.base_path.with_extension(if preview { "preview" } else { "full" })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_downloaded(&self, preview: bool) -> bool {
|
||||||
|
std::fs::exists(&self.get_path(preview))
|
||||||
|
.expect(format!("Wasn't able to check for the existence of an attachment file path at {}", &self.get_path(preview).display()).as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<kordophone::model::message::AttachmentMetadata> for AttachmentMetadata {
|
||||||
|
fn from(metadata: kordophone::model::message::AttachmentMetadata) -> Self {
|
||||||
|
Self {
|
||||||
|
attribution_info: metadata.attribution_info.map(|info| info.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<kordophone::model::message::AttributionInfo> for AttributionInfo {
|
||||||
|
fn from(info: kordophone::model::message::AttributionInfo) -> Self {
|
||||||
|
Self {
|
||||||
|
width: info.width,
|
||||||
|
height: info.height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AttachmentMetadata> for kordophone::model::message::AttachmentMetadata {
|
||||||
|
fn from(metadata: AttachmentMetadata) -> Self {
|
||||||
|
Self {
|
||||||
|
attribution_info: metadata.attribution_info.map(|info| info.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AttributionInfo> for kordophone::model::message::AttributionInfo {
|
||||||
|
fn from(info: AttributionInfo) -> Self {
|
||||||
|
Self {
|
||||||
|
width: info.width,
|
||||||
|
height: info.height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
217
kordophoned/src/daemon/models/message.rs
Normal file
217
kordophoned/src/daemon/models/message.rs
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
use chrono::NaiveDateTime;
|
||||||
|
use chrono::DateTime;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use uuid::Uuid;
|
||||||
|
use kordophone::model::message::AttachmentMetadata;
|
||||||
|
use kordophone::model::outgoing_message::OutgoingMessage;
|
||||||
|
use crate::daemon::models::Attachment;
|
||||||
|
use crate::daemon::attachment_store::AttachmentStore;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Participant {
|
||||||
|
Me,
|
||||||
|
Remote {
|
||||||
|
id: Option<i32>,
|
||||||
|
display_name: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> 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<kordophone_db::models::Participant> 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<Attachment>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Message {
|
||||||
|
pub fn builder() -> MessageBuilder {
|
||||||
|
MessageBuilder::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attachments_from(file_transfer_guids: &Vec<String>, attachment_metadata: &Option<HashMap<String, AttachmentMetadata>>) -> Vec<Attachment> {
|
||||||
|
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<kordophone_db::models::Message> 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<Message> 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<String, kordophone::model::message::AttachmentMetadata> = 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<kordophone::model::Message> 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MessageBuilder {
|
||||||
|
id: Option<String>,
|
||||||
|
sender: Option<Participant>,
|
||||||
|
text: Option<String>,
|
||||||
|
date: Option<NaiveDateTime>,
|
||||||
|
attachments: Vec<Attachment>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MessageBuilder {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MessageBuilder {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
id: None,
|
||||||
|
sender: None,
|
||||||
|
text: None,
|
||||||
|
date: None,
|
||||||
|
attachments: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sender(mut self, sender: Participant) -> Self {
|
||||||
|
self.sender = Some(sender);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text(mut self, text: String) -> Self {
|
||||||
|
self.text = Some(text);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn date(mut self, date: NaiveDateTime) -> Self {
|
||||||
|
self.date = Some(date);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attachments(mut self, attachments: Vec<Attachment>) -> Self {
|
||||||
|
self.attachments = attachments;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> Message {
|
||||||
|
Message {
|
||||||
|
id: self.id.unwrap_or_else(|| Uuid::new_v4().to_string()),
|
||||||
|
sender: self.sender.unwrap_or(Participant::Me),
|
||||||
|
text: self.text.unwrap_or_default(),
|
||||||
|
date: self.date.unwrap_or_else(|| chrono::Utc::now().naive_utc()),
|
||||||
|
attachments: self.attachments,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
kordophoned/src/daemon/models/mod.rs
Normal file
5
kordophoned/src/daemon/models/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pub mod attachment;
|
||||||
|
pub mod message;
|
||||||
|
|
||||||
|
pub use attachment::Attachment;
|
||||||
|
pub use message::Message;
|
||||||
@@ -138,30 +138,51 @@ impl DbusRepository for ServerImpl {
|
|||||||
arg::Variant(Box::new(msg.sender.display_name())),
|
arg::Variant(Box::new(msg.sender.display_name())),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add file transfer GUIDs if present
|
// Add attachments array
|
||||||
if !msg.file_transfer_guids.is_empty() {
|
let attachments: Vec<arg::PropMap> = msg.attachments
|
||||||
match serde_json::to_string(&msg.file_transfer_guids) {
|
.into_iter()
|
||||||
Ok(json_str) => {
|
.map(|attachment| {
|
||||||
map.insert("file_transfer_guids".into(), arg::Variant(Box::new(json_str)));
|
let mut attachment_map = arg::PropMap::new();
|
||||||
}
|
attachment_map.insert("guid".into(), arg::Variant(Box::new(attachment.guid.clone())));
|
||||||
Err(e) => {
|
|
||||||
log::warn!("Failed to serialize file transfer GUIDs for message {}: {}", msg_id, e);
|
// Get attachment paths and download status
|
||||||
}
|
let path = attachment.get_path(false);
|
||||||
|
let preview_path = attachment.get_path(true);
|
||||||
|
let downloaded = attachment.is_downloaded(false);
|
||||||
|
let preview_downloaded = attachment.is_downloaded(true);
|
||||||
|
|
||||||
|
attachment_map.insert("path".into(), arg::Variant(Box::new(path.to_string_lossy().to_string())));
|
||||||
|
attachment_map.insert("preview_path".into(), arg::Variant(Box::new(preview_path.to_string_lossy().to_string())));
|
||||||
|
attachment_map.insert("downloaded".into(), arg::Variant(Box::new(downloaded)));
|
||||||
|
attachment_map.insert("preview_downloaded".into(), arg::Variant(Box::new(preview_downloaded)));
|
||||||
|
|
||||||
|
// Add metadata if present
|
||||||
|
if let Some(ref metadata) = attachment.metadata {
|
||||||
|
let mut metadata_map = arg::PropMap::new();
|
||||||
|
|
||||||
|
// Add attribution_info if present
|
||||||
|
if let Some(ref attribution_info) = metadata.attribution_info {
|
||||||
|
let mut attribution_map = arg::PropMap::new();
|
||||||
|
|
||||||
|
if let Some(width) = attribution_info.width {
|
||||||
|
attribution_map.insert("width".into(), arg::Variant(Box::new(width as i32)));
|
||||||
}
|
}
|
||||||
|
if let Some(height) = attribution_info.height {
|
||||||
|
attribution_map.insert("height".into(), arg::Variant(Box::new(height as i32)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add attachment metadata if present
|
metadata_map.insert("attribution_info".into(), arg::Variant(Box::new(attribution_map)));
|
||||||
if let Some(ref attachment_metadata) = msg.attachment_metadata {
|
|
||||||
match serde_json::to_string(attachment_metadata) {
|
|
||||||
Ok(json_str) => {
|
|
||||||
map.insert("attachment_metadata".into(), arg::Variant(Box::new(json_str)));
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::warn!("Failed to serialize attachment metadata for message {}: {}", msg_id, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attachment_map.insert("metadata".into(), arg::Variant(Box::new(metadata_map)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attachment_map
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
map.insert("attachments".into(), arg::Variant(Box::new(attachments)));
|
||||||
|
|
||||||
map
|
map
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|||||||
Reference in New Issue
Block a user