diff --git a/kordophoned/src/xpc/agent.rs b/kordophoned/src/xpc/agent.rs index 3260683..3e4baaf 100644 --- a/kordophoned/src/xpc/agent.rs +++ b/kordophoned/src/xpc/agent.rs @@ -27,7 +27,10 @@ pub struct XpcAgent { impl XpcAgent { pub fn new(event_sink: mpsc::Sender, signal_receiver: mpsc::Receiver) -> Self { - Self { event_sink, signal_receiver: Arc::new(Mutex::new(Some(signal_receiver))) } + Self { + event_sink, + signal_receiver: Arc::new(Mutex::new(Some(signal_receiver))), + } } pub async fn run(self) { @@ -179,4 +182,3 @@ impl XpcAgent { rx.await.map_err(|_| "Failed to receive reply".into()) } } - diff --git a/kordophoned/src/xpc/rpc.rs b/kordophoned/src/xpc/rpc.rs index 1647db1..9d199a1 100644 --- a/kordophoned/src/xpc/rpc.rs +++ b/kordophoned/src/xpc/rpc.rs @@ -10,7 +10,7 @@ use super::util::*; pub async fn dispatch( agent: &XpcAgent, - subscribers: &std::sync::Mutex>, + subscribers: &std::sync::Mutex>, current_client: xpc_sys::xpc_connection_t, root: &HashMap, ) -> Message { @@ -18,7 +18,12 @@ pub async fn dispatch( let method = match dict_get_str(root, "method").or_else(|| dict_get_str(root, "type")) { Some(m) => m, - None => return attach_request_id(make_error_reply("InvalidRequest", "Missing method/type"), request_id), + None => { + return attach_request_id( + make_error_reply("InvalidRequest", "Missing method/type"), + request_id, + ) + } }; let _arguments = get_dictionary_field(root, "arguments"); @@ -40,19 +45,38 @@ pub async fn dispatch( let mut limit: i32 = 100; let mut offset: i32 = 0; if let Some(args) = get_dictionary_field(root, "arguments") { - if let Some(v) = dict_get_i64_from_str(args, "limit") { limit = v as i32; } - if let Some(v) = dict_get_i64_from_str(args, "offset") { offset = v as i32; } + if let Some(v) = dict_get_i64_from_str(args, "limit") { + limit = v as i32; + } + if let Some(v) = dict_get_i64_from_str(args, "offset") { + offset = v as i32; + } } - match agent.send_event(|r| Event::GetAllConversations(limit, offset, r)).await { + match agent + .send_event(|r| Event::GetAllConversations(limit, offset, r)) + .await + { Ok(conversations) => { let mut items: Vec = Vec::with_capacity(conversations.len()); for conv in conversations { let mut m: XpcMap = HashMap::new(); dict_put_str(&mut m, "guid", &conv.guid); - dict_put_str(&mut m, "display_name", &conv.display_name.unwrap_or_default()); + dict_put_str( + &mut m, + "display_name", + &conv.display_name.unwrap_or_default(), + ); dict_put_i64_as_str(&mut m, "unread_count", conv.unread_count as i64); - dict_put_str(&mut m, "last_message_preview", &conv.last_message_preview.unwrap_or_default()); - let participant_names: Vec = conv.participants.into_iter().map(|p| p.display_name()).collect(); + dict_put_str( + &mut m, + "last_message_preview", + &conv.last_message_preview.unwrap_or_default(), + ); + let participant_names: Vec = conv + .participants + .into_iter() + .map(|p| p.display_name()) + .collect(); m.insert(cstr("participants"), array_from_strs(participant_names)); dict_put_i64_as_str(&mut m, "date", conv.date.and_utc().timestamp()); items.push(Message::Dictionary(m)); @@ -76,11 +100,16 @@ pub async fn dispatch( 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)), } @@ -88,11 +117,16 @@ pub async fn dispatch( // Mark as read "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)), } @@ -100,10 +134,19 @@ pub async fn dispatch( // GetMessages "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 { @@ -131,14 +174,29 @@ pub async fn dispatch( // SendMessage "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"); @@ -151,16 +209,41 @@ pub async fn dispatch( // GetAttachmentInfo "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)), @@ -169,10 +252,21 @@ pub async fn dispatch( // DownloadAttachment "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)), } @@ -181,9 +275,18 @@ pub async fn dispatch( // UploadAttachment "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"); @@ -199,18 +302,36 @@ pub async fn dispatch( 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()); + 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)), } @@ -224,7 +345,7 @@ pub async fn dispatch( log::trace!(target: LOG_TARGET, "Client subscribed to signals (total subscribers: {})", list.len()); } make_ok_reply() - }, + } // Unknown method fallback other => make_error_reply("UnknownMethod", other), diff --git a/kordophoned/src/xpc/util.rs b/kordophoned/src/xpc/util.rs index 2889c72..8efcb81 100644 --- a/kordophoned/src/xpc/util.rs +++ b/kordophoned/src/xpc/util.rs @@ -5,19 +5,27 @@ use xpc_connection::Message; pub type XpcMap = HashMap; -pub fn cstr(s: &str) -> CString { CString::new(s).unwrap_or_else(|_| CString::new("").unwrap()) } +pub fn cstr(s: &str) -> CString { + CString::new(s).unwrap_or_else(|_| CString::new("").unwrap()) +} pub fn get_dictionary_field<'a>( map: &'a HashMap, key: &str, ) -> Option<&'a HashMap> { let k = CString::new(key).ok()?; - map.get(&k).and_then(|v| match v { Message::Dictionary(d) => Some(d), _ => None }) + map.get(&k).and_then(|v| match v { + Message::Dictionary(d) => Some(d), + _ => None, + }) } pub fn dict_get_str(map: &HashMap, key: &str) -> Option { let k = CString::new(key).ok()?; - match map.get(&k) { Some(Message::String(v)) => Some(v.to_string_lossy().into_owned()), _ => None } + match map.get(&k) { + Some(Message::String(v)) => Some(v.to_string_lossy().into_owned()), + _ => None, + } } pub fn dict_get_i64_from_str(map: &HashMap, key: &str) -> Option { @@ -28,10 +36,15 @@ pub fn dict_put_str(map: &mut XpcMap, key: &str, value: impl AsRef) { map.insert(cstr(key), Message::String(cstr(value.as_ref()))); } -pub fn dict_put_i64_as_str(map: &mut XpcMap, key: &str, value: i64) { dict_put_str(map, key, value.to_string()); } +pub fn dict_put_i64_as_str(map: &mut XpcMap, key: &str, value: i64) { + dict_put_str(map, key, value.to_string()); +} pub fn array_from_strs(values: impl IntoIterator) -> Message { - let arr = values.into_iter().map(|s| Message::String(cstr(&s))).collect(); + let arr = values + .into_iter() + .map(|s| Message::String(cstr(&s))) + .collect(); Message::Array(arr) } diff --git a/kpcli/src/daemon/xpc.rs b/kpcli/src/daemon/xpc.rs index bada46e..e703781 100644 --- a/kpcli/src/daemon/xpc.rs +++ b/kpcli/src/daemon/xpc.rs @@ -495,7 +495,7 @@ impl DaemonInterface for XpcDaemonInterface { } Message::Error(xpc_connection::MessageError::ConnectionInvalid) => { eprintln!("[kpcli] XPC connection invalid"); - break + break; } other => { eprintln!("[kpcli] Unexpected XPC message: {:?}", other);