use std::time::Duration;
use wdotool_core::recorder::{self, BackendChoice, RecorderConfig};
use wdotool_core::{Result, WdoError};
pub async fn run(
output: Option<String>,
max_duration_secs: Option<u64>,
backend_arg: String,
) -> anyhow::Result<()> {
let backend = parse_backend(&backend_arg)?;
let config = RecorderConfig {
backend,
..RecorderConfig::default()
};
let session = recorder::start(config).await?;
eprintln!(
"wdotool record: capturing via {:?} backend (Ctrl-C to stop{}{})",
session.source(),
max_duration_secs
.map(|s| format!(" or after {s}s"))
.unwrap_or_default(),
match output.as_deref() {
Some(path) if path != "-" => format!(", writing to {path}"),
_ => " (writing to stdout)".to_string(),
}
);
let stop_reason = tokio::select! {
ctrl_c = tokio::signal::ctrl_c() => {
ctrl_c.map_err(|e| WdoError::Backend {
backend: "recorder",
source: format!("ctrl_c handler install failed: {e}").into(),
})?;
"ctrl-c"
}
_ = async {
match max_duration_secs {
Some(secs) => tokio::time::sleep(Duration::from_secs(secs)).await,
None => std::future::pending::<()>().await,
}
} => "max-duration",
};
let events = session.stop().await?;
eprintln!(
"wdotool record: stopped via {stop_reason}, captured {} event{}",
events.len(),
if events.len() == 1 { "" } else { "s" }
);
let json = serde_json::to_string_pretty(&events)
.map_err(|e| WdoError::InvalidArg(format!("recorder serialization: {e}")))?;
match output.as_deref() {
None | Some("-") => {
println!("{json}");
}
Some(path) => {
std::fs::write(path, format!("{json}\n"))
.map_err(|e| WdoError::InvalidArg(format!("failed to write {path}: {e}")))?;
eprintln!("wdotool record: wrote {path}");
}
}
Ok(())
}
fn parse_backend(s: &str) -> Result<BackendChoice> {
match s {
"auto" => Ok(BackendChoice::Auto),
"portal" => Ok(BackendChoice::Portal),
"evdev" => Ok(BackendChoice::Evdev),
"simulated" => Ok(BackendChoice::Simulated),
other => Err(WdoError::InvalidArg(format!(
"unknown record backend {other:?} (expected: auto, portal, evdev, simulated)"
))),
}
}