use std::sync::Arc;
use kanade_shared::ipc::handshake::HandshakeResult;
use kanade_shared::ipc::system::PingResult;
use tauri::State;
use tokio::sync::Mutex;
use tracing::{info, warn};
use crate::klp_client::KlpClient;
pub struct AppState {
klp: Arc<Mutex<Option<KlpClient>>>,
}
#[tauri::command]
async fn get_handshake(state: State<'_, AppState>) -> Result<HandshakeResult, String> {
let guard = state.klp.lock().await;
match guard.as_ref() {
Some(client) => Ok((*client.handshake()).clone()),
None => Err("agent not connected (pipe unavailable on startup)".into()),
}
}
#[tauri::command]
async fn ping_agent(state: State<'_, AppState>) -> Result<PingResult, String> {
let client = {
let guard = state.klp.lock().await;
guard
.as_ref()
.cloned()
.ok_or_else(|| "agent not connected".to_string())?
};
client.ping().await.map_err(|e| e.to_string())
}
pub fn run() {
let state = AppState {
klp: Arc::new(Mutex::new(None)),
};
let klp_slot = state.klp.clone();
tauri::Builder::default()
.manage(state)
.invoke_handler(tauri::generate_handler![get_handshake, ping_agent])
.setup(move |_app| {
let slot = klp_slot.clone();
tauri::async_runtime::spawn(async move {
loop {
match KlpClient::connect().await {
Ok(client) => {
info!(
agent_version = %client.handshake().agent_version,
"KLP client ready",
);
*slot.lock().await = Some(client);
return;
}
Err(e) => {
warn!(
error = %e,
"KLP client connect failed; retrying in 5s",
);
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
}
}
}
});
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running kanade-client tauri application");
}