use crate::ui_protocol::AgentEvent;
use anyhow::{Context, Result};
use std::time::Duration;
use tokio::process::Command;
use tracing::{debug, warn};
const PIPE_TIMEOUT: Duration = Duration::from_secs(5);
pub fn emit_event(session: &str, event: &AgentEvent) -> Result<()> {
let json = serde_json::to_string(event).context("Failed to serialize event")?;
let plugin_path = format!(
"file:{}/.config/zellij/plugins/exomonad-plugin.wasm",
std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string())
);
debug!(
"[ZellijEvents] Spawning async emit to session {}: {}",
session, json
);
let session_owned = session.to_string();
tokio::spawn(emit_with_timeout(session_owned, plugin_path, json));
Ok(())
}
async fn emit_with_timeout(session: String, plugin_path: String, json: String) {
let child_result = Command::new("zellij")
.arg("--session")
.arg(&session)
.args([
"pipe",
"--plugin",
&plugin_path,
"--name",
"exomonad-events",
"--",
&json,
])
.spawn();
let mut child = match child_result {
Ok(c) => c,
Err(e) => {
warn!("[ZellijEvents] Failed to spawn zellij pipe: {}", e);
return;
}
};
match tokio::time::timeout(PIPE_TIMEOUT, child.wait()).await {
Ok(Ok(status)) => {
if !status.success() {
warn!("[ZellijEvents] zellij pipe exited with status: {}", status);
}
}
Ok(Err(e)) => {
warn!("[ZellijEvents] zellij pipe wait error: {}", e);
}
Err(_) => {
warn!(
"[ZellijEvents] zellij pipe timed out after {:?}, killing",
PIPE_TIMEOUT
);
let _ = child.kill().await;
}
}
}
pub fn now_iso8601() -> String {
chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true)
}