xpc: kpcli: clean up client interface
This commit is contained in:
@@ -9,7 +9,8 @@ mod dbus;
|
||||
#[cfg(target_os = "macos")]
|
||||
mod xpc;
|
||||
|
||||
#[async_trait]
|
||||
#[cfg_attr(target_os = "macos", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_os = "macos"), async_trait)]
|
||||
pub trait DaemonInterface {
|
||||
async fn print_version(&mut self) -> Result<()>;
|
||||
async fn print_conversations(&mut self) -> Result<()>;
|
||||
@@ -40,7 +41,8 @@ impl StubDaemonInterface {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
#[cfg_attr(target_os = "macos", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_os = "macos"), async_trait)]
|
||||
impl DaemonInterface for StubDaemonInterface {
|
||||
async fn print_version(&mut self) -> Result<()> {
|
||||
Err(anyhow::anyhow!(
|
||||
|
||||
@@ -111,49 +111,55 @@ impl XpcDaemonInterface {
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self)
|
||||
}
|
||||
|
||||
fn build_service_name() -> Result<CString> {
|
||||
let service_name = SERVICE_NAME.trim_end_matches('\0');
|
||||
Ok(CString::new(service_name)?)
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
fn build_request(method: &str, args: Option<HashMap<CString, Message>>) -> HashMap<CString, Message> {
|
||||
let mut request = HashMap::new();
|
||||
request.insert(CString::new("method").unwrap(), Message::String(CString::new(method).unwrap()));
|
||||
if let Some(arguments) = args {
|
||||
request.insert(CString::new("arguments").unwrap(), Message::Dictionary(arguments));
|
||||
}
|
||||
request
|
||||
}
|
||||
|
||||
async fn call_method(&self, client: &mut XPCClient, method: &str, args: Option<HashMap<CString, Message>>) -> anyhow::Result<HashMap<CString, Message>> {
|
||||
let request = Self::build_request(method, args);
|
||||
client.send_message(Message::Dictionary(request));
|
||||
|
||||
match client.next().await {
|
||||
Some(Message::Dictionary(map)) => Ok(map),
|
||||
Some(other) => Err(anyhow::anyhow!("Unexpected XPC reply: {:?}", other)),
|
||||
None => Err(anyhow::anyhow!("No reply received from XPC daemon")),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_string<'a>(map: &'a HashMap<CString, Message>, key: &str) -> Option<&'a CStr> {
|
||||
map.get(&CString::new(key).ok()?).and_then(|v| match v { Message::String(s) => Some(s.as_c_str()), _ => None })
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl DaemonInterface for XpcDaemonInterface {
|
||||
async fn print_version(&mut self) -> Result<()> {
|
||||
// Build service name CString (trim trailing NUL from const)
|
||||
let service_name = SERVICE_NAME.trim_end_matches('\0');
|
||||
let mach_port_name = CString::new(service_name)?;
|
||||
|
||||
// Open an XPC connection to the daemon service
|
||||
// Build service name and connect
|
||||
let mach_port_name = Self::build_service_name()?;
|
||||
let mut client = XPCClient::connect(&mach_port_name);
|
||||
|
||||
// Send a GetVersion request as a dictionary message: { method: "GetVersion" }
|
||||
{
|
||||
let mut request = HashMap::new();
|
||||
request.insert(
|
||||
CString::new("method").unwrap(),
|
||||
Message::String(CString::new(GET_VERSION_METHOD).unwrap()),
|
||||
);
|
||||
client.send_message(Message::Dictionary(request));
|
||||
}
|
||||
|
||||
// Await a single reply and print the version
|
||||
match client.next().await {
|
||||
Some(Message::Dictionary(map)) => {
|
||||
if let Some(Message::String(ver)) = map.get(&CString::new("version").unwrap()) {
|
||||
// Call generic method and parse reply
|
||||
let map = self.call_method(&mut client, GET_VERSION_METHOD, None).await?;
|
||||
if let Some(ver) = Self::get_string(&map, "version") {
|
||||
println!("Server version: {}", ver.to_string_lossy());
|
||||
} else if let Some(Message::String(ty)) = map.get(&CString::new("type").unwrap())
|
||||
{
|
||||
println!("XPC replied with type: {}", ty.to_string_lossy());
|
||||
} else {
|
||||
eprintln!("Unexpected XPC reply payload for GetVersion");
|
||||
}
|
||||
}
|
||||
Some(other) => {
|
||||
eprintln!("Unexpected XPC reply: {:?}", other);
|
||||
}
|
||||
None => {
|
||||
eprintln!("No reply received from XPC daemon");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
} else if let Some(ty) = Self::get_string(&map, "type") {
|
||||
println!("XPC replied with type: {}", ty.to_string_lossy());
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow::anyhow!("Unexpected XPC reply payload for GetVersion"))
|
||||
}
|
||||
}
|
||||
|
||||
// Remaining methods unimplemented on macOS
|
||||
|
||||
Reference in New Issue
Block a user