feat: add bridge-ctl CLI for runtime control

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-10 22:01:27 -04:00
parent f4717832f0
commit f82cbfea79

View File

@@ -1,3 +1,93 @@
fn main() {
println!("bridge-ctl");
use std::io::{BufRead, BufReader, Write};
use std::os::unix::net::UnixStream;
use std::path::PathBuf;
use std::time::Duration;
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(name = "bridge-ctl")]
#[command(about = "Control a running owncast-irc-bridge instance")]
struct Cli {
/// Path to the bridge control socket
#[arg(short, long, default_value = "/tmp/owncast-irc-bridge.sock")]
socket: PathBuf,
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Show bridge status
Status,
/// Control IRC connection
Irc {
#[command(subcommand)]
action: ConnectionAction,
},
/// Control Owncast connection
Owncast {
#[command(subcommand)]
action: ConnectionAction,
},
/// Shut down the bridge
Quit,
}
#[derive(Subcommand)]
enum ConnectionAction {
Connect,
Disconnect,
Reconnect,
}
fn main() {
let cli = Cli::parse();
let command_str = match &cli.command {
Commands::Status => "status".to_string(),
Commands::Quit => "quit".to_string(),
Commands::Irc { action } => format!("irc {}", action_str(action)),
Commands::Owncast { action } => format!("owncast {}", action_str(action)),
};
match send_command(&cli.socket, &command_str) {
Ok(response) => print!("{response}"),
Err(e) => {
eprintln!("Error: {e}");
std::process::exit(1);
}
}
}
fn action_str(action: &ConnectionAction) -> &'static str {
match action {
ConnectionAction::Connect => "connect",
ConnectionAction::Disconnect => "disconnect",
ConnectionAction::Reconnect => "reconnect",
}
}
fn send_command(socket_path: &PathBuf, command: &str) -> Result<String, Box<dyn std::error::Error>> {
let mut stream = UnixStream::connect(socket_path)?;
stream.set_read_timeout(Some(Duration::from_secs(5)))?;
writeln!(stream, "{command}")?;
stream.flush()?;
let reader = BufReader::new(stream);
let mut response = String::new();
for line in reader.lines() {
match line {
Ok(l) => {
response.push_str(&l);
response.push('\n');
}
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => break,
Err(ref e) if e.kind() == std::io::ErrorKind::TimedOut => break,
Err(e) => return Err(e.into()),
}
}
Ok(response)
}