pub mod client;
pub mod commands;
pub mod config;
pub mod error;
pub mod output;
pub mod templates;
pub mod tui;
pub mod utils;
use clap::{Parser, Subcommand};
#[derive(Debug, Parser)]
#[command(name = "theater")]
#[command(author, version, about, long_about = None)]
pub struct Cli {
#[arg(short, long, global = true)]
pub verbose: bool,
#[arg(long, global = true)]
pub json: bool,
#[command(subcommand)]
pub command: Commands,
}
#[derive(Debug, Subcommand)]
pub enum Commands {
#[command(name = "create")]
Create(commands::create::CreateArgs),
#[command(name = "build")]
Build(commands::build::BuildArgs),
#[command(name = "start")]
Start(commands::start::StartArgs),
#[command(name = "subscribe")]
Subscribe(commands::subscribe::SubscribeArgs),
#[command(name = "list")]
List(commands::list::ListArgs),
#[command(name = "state")]
State(commands::state::StateArgs),
#[command(name = "events")]
Events(commands::events::EventsArgs),
#[command(name = "events-explore")]
EventsExplore(commands::events_explore::ExploreArgs),
#[command(name = "inspect")]
Inspect(commands::inspect::InspectArgs),
#[command(name = "stop")]
Stop(commands::stop::StopArgs),
#[command(name = "message")]
Message(commands::message::MessageArgs),
#[command(name = "list-stored")]
ListStored(commands::list_stored::ListStoredArgs),
#[command(name = "channel")]
Channel(commands::channel::ChannelArgs),
#[command(name = "completion")]
Completion(commands::completion::CompletionArgs),
#[command(name = "dynamic-completion", hide = true)]
DynamicCompletion(commands::dynamic_completion::DynamicCompletionArgs),
}
pub async fn run(
cli: Cli,
config: config::Config,
_shutdown_rx: tokio::sync::oneshot::Receiver<()>,
) -> anyhow::Result<()> {
let output = output::OutputManager::new(config.output.clone());
let ctx = CommandContext {
config,
output,
verbose: cli.verbose,
json: cli.json,
};
let result = match &cli.command {
Commands::Subscribe(args) => commands::subscribe::execute_async(args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e)),
Commands::Create(args) => commands::create::execute_async(args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e)),
Commands::Build(args) => commands::build::execute_async(args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e)),
Commands::List(args) => commands::list::execute_async(args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e)),
Commands::State(args) => commands::state::execute_async(args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e)),
Commands::Events(args) => commands::events::execute_async(args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e)),
Commands::EventsExplore(args) => commands::events_explore::execute_async(args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e)),
Commands::Inspect(args) => commands::inspect::execute_async(args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e)),
Commands::Start(args) => commands::start::execute_async(args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e)),
Commands::Stop(args) => commands::stop::execute_async(args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e)),
Commands::Message(args) => commands::message::execute_async(args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e)),
Commands::Channel(args) => match &args.command {
commands::channel::ChannelCommands::Open(open_args) => {
commands::channel::open::execute_async(open_args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e))
}
},
Commands::ListStored(args) => commands::list_stored::execute_async(args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e)),
Commands::Completion(args) => commands::completion::execute_async(args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e)),
Commands::DynamicCompletion(args) => {
commands::dynamic_completion::execute_async(args, &ctx)
.await
.map_err(|e| anyhow::Error::from(e))
}
};
match result {
Ok(()) => Ok(()),
Err(e) => {
if let Some(cli_error) = e.downcast_ref::<error::CliError>() {
ctx.output.error(&cli_error.user_message())?;
if ctx.verbose {
eprintln!("\nDebug info: {:?}", cli_error);
}
} else {
ctx.output.error(&format!("Error: {}", e))?;
if ctx.verbose {
eprintln!("\nDebug info: {:?}", e);
}
}
std::process::exit(1);
}
}
}
pub struct CommandContext {
pub config: config::Config,
pub output: output::OutputManager,
pub verbose: bool,
pub json: bool,
}
impl CommandContext {
pub fn create_client(&self) -> client::TheaterClient {
client::TheaterClient::new(self.config.server.default_address)
}
pub fn server_address(
&self,
override_addr: Option<std::net::SocketAddr>,
) -> std::net::SocketAddr {
override_addr.unwrap_or(self.config.server.default_address)
}
}