feat: add bridge-ctl CLI for runtime control
Made-with: Cursor
This commit is contained in:
@@ -1,3 +1,93 @@
|
|||||||
fn main() {
|
use std::io::{BufRead, BufReader, Write};
|
||||||
println!("bridge-ctl");
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user