cargo fmt
This commit is contained in:
@@ -11,14 +11,12 @@ fn main() {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let xml = std::fs::read_to_string(KORDOPHONE_XML)
|
||||
.expect("Error reading server dbus interface");
|
||||
let xml = std::fs::read_to_string(KORDOPHONE_XML).expect("Error reading server dbus interface");
|
||||
|
||||
let output = dbus_codegen::generate(&xml, &opts)
|
||||
.expect("Error generating server dbus interface");
|
||||
let output =
|
||||
dbus_codegen::generate(&xml, &opts).expect("Error generating server dbus interface");
|
||||
|
||||
std::fs::write(out_path, output)
|
||||
.expect("Error writing server dbus code");
|
||||
std::fs::write(out_path, output).expect("Error writing server dbus code");
|
||||
|
||||
println!("cargo:rerun-if-changed={}", KORDOPHONE_XML);
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ use crate::daemon::models::Attachment;
|
||||
use crate::daemon::Daemon;
|
||||
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use tokio::pin;
|
||||
|
||||
@@ -32,7 +32,7 @@ pub enum AttachmentStoreEvent {
|
||||
GetAttachmentInfo(String, Reply<Attachment>),
|
||||
|
||||
// Queue a download for a given attachment guid.
|
||||
// Args:
|
||||
// Args:
|
||||
// - attachment guid
|
||||
// - preview: whether to download the preview (true) or full attachment (false)
|
||||
QueueDownloadAttachment(String, bool),
|
||||
@@ -62,7 +62,10 @@ impl AttachmentStore {
|
||||
data_dir.join("attachments")
|
||||
}
|
||||
|
||||
pub fn new(database: Arc<Mutex<Database>>, daemon_event_sink: Sender<Event>) -> AttachmentStore {
|
||||
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());
|
||||
|
||||
@@ -97,7 +100,7 @@ impl AttachmentStore {
|
||||
metadata: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async fn download_attachment(&mut self, attachment: &Attachment, preview: bool) -> Result<()> {
|
||||
if attachment.is_downloaded(preview) {
|
||||
log::info!(target: target::ATTACHMENTS, "Attachment already downloaded: {}", attachment.guid);
|
||||
@@ -130,7 +133,7 @@ impl AttachmentStore {
|
||||
log::info!(target: target::ATTACHMENTS, "Completed download for attachment: {}", attachment.guid);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub async fn run(&mut self) {
|
||||
loop {
|
||||
tokio::select! {
|
||||
|
||||
@@ -150,7 +150,8 @@ impl Daemon {
|
||||
}
|
||||
|
||||
// Attachment store
|
||||
let mut attachment_store = AttachmentStore::new(self.database.clone(), self.event_sender.clone());
|
||||
let mut attachment_store =
|
||||
AttachmentStore::new(self.database.clone(), self.event_sender.clone());
|
||||
self.attachment_store_sink = Some(attachment_store.get_event_sink());
|
||||
tokio::spawn(async move {
|
||||
attachment_store.run().await;
|
||||
@@ -304,7 +305,10 @@ impl Daemon {
|
||||
self.attachment_store_sink
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.send(AttachmentStoreEvent::QueueDownloadAttachment(attachment_id, preview))
|
||||
.send(AttachmentStoreEvent::QueueDownloadAttachment(
|
||||
attachment_id,
|
||||
preview,
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -20,14 +20,20 @@ pub struct Attachment {
|
||||
|
||||
impl Attachment {
|
||||
pub fn get_path(&self, preview: bool) -> PathBuf {
|
||||
self.base_path.with_extension(if preview { "preview" } else { "full" })
|
||||
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())
|
||||
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 {
|
||||
@@ -61,4 +67,4 @@ impl From<AttributionInfo> for kordophone::model::message::AttributionInfo {
|
||||
height: info.height,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use chrono::NaiveDateTime;
|
||||
use chrono::DateTime;
|
||||
use chrono::NaiveDateTime;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use crate::daemon::attachment_store::AttachmentStore;
|
||||
use crate::daemon::models::Attachment;
|
||||
use kordophone::model::message::AttachmentMetadata;
|
||||
use kordophone::model::outgoing_message::OutgoingMessage;
|
||||
use crate::daemon::models::Attachment;
|
||||
use crate::daemon::attachment_store::AttachmentStore;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Participant {
|
||||
@@ -54,7 +54,7 @@ impl Participant {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Message {
|
||||
pub id: String,
|
||||
pub sender: Participant,
|
||||
@@ -63,24 +63,34 @@ pub struct Message {
|
||||
pub attachments: Vec<Attachment>,
|
||||
}
|
||||
|
||||
fn attachments_from(file_transfer_guids: &Vec<String>, attachment_metadata: &Option<HashMap<String, AttachmentMetadata>>) -> Vec<Attachment> {
|
||||
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);
|
||||
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()),
|
||||
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);
|
||||
let attachments =
|
||||
attachments_from(&message.file_transfer_guids, &message.attachment_metadata);
|
||||
Self {
|
||||
id: message.id,
|
||||
sender: message.sender.into(),
|
||||
@@ -105,11 +115,21 @@ impl From<Message> for kordophone_db::models::Message {
|
||||
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) }
|
||||
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)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -117,7 +137,8 @@ impl From<Message> for kordophone_db::models::Message {
|
||||
|
||||
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);
|
||||
let attachments =
|
||||
attachments_from(&message.file_transfer_guids, &message.attachment_metadata);
|
||||
Self {
|
||||
id: message.guid,
|
||||
sender: match message.sender {
|
||||
@@ -130,12 +151,10 @@ impl From<kordophone::model::Message> for Message {
|
||||
text: message.text,
|
||||
date: DateTime::from_timestamp(
|
||||
message.date.unix_timestamp(),
|
||||
message.date.unix_timestamp_nanos()
|
||||
.try_into()
|
||||
.unwrap_or(0),
|
||||
)
|
||||
.unwrap()
|
||||
.naive_local(),
|
||||
message.date.unix_timestamp_nanos().try_into().unwrap_or(0),
|
||||
)
|
||||
.unwrap()
|
||||
.naive_local(),
|
||||
attachments,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@ pub mod attachment;
|
||||
pub mod message;
|
||||
|
||||
pub use attachment::Attachment;
|
||||
pub use message::Message;
|
||||
pub use message::Message;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use std::collections::VecDeque;
|
||||
use std::time::Duration;
|
||||
|
||||
use tokio::sync::mpsc::{Sender, Receiver};
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tokio::sync::Mutex;
|
||||
use tokio_condvar::Condvar;
|
||||
|
||||
use crate::daemon::events::Event as DaemonEvent;
|
||||
use kordophone::model::outgoing_message::OutgoingMessage;
|
||||
use kordophone::api::APIInterface;
|
||||
use kordophone::model::outgoing_message::OutgoingMessage;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
@@ -25,15 +25,19 @@ pub struct PostOffice<C: APIInterface, F: AsyncFnMut() -> Result<C>> {
|
||||
event_sink: Sender<DaemonEvent>,
|
||||
make_client: F,
|
||||
message_queue: Mutex<VecDeque<OutgoingMessage>>,
|
||||
message_available: Condvar,
|
||||
message_available: Condvar,
|
||||
}
|
||||
|
||||
impl<C: APIInterface, F: AsyncFnMut() -> Result<C>> PostOffice<C, F> {
|
||||
pub fn new(event_source: Receiver<Event>, event_sink: Sender<DaemonEvent>, make_client: F) -> Self {
|
||||
Self {
|
||||
pub fn new(
|
||||
event_source: Receiver<Event>,
|
||||
event_sink: Sender<DaemonEvent>,
|
||||
make_client: F,
|
||||
) -> Self {
|
||||
Self {
|
||||
event_source,
|
||||
event_sink,
|
||||
make_client,
|
||||
event_sink,
|
||||
make_client,
|
||||
message_queue: Mutex::new(VecDeque::new()),
|
||||
message_available: Condvar::new(),
|
||||
}
|
||||
@@ -85,13 +89,12 @@ impl<C: APIInterface, F: AsyncFnMut() -> Result<C>> PostOffice<C, F> {
|
||||
}
|
||||
|
||||
async fn try_send_message(
|
||||
make_client: &mut F,
|
||||
event_sink: &Sender<DaemonEvent>,
|
||||
message: OutgoingMessage
|
||||
) -> Vec<OutgoingMessage>
|
||||
{
|
||||
make_client: &mut F,
|
||||
event_sink: &Sender<DaemonEvent>,
|
||||
message: OutgoingMessage,
|
||||
) -> Vec<OutgoingMessage> {
|
||||
let mut retry_messages = Vec::new();
|
||||
|
||||
|
||||
match (make_client)().await {
|
||||
Ok(mut client) => {
|
||||
log::debug!(target: target::POST_OFFICE, "Obtained client, sending message.");
|
||||
@@ -100,7 +103,8 @@ impl<C: APIInterface, F: AsyncFnMut() -> Result<C>> PostOffice<C, F> {
|
||||
log::info!(target: target::POST_OFFICE, "Message sent successfully: {}", message.guid);
|
||||
|
||||
let conversation_id = message.conversation_id.clone();
|
||||
let event = DaemonEvent::MessageSent(sent_message.into(), message, conversation_id);
|
||||
let event =
|
||||
DaemonEvent::MessageSent(sent_message.into(), message, conversation_id);
|
||||
event_sink.send(event).await.unwrap();
|
||||
}
|
||||
|
||||
@@ -123,4 +127,4 @@ impl<C: APIInterface, F: AsyncFnMut() -> Result<C>> PostOffice<C, F> {
|
||||
|
||||
retry_messages
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use kordophone_db::settings::Settings as DbSettings;
|
||||
use anyhow::Result;
|
||||
use kordophone_db::settings::Settings as DbSettings;
|
||||
|
||||
pub mod keys {
|
||||
pub static SERVER_URL: &str = "ServerURL";
|
||||
@@ -7,8 +7,7 @@ pub mod keys {
|
||||
pub static TOKEN: &str = "Token";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Default)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Settings {
|
||||
pub server_url: Option<String>,
|
||||
pub username: Option<String>,
|
||||
@@ -20,7 +19,7 @@ impl Settings {
|
||||
let server_url = db_settings.get(keys::SERVER_URL)?;
|
||||
let username = db_settings.get(keys::USERNAME)?;
|
||||
let token = db_settings.get(keys::TOKEN)?;
|
||||
|
||||
|
||||
// Create the settings struct with the results
|
||||
let settings = Self {
|
||||
server_url,
|
||||
@@ -30,7 +29,7 @@ impl Settings {
|
||||
|
||||
// Load bearing
|
||||
log::debug!("Loaded settings: {:?}", settings);
|
||||
|
||||
|
||||
Ok(settings)
|
||||
}
|
||||
|
||||
@@ -47,4 +46,3 @@ impl Settings {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
use crate::daemon::{
|
||||
Daemon,
|
||||
DaemonResult,
|
||||
|
||||
events::{Event, Reply},
|
||||
target,
|
||||
target, Daemon, DaemonResult,
|
||||
};
|
||||
|
||||
use kordophone::APIInterface;
|
||||
use kordophone::api::event_socket::EventSocket;
|
||||
use kordophone::model::event::Event as UpdateEvent;
|
||||
use kordophone::model::event::EventData as UpdateEventData;
|
||||
use kordophone::APIInterface;
|
||||
|
||||
use kordophone_db::database::Database;
|
||||
use kordophone_db::database::DatabaseAccess;
|
||||
|
||||
use tokio::sync::mpsc::Sender;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::sync::mpsc::Sender;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
pub struct UpdateMonitor {
|
||||
database: Arc<Mutex<Database>>,
|
||||
@@ -29,8 +26,8 @@ pub struct UpdateMonitor {
|
||||
|
||||
impl UpdateMonitor {
|
||||
pub fn new(database: Arc<Mutex<Database>>, event_sender: Sender<Event>) -> Self {
|
||||
Self {
|
||||
database,
|
||||
Self {
|
||||
database,
|
||||
event_sender,
|
||||
last_sync_times: HashMap::new(),
|
||||
update_seq: None,
|
||||
@@ -42,23 +39,24 @@ impl UpdateMonitor {
|
||||
make_event: impl FnOnce(Reply<T>) -> Event,
|
||||
) -> DaemonResult<T> {
|
||||
let (reply_tx, reply_rx) = tokio::sync::oneshot::channel();
|
||||
self.event_sender.send(make_event(reply_tx))
|
||||
self.event_sender
|
||||
.send(make_event(reply_tx))
|
||||
.await
|
||||
.map_err(|_| "Failed to send event")?;
|
||||
|
||||
|
||||
reply_rx.await.map_err(|_| "Failed to receive reply".into())
|
||||
}
|
||||
|
||||
|
||||
async fn handle_update(&mut self, update: UpdateEvent) {
|
||||
self.update_seq = Some(update.update_seq);
|
||||
|
||||
|
||||
match update.data {
|
||||
UpdateEventData::ConversationChanged(conversation) => {
|
||||
log::info!(target: target::UPDATES, "Conversation changed: {:?}", conversation);
|
||||
|
||||
// Check if we've synced this conversation recently (within 5 seconds)
|
||||
// This is currently a hack/workaround to prevent an infinite loop of sync events, because for some reason
|
||||
// imagent will post a conversation changed notification when we call getMessages.
|
||||
// imagent will post a conversation changed notification when we call getMessages.
|
||||
if let Some(last_sync) = self.last_sync_times.get(&conversation.guid) {
|
||||
if last_sync.elapsed() < Duration::from_secs(5) {
|
||||
log::info!(target: target::UPDATES, "Skipping sync for conversation id: {}. Last sync was {} seconds ago.",
|
||||
@@ -67,8 +65,12 @@ impl UpdateMonitor {
|
||||
}
|
||||
}
|
||||
|
||||
// This is the non-hacky path once we can reason about chat items with associatedMessageGUIDs (e.g., reactions).
|
||||
let last_message = self.database.with_repository(|r| r.get_last_message_for_conversation(&conversation.guid)).await.unwrap_or_default();
|
||||
// This is the non-hacky path once we can reason about chat items with associatedMessageGUIDs (e.g., reactions).
|
||||
let last_message = self
|
||||
.database
|
||||
.with_repository(|r| r.get_last_message_for_conversation(&conversation.guid))
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
match (&last_message, &conversation.last_message) {
|
||||
(Some(message), Some(conversation_message)) => {
|
||||
if message.id == conversation_message.guid {
|
||||
@@ -80,10 +82,12 @@ impl UpdateMonitor {
|
||||
};
|
||||
|
||||
// Update the last sync time and proceed with sync
|
||||
self.last_sync_times.insert(conversation.guid.clone(), Instant::now());
|
||||
|
||||
self.last_sync_times
|
||||
.insert(conversation.guid.clone(), Instant::now());
|
||||
|
||||
log::info!(target: target::UPDATES, "Syncing new messages for conversation id: {}", conversation.guid);
|
||||
self.send_event(|r| Event::SyncConversation(conversation.guid, r)).await
|
||||
self.send_event(|r| Event::SyncConversation(conversation.guid, r))
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
log::error!("Failed to send daemon event: {}", e);
|
||||
});
|
||||
@@ -92,14 +96,15 @@ impl UpdateMonitor {
|
||||
UpdateEventData::MessageReceived(conversation, message) => {
|
||||
log::info!(target: target::UPDATES, "Message received: msgid:{:?}, convid:{:?}", message.guid, conversation.guid);
|
||||
log::info!(target: target::UPDATES, "Triggering message sync for conversation id: {}", conversation.guid);
|
||||
self.send_event(|r| Event::SyncConversation(conversation.guid, r)).await
|
||||
self.send_event(|r| Event::SyncConversation(conversation.guid, r))
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
log::error!("Failed to send daemon event: {}", e);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn run(&mut self) {
|
||||
use futures_util::stream::StreamExt;
|
||||
|
||||
@@ -130,15 +135,15 @@ impl UpdateMonitor {
|
||||
|
||||
log::debug!(target: target::UPDATES, "Starting event stream");
|
||||
let mut event_stream = socket.events().await;
|
||||
|
||||
// We won't know if the websocket is dead until we try to send a message, so time out waiting for
|
||||
// a message every 30 seconds.
|
||||
|
||||
// We won't know if the websocket is dead until we try to send a message, so time out waiting for
|
||||
// a message every 30 seconds.
|
||||
let mut timeout = tokio::time::interval(Duration::from_secs(30));
|
||||
timeout.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
|
||||
|
||||
// First tick will happen immediately
|
||||
timeout.tick().await;
|
||||
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
Some(result) = event_stream.next() => {
|
||||
@@ -161,9 +166,9 @@ impl UpdateMonitor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add a small delay before reconnecting to avoid tight reconnection loops
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,11 +42,11 @@ impl DbusRegistry {
|
||||
R: IntoIterator<Item = dbus_crossroads::IfaceToken<T>>,
|
||||
{
|
||||
let dbus_path = String::from(path);
|
||||
|
||||
|
||||
let mut cr = self.crossroads.lock().unwrap();
|
||||
let tokens: Vec<_> = register_fn(&mut cr).into_iter().collect();
|
||||
cr.insert(dbus_path, &tokens, implementation);
|
||||
|
||||
|
||||
// Start message handler if not already started
|
||||
let mut handler_started = self.message_handler_started.lock().unwrap();
|
||||
if !*handler_started {
|
||||
|
||||
@@ -13,4 +13,4 @@ pub mod interface {
|
||||
pub use crate::interface::NetBuzzertKordophoneRepositoryConversationsUpdated as ConversationsUpdated;
|
||||
pub use crate::interface::NetBuzzertKordophoneRepositoryMessagesUpdated as MessagesUpdated;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ use tokio::sync::oneshot;
|
||||
|
||||
use crate::daemon::{
|
||||
events::{Event, Reply},
|
||||
settings::Settings, DaemonResult,
|
||||
settings::Settings,
|
||||
DaemonResult,
|
||||
};
|
||||
|
||||
use crate::dbus::interface::NetBuzzertKordophoneRepository as DbusRepository;
|
||||
@@ -136,52 +137,82 @@ impl DbusRepository for ServerImpl {
|
||||
"sender".into(),
|
||||
arg::Variant(Box::new(msg.sender.display_name())),
|
||||
);
|
||||
|
||||
|
||||
// Add attachments array
|
||||
let attachments: Vec<arg::PropMap> = msg.attachments
|
||||
let attachments: Vec<arg::PropMap> = msg
|
||||
.attachments
|
||||
.into_iter()
|
||||
.map(|attachment| {
|
||||
let mut attachment_map = arg::PropMap::new();
|
||||
attachment_map.insert("guid".into(), arg::Variant(Box::new(attachment.guid.clone())));
|
||||
|
||||
attachment_map.insert(
|
||||
"guid".into(),
|
||||
arg::Variant(Box::new(attachment.guid.clone())),
|
||||
);
|
||||
|
||||
// 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)));
|
||||
|
||||
|
||||
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)));
|
||||
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)));
|
||||
attribution_map.insert(
|
||||
"height".into(),
|
||||
arg::Variant(Box::new(height as i32)),
|
||||
);
|
||||
}
|
||||
|
||||
metadata_map.insert("attribution_info".into(), arg::Variant(Box::new(attribution_map)));
|
||||
|
||||
metadata_map.insert(
|
||||
"attribution_info".into(),
|
||||
arg::Variant(Box::new(attribution_map)),
|
||||
);
|
||||
}
|
||||
|
||||
attachment_map.insert("metadata".into(), arg::Variant(Box::new(metadata_map)));
|
||||
|
||||
attachment_map.insert(
|
||||
"metadata".into(),
|
||||
arg::Variant(Box::new(metadata_map)),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
attachment_map
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
map.insert("attachments".into(), arg::Variant(Box::new(attachments)));
|
||||
|
||||
|
||||
map
|
||||
})
|
||||
.collect()
|
||||
@@ -216,20 +247,21 @@ impl DbusRepository for ServerImpl {
|
||||
(
|
||||
// - path: string
|
||||
path.to_string_lossy().to_string(),
|
||||
|
||||
// - preview_path: string
|
||||
preview_path.to_string_lossy().to_string(),
|
||||
|
||||
// - downloaded: boolean
|
||||
downloaded,
|
||||
|
||||
// - preview_downloaded: boolean
|
||||
preview_downloaded,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn download_attachment(&mut self, attachment_id: String, preview: bool) -> Result<(), dbus::MethodErr> {
|
||||
fn download_attachment(
|
||||
&mut self,
|
||||
attachment_id: String,
|
||||
preview: bool,
|
||||
) -> Result<(), dbus::MethodErr> {
|
||||
// For now, just trigger the download event - we'll implement the actual download logic later
|
||||
self.send_event_sync(|r| Event::DownloadAttachment(attachment_id, preview, r))
|
||||
}
|
||||
@@ -286,7 +318,6 @@ impl DbusSettings for ServerImpl {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn run_sync_future<F, T>(f: F) -> Result<T, MethodErr>
|
||||
where
|
||||
T: Send,
|
||||
|
||||
@@ -60,14 +60,12 @@ async fn main() {
|
||||
// Create and register server implementation
|
||||
let server = ServerImpl::new(daemon.event_sender.clone());
|
||||
|
||||
dbus_registry.register_object(
|
||||
interface::OBJECT_PATH,
|
||||
server,
|
||||
|cr| vec![
|
||||
dbus_registry.register_object(interface::OBJECT_PATH, server, |cr| {
|
||||
vec![
|
||||
interface::register_net_buzzert_kordophone_repository(cr),
|
||||
interface::register_net_buzzert_kordophone_settings(cr),
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
let mut signal_receiver = daemon.obtain_signal_receiver();
|
||||
tokio::spawn(async move {
|
||||
|
||||
Reference in New Issue
Block a user