#![cfg(target_os = "macos")] //! macOS XPC implementation of the DaemonInterface for kpcli. use super::{ConfigCommands, DaemonInterface}; use anyhow::Result; use async_trait::async_trait; use futures::stream::StreamExt; use futures::executor::block_on; use std::collections::HashMap; use xpc_connection::{Message, XpcConnection}; const SERVICE_NAME: &str = "net.buzzert.kordophonecd\0"; const GET_VERSION_METHOD: &str = "GetVersion\0"; /// XPC-based implementation of DaemonInterface that sends method calls to the daemon over libxpc. pub struct XpcDaemonInterface; impl XpcDaemonInterface { /// Create a new XpcDaemonInterface. No state is held. pub fn new() -> Result { Ok(Self) } } #[async_trait] impl DaemonInterface for XpcDaemonInterface { async fn print_version(&mut self) -> Result<()> { // Open an XPC connection to the daemon service let mut conn = XpcConnection::new(SERVICE_NAME); let mut incoming = conn.connect(); // Send a GetVersion request as a dictionary message let mut dict = HashMap::new(); dict.insert( GET_VERSION_METHOD.to_string(), Message::String(String::new()), ); conn.send_message(Message::Dictionary(dict)); // Wait for a single string reply (futures-preview StreamFuture returns (Option, Stream)) let (opt_msg, _) = match block_on(incoming.next()) { Ok(pair) => pair, Err(e) => { eprintln!("Error reading XPC reply: {:?}", e); return Ok(()); } }; if let Some(Message::String(ver_raw)) = opt_msg { // Trim the trailing NUL if present let version = ver_raw.trim_end_matches('\0'); println!("Server version: {}", version); } else { eprintln!("Unexpected XPC reply for GetVersion"); } Ok(()) } // Remaining methods unimplemented on macOS async fn print_conversations(&mut self) -> Result<()> { Err(anyhow::anyhow!("Feature not implemented for XPC")) } async fn sync_conversations(&mut self, _conversation_id: Option) -> Result<()> { Err(anyhow::anyhow!("Feature not implemented for XPC")) } async fn sync_conversations_list(&mut self) -> Result<()> { Err(anyhow::anyhow!("Feature not implemented for XPC")) } async fn print_messages( &mut self, _conversation_id: String, _last_message_id: Option, ) -> Result<()> { Err(anyhow::anyhow!("Feature not implemented for XPC")) } async fn enqueue_outgoing_message( &mut self, _conversation_id: String, _text: String, ) -> Result<()> { Err(anyhow::anyhow!("Feature not implemented for XPC")) } async fn wait_for_signals(&mut self) -> Result<()> { Err(anyhow::anyhow!("Feature not implemented for XPC")) } async fn config(&mut self, _cmd: ConfigCommands) -> Result<()> { Err(anyhow::anyhow!("Feature not implemented for XPC")) } async fn delete_all_conversations(&mut self) -> Result<()> { Err(anyhow::anyhow!("Feature not implemented for XPC")) } async fn download_attachment(&mut self, _attachment_id: String) -> Result<()> { Err(anyhow::anyhow!("Feature not implemented for XPC")) } async fn upload_attachment(&mut self, _path: String) -> Result<()> { Err(anyhow::anyhow!("Feature not implemented for XPC")) } async fn mark_conversation_as_read(&mut self, _conversation_id: String) -> Result<()> { Err(anyhow::anyhow!("Feature not implemented for XPC")) } }