agent: config.rs — rename AgentConfig to RunOptions, add Clone, windows_service field, to_service_args()

This commit is contained in:
Butterfly Dev 2026-04-07 05:32:32 +00:00
parent eae74e9d7d
commit 7a44809a41

View File

@ -1,14 +1,20 @@
//! Agent configuration parsed from CLI arguments and environment variables. //! Agent run configuration — shared options for `run` and `service install`.
//!
//! This struct holds all the operational parameters for the Butterfly agent:
//! server address, encoding, frame rate, quality, etc. It is used both when
//! running in foreground mode (`butterfly-agent run`) and when embedding
//! these options into a system service definition (`butterfly-agent service install`).
use clap::Parser; use clap::Args;
use std::time::Duration; use std::time::Duration;
/// Butterfly Desktop Agent — captures display from this machine and streams /// Operational options for running the Butterfly agent.
/// it to a Butterfly server. Also receives and executes HUD commands (mouse, ///
/// keyboard) from remote viewers for full remote control. /// These options control how the agent connects, captures, encodes, and streams.
#[derive(Parser, Debug)] /// They are shared between foreground mode and service installation (the service
#[command(name = "butterfly-agent", version, about)] /// definition embeds these options so the agent runs with the same configuration).
pub struct AgentConfig { #[derive(Args, Debug, Clone)]
pub struct RunOptions {
/// WebSocket URL of the Butterfly server. /// WebSocket URL of the Butterfly server.
/// ///
/// Example: ws://192.168.1.100:8080 /// Example: ws://192.168.1.100:8080
@ -52,14 +58,18 @@ pub struct AgentConfig {
/// Maximum reconnection attempts (0 = infinite). /// Maximum reconnection attempts (0 = infinite).
#[arg(long, default_value_t = 0, env = "BUTTERFLY_MAX_RECONNECT")] #[arg(long, default_value_t = 0, env = "BUTTERFLY_MAX_RECONNECT")]
pub max_reconnect: u32, pub max_reconnect: u32,
/// (Windows only, internal) Run as a Windows Service.
/// This flag is set automatically when the service installer registers the
/// agent with the Windows Service Control Manager. It should not be used
/// manually — the SCM uses it to signal that the agent should connect to
/// the service dispatcher instead of running in the foreground.
#[cfg(windows)]
#[arg(long, hide = true)]
pub windows_service: bool,
} }
impl AgentConfig { impl RunOptions {
/// Parse configuration from CLI arguments.
pub fn parse_args() -> Self {
Self::parse()
}
/// Duration between captured frames. /// Duration between captured frames.
pub fn frame_interval(&self) -> Duration { pub fn frame_interval(&self) -> Duration {
Duration::from_secs_f64(1.0 / self.fps as f64) Duration::from_secs_f64(1.0 / self.fps as f64)
@ -91,4 +101,45 @@ impl AgentConfig {
self.server.replace("ws://", "http://").replace("wss://", "https://") self.server.replace("ws://", "http://").replace("wss://", "https://")
) )
} }
/// Build the command-line arguments vector for embedding in service definitions.
///
/// Returns something like `["run", "--server", "ws://...", "--encoder", "h264", ...]`.
/// The "run" subcommand is included so the service knows to start in agent mode.
pub fn to_service_args(&self) -> Vec<String> {
let mut args = vec!["run".to_string()];
args.push(format!("--server={}", self.server));
if let Some(ref sid) = self.session_id {
args.push(format!("--session-id={}", sid));
}
if self.fps != 60 {
args.push(format!("--fps={}", self.fps));
}
if self.encoder != "h264" {
args.push(format!("--encoder={}", self.encoder));
}
if self.quality != 60 {
args.push(format!("--quality={}", self.quality));
}
if self.display != 0 {
args.push(format!("--display={}", self.display));
}
if self.audio {
args.push("--audio".to_string());
}
if self.heartbeat_secs != 15 {
args.push(format!("--heartbeat={}", self.heartbeat_secs));
}
if self.reconnect_delay_secs != 3 {
args.push(format!("--reconnect-delay={}", self.reconnect_delay_secs));
}
if self.max_reconnect != 0 {
args.push(format!("--max-reconnect={}", self.max_reconnect));
}
args
}
} }