use kordophoned::daemon::signals::Signal; use std::collections::HashMap; use std::ffi::CString; 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 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, }) } 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, } } pub fn dict_get_i64_from_str(map: &HashMap, key: &str) -> Option { dict_get_str(map, key).and_then(|s| s.parse::().ok()) } 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 array_from_strs(values: impl IntoIterator) -> Message { let arr = values .into_iter() .map(|s| Message::String(cstr(&s))) .collect(); Message::Array(arr) } pub fn make_ok_reply() -> Message { let mut reply: XpcMap = HashMap::new(); dict_put_str(&mut reply, "type", "Ok"); Message::Dictionary(reply) } pub fn make_error_reply(code: &str, message: &str) -> Message { let mut reply: HashMap = HashMap::new(); reply.insert(cstr("type"), Message::String(cstr("Error"))); reply.insert(cstr("error"), Message::String(cstr(code))); reply.insert(cstr("message"), Message::String(cstr(message))); Message::Dictionary(reply) } pub fn attach_request_id(mut message: Message, request_id: Option) -> Message { if let (Some(id), Message::Dictionary(ref mut m)) = (request_id, &mut message) { dict_put_str(m, "request_id", &id); } message } pub fn signal_to_message(signal: Signal) -> Message { let mut root: XpcMap = HashMap::new(); let mut args: XpcMap = HashMap::new(); match signal { Signal::ConversationsUpdated => { dict_put_str(&mut root, "name", "ConversationsUpdated"); } Signal::MessagesUpdated(conversation_id) => { dict_put_str(&mut root, "name", "MessagesUpdated"); dict_put_str(&mut args, "conversation_id", &conversation_id); } Signal::AttachmentDownloaded(attachment_id) => { dict_put_str(&mut root, "name", "AttachmentDownloadCompleted"); dict_put_str(&mut args, "attachment_id", &attachment_id); } Signal::AttachmentUploaded(upload_guid, attachment_guid) => { dict_put_str(&mut root, "name", "AttachmentUploadCompleted"); dict_put_str(&mut args, "upload_guid", &upload_guid); dict_put_str(&mut args, "attachment_guid", &attachment_guid); } Signal::UpdateStreamReconnected => { dict_put_str(&mut root, "name", "UpdateStreamReconnected"); } } if !args.is_empty() { root.insert(cstr("arguments"), Message::Dictionary(args)); } Message::Dictionary(root) }