1use super::app::AppContext;
2use super::commands::{Cli, Commands};
3use super::error::CliResult;
4#[cfg(feature = "docker")]
5use super::handle_docker;
6#[cfg(feature = "kubernetes")]
7use super::handle_kubernetes;
8#[cfg(feature = "monitoring")]
9use super::handle_monitoring;
10#[cfg(feature = "nordvpn")]
11use super::handle_nordvpn;
12#[cfg(feature = "secrets")]
13use super::handle_secrets;
14use super::{
15 handle_api, handle_commit, handle_config, handle_curl, handle_diag, handle_done, handle_env,
16 handle_cloudflared, handle_flush, handle_generate, handle_init, handle_install, handle_list,
17 handle_login, handle_logs, handle_logs_flag, handle_monitor, handle_network, handle_nginx,
18 handle_no_command, handle_ports, handle_redeploy, handle_redeploy_v2, handle_resurrect,
19 handle_service, handle_ssh,
20 handle_services, handle_setup, handle_snapshot, handle_start, handle_stop, handle_tail,
21 handle_version,
22};
23use std::future::Future;
24use std::pin::Pin;
25
26type DispatchFuture<'a> = Pin<Box<dyn Future<Output = CliResult<()>> + 'a>>;
27
28pub fn dispatch(cli: Cli, ctx: &mut AppContext) -> DispatchFuture<'_> {
29 let debug = ctx.debug();
30 let Cli {
31 logs,
32 list,
33 port,
34 command,
35 ..
36 } = cli;
37
38 if logs {
39 return Box::pin(handle_logs_flag());
40 }
41
42 if list && command.is_none() {
43 return Box::pin(handle_list(debug));
44 }
45
46 match command {
47 Some(Commands::Ports(cmd)) => Box::pin(handle_ports(cmd, port, debug)),
48 Some(Commands::Commit(cmd)) => Box::pin(handle_commit(cmd)),
49 Some(Commands::Init) => Box::pin(handle_init(debug)),
50 Some(Commands::Setup) => Box::pin(handle_setup(debug)),
51 Some(Commands::Redeploy { service_name }) => Box::pin(handle_redeploy(service_name, debug)),
52 Some(Commands::RedeployV2(cmd)) => Box::pin(handle_redeploy_v2(cmd, debug)),
53 Some(Commands::Config(cmd)) => Box::pin(handle_config(cmd, debug)),
54 Some(Commands::Install { list, package }) => Box::pin(handle_install(package, list, debug)),
55 Some(Commands::Logs(cmd)) => Box::pin(handle_logs(cmd, debug)),
56 Some(Commands::Ssh(cmd)) => Box::pin(handle_ssh(cmd, debug)),
57 Some(Commands::Cloudflared(cmd)) => Box::pin(handle_cloudflared(cmd, debug)),
58 Some(Commands::List) => Box::pin(handle_list(debug)),
59 Some(Commands::Curl(cmd)) => Box::pin(handle_curl(cmd, debug)),
60 Some(Commands::Services) => Box::pin(handle_services(debug)),
61 Some(Commands::Service {
62 command,
63 service_name,
64 }) => Box::pin(handle_service(command, service_name, debug)),
65 Some(Commands::Nginx(cmd)) => Box::pin(handle_nginx(cmd.command, debug)),
66 Some(Commands::Network(cmd)) => Box::pin(handle_network(cmd, debug)),
67 Some(Commands::Diag(cmd)) => Box::pin(handle_diag(cmd, debug)),
68 Some(Commands::Monitor(cmd)) => Box::pin(handle_monitor(cmd, debug)),
69 Some(Commands::Snapshot) => Box::pin(handle_snapshot(debug)),
70 Some(Commands::Resurrect) => Box::pin(handle_resurrect(debug)),
71 Some(Commands::Stop { target }) => Box::pin(handle_stop(target, debug)),
72 Some(Commands::Flush { target }) => Box::pin(handle_flush(target, debug)),
73 Some(Commands::Login) => Box::pin(handle_login()),
74 Some(Commands::Version(cmd)) => Box::pin(handle_version(cmd, debug)),
75 Some(Commands::Env { target }) => Box::pin(handle_env(target, debug)),
76 Some(Commands::Tail(cmd)) => Box::pin(handle_tail(cmd, debug)),
77 Some(Commands::Start { args }) => Box::pin(handle_start(args, debug)),
78 Some(Commands::Generate(cmd)) => Box::pin(handle_generate(cmd, debug)),
79 Some(Commands::Api(cmd)) => Box::pin(handle_api(cmd, debug)),
80 #[cfg(feature = "docker")]
81 Some(Commands::Docker(cmd)) => Box::pin(handle_docker(cmd, debug)),
82 #[cfg(feature = "secrets")]
83 Some(Commands::Secrets(cmd)) => Box::pin(handle_secrets(cmd, debug)),
84 Some(Commands::Done(cmd)) => Box::pin(handle_done(cmd, debug)),
85 #[cfg(feature = "kubernetes")]
86 Some(Commands::Kubernetes(cmd)) => Box::pin(handle_kubernetes(cmd, debug)),
87 #[cfg(feature = "nordvpn")]
88 Some(Commands::Nordvpn(cmd)) => Box::pin(handle_nordvpn(cmd, debug)),
89 #[cfg(feature = "monitoring")]
90 Some(Commands::Monitoring(cmd)) => Box::pin(handle_monitoring(cmd)),
91 None => {
92 Box::pin(handle_no_command(port, debug))
94 }
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 use clap::Parser;
102
103 #[test]
104 fn dispatch_future_is_boxed_and_small() {
105 let cli = Cli::parse_from(["xbp", "login"]);
106 let mut ctx = AppContext::new(false);
107 let future = dispatch(cli, &mut ctx);
108 assert!(std::mem::size_of_val(&future) <= 2 * std::mem::size_of::<usize>());
109 }
110}