|
|
|
|
@@ -1,14 +1,13 @@
|
|
|
|
|
use kordophoned::daemon::{events::Event, signals::Signal, DaemonResult};
|
|
|
|
|
use crate::xpc::interface::SERVICE_NAME;
|
|
|
|
|
use futures_util::StreamExt;
|
|
|
|
|
use kordophoned::daemon::{events::Event, signals::Signal, DaemonResult};
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
use std::ffi::CString;
|
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
use tokio::sync::{mpsc, oneshot, Mutex};
|
|
|
|
|
use std::thread;
|
|
|
|
|
use tokio::sync::{mpsc, oneshot, Mutex};
|
|
|
|
|
use xpc_connection::{Message, MessageError, XpcClient, XpcListener};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static LOG_TARGET: &str = "xpc";
|
|
|
|
|
|
|
|
|
|
/// XPC IPC agent that forwards daemon events and signals over libxpc.
|
|
|
|
|
@@ -83,7 +82,9 @@ impl XpcAgent {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn cstr(s: &str) -> CString { CString::new(s).unwrap_or_else(|_| CString::new("").unwrap()) }
|
|
|
|
|
fn cstr(s: &str) -> CString {
|
|
|
|
|
CString::new(s).unwrap_or_else(|_| CString::new("").unwrap())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_string_field(map: &HashMap<CString, Message>, key: &str) -> Option<String> {
|
|
|
|
|
let k = CString::new(key).ok()?;
|
|
|
|
|
@@ -93,7 +94,10 @@ fn get_string_field(map: &HashMap<CString, Message>, key: &str) -> Option<String
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_dictionary_field<'a>(map: &'a HashMap<CString, Message>, key: &str) -> Option<&'a HashMap<CString, Message>> {
|
|
|
|
|
fn get_dictionary_field<'a>(
|
|
|
|
|
map: &'a HashMap<CString, Message>,
|
|
|
|
|
key: &str,
|
|
|
|
|
) -> Option<&'a HashMap<CString, Message>> {
|
|
|
|
|
let k = CString::new(key).ok()?;
|
|
|
|
|
map.get(&k).and_then(|v| match v {
|
|
|
|
|
Message::Dictionary(d) => Some(d),
|
|
|
|
|
@@ -106,7 +110,7 @@ fn make_error_reply(code: &str, message: &str) -> Message {
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -151,17 +155,15 @@ async fn dispatch(agent: &XpcAgent, root: &HashMap<CString, Message>) -> Message
|
|
|
|
|
|
|
|
|
|
match method.as_str() {
|
|
|
|
|
// Example implemented method: GetVersion
|
|
|
|
|
"GetVersion" => {
|
|
|
|
|
match agent.send_event(Event::GetVersion).await {
|
|
|
|
|
Ok(version) => {
|
|
|
|
|
let mut reply: XpcMap = HashMap::new();
|
|
|
|
|
dict_put_str(&mut reply, "type", "GetVersionResponse");
|
|
|
|
|
dict_put_str(&mut reply, "version", &version);
|
|
|
|
|
Message::Dictionary(reply)
|
|
|
|
|
}
|
|
|
|
|
Err(e) => make_error_reply("DaemonError", &format!("{}", e)),
|
|
|
|
|
"GetVersion" => match agent.send_event(Event::GetVersion).await {
|
|
|
|
|
Ok(version) => {
|
|
|
|
|
let mut reply: XpcMap = HashMap::new();
|
|
|
|
|
dict_put_str(&mut reply, "type", "GetVersionResponse");
|
|
|
|
|
dict_put_str(&mut reply, "version", &version);
|
|
|
|
|
Message::Dictionary(reply)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Err(e) => make_error_reply("DaemonError", &format!("{}", e)),
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
"GetConversations" => {
|
|
|
|
|
// Defaults
|
|
|
|
|
@@ -169,20 +171,35 @@ async fn dispatch(agent: &XpcAgent, root: &HashMap<CString, Message>) -> Message
|
|
|
|
|
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) => {
|
|
|
|
|
// Build array of conversation dictionaries
|
|
|
|
|
let mut items: Vec<Message> = 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());
|
|
|
|
|
dict_put_str(
|
|
|
|
|
&mut m,
|
|
|
|
|
"last_message_preview",
|
|
|
|
|
&conv.last_message_preview.unwrap_or_default(),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// participants -> array of strings
|
|
|
|
|
let participant_names: Vec<String> = conv
|
|
|
|
|
|