diff --git a/kordophoned/src/xpc/agent.rs b/kordophoned/src/xpc/agent.rs index f9bb2aa..cd7b0b3 100644 --- a/kordophoned/src/xpc/agent.rs +++ b/kordophoned/src/xpc/agent.rs @@ -1,7 +1,7 @@ use crate::xpc::interface::SERVICE_NAME; use futures_util::StreamExt; -use kordophoned::daemon::{events::Event, signals::Signal, DaemonResult}; use kordophoned::daemon::settings::Settings; +use kordophoned::daemon::{events::Event, signals::Signal, DaemonResult}; use std::collections::HashMap; use std::ffi::CString; use std::sync::Arc; @@ -252,47 +252,62 @@ async fn dispatch(agent: &XpcAgent, root: &HashMap) -> Message } } - "SyncConversationList" => { - match agent.send_event(Event::SyncConversationList).await { - Ok(()) => make_ok_reply(), - Err(e) => make_error_reply("DaemonError", &format!("{}", e)), - } - } + "SyncConversationList" => match agent.send_event(Event::SyncConversationList).await { + Ok(()) => make_ok_reply(), + Err(e) => make_error_reply("DaemonError", &format!("{}", e)), + }, - "SyncAllConversations" => { - match agent.send_event(Event::SyncAllConversations).await { - Ok(()) => make_ok_reply(), - Err(e) => make_error_reply("DaemonError", &format!("{}", e)), - } - } + "SyncAllConversations" => match agent.send_event(Event::SyncAllConversations).await { + Ok(()) => make_ok_reply(), + Err(e) => make_error_reply("DaemonError", &format!("{}", e)), + }, "SyncConversation" => { - let conversation_id = match get_dictionary_field(root, "arguments").and_then(|m| dict_get_str(m, "conversation_id")) { + let conversation_id = match get_dictionary_field(root, "arguments") + .and_then(|m| dict_get_str(m, "conversation_id")) + { Some(id) => id, None => return make_error_reply("InvalidRequest", "Missing conversation_id"), }; - match agent.send_event(|r| Event::SyncConversation(conversation_id, r)).await { + match agent + .send_event(|r| Event::SyncConversation(conversation_id, r)) + .await + { Ok(()) => make_ok_reply(), Err(e) => make_error_reply("DaemonError", &format!("{}", e)), } } "MarkConversationAsRead" => { - let conversation_id = match get_dictionary_field(root, "arguments").and_then(|m| dict_get_str(m, "conversation_id")) { + let conversation_id = match get_dictionary_field(root, "arguments") + .and_then(|m| dict_get_str(m, "conversation_id")) + { Some(id) => id, None => return make_error_reply("InvalidRequest", "Missing conversation_id"), }; - match agent.send_event(|r| Event::MarkConversationAsRead(conversation_id, r)).await { + match agent + .send_event(|r| Event::MarkConversationAsRead(conversation_id, r)) + .await + { Ok(()) => make_ok_reply(), Err(e) => make_error_reply("DaemonError", &format!("{}", e)), } } "GetMessages" => { - let args = match get_dictionary_field(root, "arguments") { Some(a) => a, None => return make_error_reply("InvalidRequest", "Missing arguments") }; - let conversation_id = match dict_get_str(args, "conversation_id") { Some(id) => id, None => return make_error_reply("InvalidRequest", "Missing conversation_id") }; + let args = match get_dictionary_field(root, "arguments") { + Some(a) => a, + None => return make_error_reply("InvalidRequest", "Missing arguments"), + }; + let conversation_id = match dict_get_str(args, "conversation_id") { + Some(id) => id, + None => return make_error_reply("InvalidRequest", "Missing conversation_id"), + }; let last_message_id = dict_get_str(args, "last_message_id"); - match agent.send_event(|r| Event::GetMessages(conversation_id, last_message_id, r)).await { + match agent + .send_event(|r| Event::GetMessages(conversation_id, last_message_id, r)) + .await + { Ok(messages) => { let mut items: Vec = Vec::with_capacity(messages.len()); for msg in messages { @@ -312,22 +327,35 @@ async fn dispatch(agent: &XpcAgent, root: &HashMap) -> Message } } - "DeleteAllConversations" => { - match agent.send_event(Event::DeleteAllConversations).await { - Ok(()) => make_ok_reply(), - Err(e) => make_error_reply("DaemonError", &format!("{}", e)), - } - } + "DeleteAllConversations" => match agent.send_event(Event::DeleteAllConversations).await { + Ok(()) => make_ok_reply(), + Err(e) => make_error_reply("DaemonError", &format!("{}", e)), + }, "SendMessage" => { - let args = match get_dictionary_field(root, "arguments") { Some(a) => a, None => return make_error_reply("InvalidRequest", "Missing arguments") }; - let conversation_id = match dict_get_str(args, "conversation_id") { Some(v) => v, None => return make_error_reply("InvalidRequest", "Missing conversation_id") }; + let args = match get_dictionary_field(root, "arguments") { + Some(a) => a, + None => return make_error_reply("InvalidRequest", "Missing arguments"), + }; + let conversation_id = match dict_get_str(args, "conversation_id") { + Some(v) => v, + None => return make_error_reply("InvalidRequest", "Missing conversation_id"), + }; let text = dict_get_str(args, "text").unwrap_or_default(); let attachment_guids: Vec = match args.get(&cstr("attachment_guids")) { - Some(Message::Array(arr)) => arr.iter().filter_map(|m| match m { Message::String(s) => Some(s.to_string_lossy().into_owned()), _ => None }).collect(), + Some(Message::Array(arr)) => arr + .iter() + .filter_map(|m| match m { + Message::String(s) => Some(s.to_string_lossy().into_owned()), + _ => None, + }) + .collect(), _ => Vec::new(), }; - match agent.send_event(|r| Event::SendMessage(conversation_id, text, attachment_guids, r)).await { + match agent + .send_event(|r| Event::SendMessage(conversation_id, text, attachment_guids, r)) + .await + { Ok(uuid) => { let mut reply: XpcMap = HashMap::new(); dict_put_str(&mut reply, "type", "SendMessageResponse"); @@ -339,16 +367,41 @@ async fn dispatch(agent: &XpcAgent, root: &HashMap) -> Message } "GetAttachmentInfo" => { - let args = match get_dictionary_field(root, "arguments") { Some(a) => a, None => return make_error_reply("InvalidRequest", "Missing arguments") }; - let attachment_id = match dict_get_str(args, "attachment_id") { Some(v) => v, None => return make_error_reply("InvalidRequest", "Missing attachment_id") }; - match agent.send_event(|r| Event::GetAttachment(attachment_id, r)).await { + let args = match get_dictionary_field(root, "arguments") { + Some(a) => a, + None => return make_error_reply("InvalidRequest", "Missing arguments"), + }; + let attachment_id = match dict_get_str(args, "attachment_id") { + Some(v) => v, + None => return make_error_reply("InvalidRequest", "Missing attachment_id"), + }; + match agent + .send_event(|r| Event::GetAttachment(attachment_id, r)) + .await + { Ok(attachment) => { let mut reply: XpcMap = HashMap::new(); dict_put_str(&mut reply, "type", "GetAttachmentInfoResponse"); - dict_put_str(&mut reply, "path", &attachment.get_path_for_preview(false).to_string_lossy()); - dict_put_str(&mut reply, "preview_path", &attachment.get_path_for_preview(true).to_string_lossy()); - dict_put_str(&mut reply, "downloaded", &attachment.is_downloaded(false).to_string()); - dict_put_str(&mut reply, "preview_downloaded", &attachment.is_downloaded(true).to_string()); + dict_put_str( + &mut reply, + "path", + &attachment.get_path_for_preview(false).to_string_lossy(), + ); + dict_put_str( + &mut reply, + "preview_path", + &attachment.get_path_for_preview(true).to_string_lossy(), + ); + dict_put_str( + &mut reply, + "downloaded", + &attachment.is_downloaded(false).to_string(), + ); + dict_put_str( + &mut reply, + "preview_downloaded", + &attachment.is_downloaded(true).to_string(), + ); Message::Dictionary(reply) } Err(e) => make_error_reply("DaemonError", &format!("{}", e)), @@ -356,10 +409,21 @@ async fn dispatch(agent: &XpcAgent, root: &HashMap) -> Message } "DownloadAttachment" => { - let args = match get_dictionary_field(root, "arguments") { Some(a) => a, None => return make_error_reply("InvalidRequest", "Missing arguments") }; - let attachment_id = match dict_get_str(args, "attachment_id") { Some(v) => v, None => return make_error_reply("InvalidRequest", "Missing attachment_id") }; - let preview = dict_get_str(args, "preview").map(|s| s == "true").unwrap_or(false); - match agent.send_event(|r| Event::DownloadAttachment(attachment_id, preview, r)).await { + let args = match get_dictionary_field(root, "arguments") { + Some(a) => a, + None => return make_error_reply("InvalidRequest", "Missing arguments"), + }; + let attachment_id = match dict_get_str(args, "attachment_id") { + Some(v) => v, + None => return make_error_reply("InvalidRequest", "Missing attachment_id"), + }; + let preview = dict_get_str(args, "preview") + .map(|s| s == "true") + .unwrap_or(false); + match agent + .send_event(|r| Event::DownloadAttachment(attachment_id, preview, r)) + .await + { Ok(()) => make_ok_reply(), Err(e) => make_error_reply("DaemonError", &format!("{}", e)), } @@ -367,9 +431,18 @@ async fn dispatch(agent: &XpcAgent, root: &HashMap) -> Message "UploadAttachment" => { use std::path::PathBuf; - let args = match get_dictionary_field(root, "arguments") { Some(a) => a, None => return make_error_reply("InvalidRequest", "Missing arguments") }; - let path = match dict_get_str(args, "path") { Some(v) => v, None => return make_error_reply("InvalidRequest", "Missing path") }; - match agent.send_event(|r| Event::UploadAttachment(PathBuf::from(path), r)).await { + let args = match get_dictionary_field(root, "arguments") { + Some(a) => a, + None => return make_error_reply("InvalidRequest", "Missing arguments"), + }; + let path = match dict_get_str(args, "path") { + Some(v) => v, + None => return make_error_reply("InvalidRequest", "Missing path"), + }; + match agent + .send_event(|r| Event::UploadAttachment(PathBuf::from(path), r)) + .await + { Ok(upload_guid) => { let mut reply: XpcMap = HashMap::new(); dict_put_str(&mut reply, "type", "UploadAttachmentResponse"); @@ -380,34 +453,48 @@ async fn dispatch(agent: &XpcAgent, root: &HashMap) -> Message } } - "GetAllSettings" => { - match agent.send_event(Event::GetAllSettings).await { - Ok(settings) => { - let mut reply: XpcMap = HashMap::new(); - dict_put_str(&mut reply, "type", "GetAllSettingsResponse"); - dict_put_str(&mut reply, "server_url", &settings.server_url.unwrap_or_default()); - dict_put_str(&mut reply, "username", &settings.username.unwrap_or_default()); - Message::Dictionary(reply) - } - Err(e) => make_error_reply("DaemonError", &format!("{}", e)), + "GetAllSettings" => match agent.send_event(Event::GetAllSettings).await { + Ok(settings) => { + let mut reply: XpcMap = HashMap::new(); + dict_put_str(&mut reply, "type", "GetAllSettingsResponse"); + dict_put_str( + &mut reply, + "server_url", + &settings.server_url.unwrap_or_default(), + ); + dict_put_str( + &mut reply, + "username", + &settings.username.unwrap_or_default(), + ); + Message::Dictionary(reply) } - } + Err(e) => make_error_reply("DaemonError", &format!("{}", e)), + }, "UpdateSettings" => { - let args = match get_dictionary_field(root, "arguments") { Some(a) => a, None => return make_error_reply("InvalidRequest", "Missing arguments") }; + let args = match get_dictionary_field(root, "arguments") { + Some(a) => a, + None => return make_error_reply("InvalidRequest", "Missing arguments"), + }; let server_url = dict_get_str(args, "server_url"); let username = dict_get_str(args, "username"); - let settings = Settings { server_url, username, token: None }; - match agent.send_event(|r| Event::UpdateSettings(settings, r)).await { + let settings = Settings { + server_url, + username, + token: None, + }; + match agent + .send_event(|r| Event::UpdateSettings(settings, r)) + .await + { Ok(()) => make_ok_reply(), Err(e) => make_error_reply("DaemonError", &format!("{}", e)), } } // No-op used by clients to ensure the connection is established and subscribed - "SubscribeSignals" => { - make_ok_reply() - } + "SubscribeSignals" => make_ok_reply(), // Unknown method fallback other => make_error_reply("UnknownMethod", other), @@ -438,11 +525,17 @@ fn signal_to_message(signal: Signal) -> Message { dict_put_str(&mut root, "name", "UpdateStreamReconnected"); } } - if !args.is_empty() { root.insert(cstr("arguments"), Message::Dictionary(args)); } + if !args.is_empty() { + root.insert(cstr("arguments"), Message::Dictionary(args)); + } Message::Dictionary(root) } -async fn handle_client(agent: XpcAgent, mut client: XpcClient, mut signal_rx: broadcast::Receiver) { +async fn handle_client( + agent: XpcAgent, + mut client: XpcClient, + mut signal_rx: broadcast::Receiver, +) { log::info!(target: LOG_TARGET, "New XPC connection"); loop { diff --git a/kpcli/src/daemon/xpc.rs b/kpcli/src/daemon/xpc.rs index fae71d0..d67d9c2 100644 --- a/kpcli/src/daemon/xpc.rs +++ b/kpcli/src/daemon/xpc.rs @@ -278,18 +278,27 @@ impl DaemonInterface for XpcDaemonInterface { if let Some(id) = _conversation_id { let mut args = HashMap::new(); - args.insert(Self::key("conversation_id"), Message::String(CString::new(id).unwrap())); - let _ = self.call_method(&mut client, "SyncConversation", Some(args)).await?; + args.insert( + Self::key("conversation_id"), + Message::String(CString::new(id).unwrap()), + ); + let _ = self + .call_method(&mut client, "SyncConversation", Some(args)) + .await?; return Ok(()); } - let _ = self.call_method(&mut client, "SyncAllConversations", None).await?; + let _ = self + .call_method(&mut client, "SyncAllConversations", None) + .await?; Ok(()) } async fn sync_conversations_list(&mut self) -> Result<()> { let mach_port_name = Self::build_service_name()?; let mut client = XPCClient::connect(&mach_port_name); - let _ = self.call_method(&mut client, "SyncConversationList", None).await?; + let _ = self + .call_method(&mut client, "SyncConversationList", None) + .await?; Ok(()) } async fn print_messages( @@ -301,24 +310,39 @@ impl DaemonInterface for XpcDaemonInterface { let mut client = XPCClient::connect(&mach_port_name); let mut args = HashMap::new(); - args.insert(Self::key("conversation_id"), Message::String(CString::new(_conversation_id).unwrap())); + args.insert( + Self::key("conversation_id"), + Message::String(CString::new(_conversation_id).unwrap()), + ); if let Some(last) = _last_message_id { - args.insert(Self::key("last_message_id"), Message::String(CString::new(last).unwrap())); + args.insert( + Self::key("last_message_id"), + Message::String(CString::new(last).unwrap()), + ); } - let reply = self.call_method(&mut client, "GetMessages", Some(args)).await?; + let reply = self + .call_method(&mut client, "GetMessages", Some(args)) + .await?; match reply.get(&Self::key("messages")) { Some(Message::Array(items)) => { println!("Number of messages: {}", items.len()); for item in items { if let Message::Dictionary(map) = item { - let guid = Self::get_string(map, "id").map(|s| s.to_string_lossy().into_owned()).unwrap_or_default(); - let sender = Self::get_string(map, "sender").map(|s| s.to_string_lossy().into_owned()).unwrap_or_default(); - let text = Self::get_string(map, "text").map(|s| s.to_string_lossy().into_owned()).unwrap_or_default(); + let guid = Self::get_string(map, "id") + .map(|s| s.to_string_lossy().into_owned()) + .unwrap_or_default(); + let sender = Self::get_string(map, "sender") + .map(|s| s.to_string_lossy().into_owned()) + .unwrap_or_default(); + let text = Self::get_string(map, "text") + .map(|s| s.to_string_lossy().into_owned()) + .unwrap_or_default(); let date_ts = Self::get_i64_from_str(map, "date").unwrap_or(0); let msg = crate::printers::PrintableMessage { guid, - date: time::OffsetDateTime::from_unix_timestamp(date_ts).unwrap_or_else(|_| time::OffsetDateTime::UNIX_EPOCH), + date: time::OffsetDateTime::from_unix_timestamp(date_ts) + .unwrap_or_else(|_| time::OffsetDateTime::UNIX_EPOCH), sender, text, file_transfer_guids: vec![], @@ -340,10 +364,20 @@ impl DaemonInterface for XpcDaemonInterface { let mach_port_name = Self::build_service_name()?; let mut client = XPCClient::connect(&mach_port_name); let mut args = HashMap::new(); - args.insert(Self::key("conversation_id"), Message::String(CString::new(_conversation_id).unwrap())); - args.insert(Self::key("text"), Message::String(CString::new(_text).unwrap())); - let reply = self.call_method(&mut client, "SendMessage", Some(args)).await?; - if let Some(uuid) = Self::get_string(&reply, "uuid") { println!("Outgoing message ID: {}", uuid.to_string_lossy()); } + args.insert( + Self::key("conversation_id"), + Message::String(CString::new(_conversation_id).unwrap()), + ); + args.insert( + Self::key("text"), + Message::String(CString::new(_text).unwrap()), + ); + let reply = self + .call_method(&mut client, "SendMessage", Some(args)) + .await?; + if let Some(uuid) = Self::get_string(&reply, "uuid") { + println!("Outgoing message ID: {}", uuid.to_string_lossy()); + } Ok(()) } async fn wait_for_signals(&mut self) -> Result<()> { @@ -351,7 +385,10 @@ impl DaemonInterface for XpcDaemonInterface { let mut client = XPCClient::connect(&mach_port_name); // Send a subscription/warm-up message so the server loop starts selecting for this client - client.send_message(Message::Dictionary(Self::build_request("SubscribeSignals", None))); + client.send_message(Message::Dictionary(Self::build_request( + "SubscribeSignals", + None, + ))); println!("Waiting for XPC signals..."); while let Some(msg) = client.next().await { @@ -359,7 +396,10 @@ impl DaemonInterface for XpcDaemonInterface { Message::Dictionary(map) => { let name_key = Self::key("name"); let args_key = Self::key("arguments"); - let name = match map.get(&name_key) { Some(Message::String(s)) => s.to_string_lossy().into_owned(), _ => continue }; + let name = match map.get(&name_key) { + Some(Message::String(s)) => s.to_string_lossy().into_owned(), + _ => continue, + }; match name.as_str() { "ConversationsUpdated" => { @@ -367,8 +407,13 @@ impl DaemonInterface for XpcDaemonInterface { } "MessagesUpdated" => { if let Some(Message::Dictionary(args)) = map.get(&args_key) { - if let Some(Message::String(cid)) = args.get(&Self::key("conversation_id")) { - println!("Signal: Messages updated for conversation {}", cid.to_string_lossy()); + if let Some(Message::String(cid)) = + args.get(&Self::key("conversation_id")) + { + println!( + "Signal: Messages updated for conversation {}", + cid.to_string_lossy() + ); } } } @@ -377,23 +422,52 @@ impl DaemonInterface for XpcDaemonInterface { } "AttachmentDownloadCompleted" => { if let Some(Message::Dictionary(args)) = map.get(&args_key) { - if let Some(Message::String(aid)) = args.get(&Self::key("attachment_id")) { - println!("Signal: Attachment downloaded: {}", aid.to_string_lossy()); + if let Some(Message::String(aid)) = + args.get(&Self::key("attachment_id")) + { + println!( + "Signal: Attachment downloaded: {}", + aid.to_string_lossy() + ); } } } "AttachmentDownloadFailed" => { if let Some(Message::Dictionary(args)) = map.get(&args_key) { - if let Some(Message::String(aid)) = args.get(&Self::key("attachment_id")) { - eprintln!("Signal: Attachment download failed: {}", aid.to_string_lossy()); + if let Some(Message::String(aid)) = + args.get(&Self::key("attachment_id")) + { + eprintln!( + "Signal: Attachment download failed: {}", + aid.to_string_lossy() + ); } } } "AttachmentUploadCompleted" => { if let Some(Message::Dictionary(args)) = map.get(&args_key) { - let upload = args.get(&Self::key("upload_guid")).and_then(|v| match v { Message::String(s) => Some(s.to_string_lossy().into_owned()), _ => None }).unwrap_or_default(); - let attachment = args.get(&Self::key("attachment_guid")).and_then(|v| match v { Message::String(s) => Some(s.to_string_lossy().into_owned()), _ => None }).unwrap_or_default(); - println!("Signal: Attachment uploaded: upload={}, attachment={}", upload, attachment); + let upload = args + .get(&Self::key("upload_guid")) + .and_then(|v| match v { + Message::String(s) => { + Some(s.to_string_lossy().into_owned()) + } + _ => None, + }) + .unwrap_or_default(); + let attachment = args + .get(&Self::key("attachment_guid")) + .and_then(|v| match v { + Message::String(s) => { + Some(s.to_string_lossy().into_owned()) + } + _ => None, + }) + .unwrap_or_default(); + println!( + "Signal: Attachment uploaded: upload={}, attachment={}", + upload, attachment + ); } } "ConfigChanged" => { @@ -413,23 +487,40 @@ impl DaemonInterface for XpcDaemonInterface { let mut client = XPCClient::connect(&mach_port_name); match _cmd { ConfigCommands::Print => { - let reply = self.call_method(&mut client, "GetAllSettings", None).await?; - let server_url = Self::get_string(&reply, "server_url").map(|s| s.to_string_lossy().into_owned()).unwrap_or_default(); - let username = Self::get_string(&reply, "username").map(|s| s.to_string_lossy().into_owned()).unwrap_or_default(); - let table = prettytable::table!([b->"Server URL", &server_url], [b->"Username", &username]); + let reply = self + .call_method(&mut client, "GetAllSettings", None) + .await?; + let server_url = Self::get_string(&reply, "server_url") + .map(|s| s.to_string_lossy().into_owned()) + .unwrap_or_default(); + let username = Self::get_string(&reply, "username") + .map(|s| s.to_string_lossy().into_owned()) + .unwrap_or_default(); + let table = + prettytable::table!([b->"Server URL", &server_url], [b->"Username", &username]); table.printstd(); Ok(()) } ConfigCommands::SetServerUrl { url } => { let mut args = HashMap::new(); - args.insert(Self::key("server_url"), Message::String(CString::new(url).unwrap())); - let _ = self.call_method(&mut client, "UpdateSettings", Some(args)).await?; + args.insert( + Self::key("server_url"), + Message::String(CString::new(url).unwrap()), + ); + let _ = self + .call_method(&mut client, "UpdateSettings", Some(args)) + .await?; Ok(()) } ConfigCommands::SetUsername { username } => { let mut args = HashMap::new(); - args.insert(Self::key("username"), Message::String(CString::new(username).unwrap())); - let _ = self.call_method(&mut client, "UpdateSettings", Some(args)).await?; + args.insert( + Self::key("username"), + Message::String(CString::new(username).unwrap()), + ); + let _ = self + .call_method(&mut client, "UpdateSettings", Some(args)) + .await?; Ok(()) } } @@ -437,33 +528,55 @@ impl DaemonInterface for XpcDaemonInterface { async fn delete_all_conversations(&mut self) -> Result<()> { let mach_port_name = Self::build_service_name()?; let mut client = XPCClient::connect(&mach_port_name); - let _ = self.call_method(&mut client, "DeleteAllConversations", None).await?; + let _ = self + .call_method(&mut client, "DeleteAllConversations", None) + .await?; Ok(()) } async fn download_attachment(&mut self, _attachment_id: String) -> Result<()> { let mach_port_name = Self::build_service_name()?; let mut client = XPCClient::connect(&mach_port_name); let mut args = HashMap::new(); - args.insert(Self::key("attachment_id"), Message::String(CString::new(_attachment_id).unwrap())); - args.insert(Self::key("preview"), Message::String(CString::new("false").unwrap())); - let _ = self.call_method(&mut client, "DownloadAttachment", Some(args)).await?; + args.insert( + Self::key("attachment_id"), + Message::String(CString::new(_attachment_id).unwrap()), + ); + args.insert( + Self::key("preview"), + Message::String(CString::new("false").unwrap()), + ); + let _ = self + .call_method(&mut client, "DownloadAttachment", Some(args)) + .await?; Ok(()) } async fn upload_attachment(&mut self, _path: String) -> Result<()> { let mach_port_name = Self::build_service_name()?; let mut client = XPCClient::connect(&mach_port_name); let mut args = HashMap::new(); - args.insert(Self::key("path"), Message::String(CString::new(_path).unwrap())); - let reply = self.call_method(&mut client, "UploadAttachment", Some(args)).await?; - if let Some(guid) = Self::get_string(&reply, "upload_guid") { println!("Upload GUID: {}", guid.to_string_lossy()); } + args.insert( + Self::key("path"), + Message::String(CString::new(_path).unwrap()), + ); + let reply = self + .call_method(&mut client, "UploadAttachment", Some(args)) + .await?; + if let Some(guid) = Self::get_string(&reply, "upload_guid") { + println!("Upload GUID: {}", guid.to_string_lossy()); + } Ok(()) } async fn mark_conversation_as_read(&mut self, _conversation_id: String) -> Result<()> { let mach_port_name = Self::build_service_name()?; let mut client = XPCClient::connect(&mach_port_name); let mut args = HashMap::new(); - args.insert(Self::key("conversation_id"), Message::String(CString::new(_conversation_id).unwrap())); - let _ = self.call_method(&mut client, "MarkConversationAsRead", Some(args)).await?; + args.insert( + Self::key("conversation_id"), + Message::String(CString::new(_conversation_id).unwrap()), + ); + let _ = self + .call_method(&mut client, "MarkConversationAsRead", Some(args)) + .await?; Ok(()) } }