Skip to main content

quorum_private/cli/
help.rs

1//! Main cli file used for getting help with server commands
2
3use colored::Colorize;
4
5struct CommandEntry {
6    command: &'static str,                           //full command
7    summary: &'static str,                           //one line description
8    description: &'static str,                       //the full command description
9    usage: &'static str,                             //example usage
10    requires_auth: bool,                             //whether login is required first
11    requires_admin: bool,                            //whether admin privileges are required
12    params: &'static [(&'static str, &'static str)], //parameter names and what they mean
13}
14
15const COMMANDS: &[CommandEntry] = &[
16    // --help--
17    CommandEntry {
18        command: "help",
19        summary: "Lists all available commands.",
20        description: "Prints a summary of every available command, grouped by namespace.",
21        usage: "help",
22        requires_auth: false,
23        requires_admin: false,
24        params: &[],
25    },
26    CommandEntry {
27        command: "help <command>",
28        summary: "Shows detailed help for a specific command.",
29        description: "Prints the full description, usage, parameters, and auth requirement for the given command.",
30        usage: "help server:status",
31        requires_auth: false,
32        requires_admin: false,
33        params: &[("command", "The command to look up, e.g. server:status")],
34    },
35    // --server--
36    CommandEntry {
37        command: "server:login",
38        summary: "Authenticates an operator session in the terminal.",
39        description: "Prompts for a username and password and verifies them against the database. On success, grants access to write/destructive commands for the next 20 minutes of inactivity.",
40        usage: "server:login",
41        requires_auth: false,
42        requires_admin: false,
43        params: &[],
44    },
45    CommandEntry {
46        command: "server:status",
47        summary: "Shows uptime and basic server info.",
48        description: "Prints how long the server has been running, what address it is listening on, and whether testing mode is active.",
49        usage: "server:status",
50        requires_auth: false,
51        requires_admin: false,
52        params: &[],
53    },
54    CommandEntry {
55        command: "server:logout",
56        summary: "Ends the current operator session.",
57        description: "Clears the authenticated session immediately. Any subsequent write commands will require logging in again.",
58        usage: "server:logout",
59        requires_auth: true,
60        requires_admin: false,
61        params: &[],
62    },
63    CommandEntry {
64        command: "server:shutdown",
65        summary: "Gracefully shuts the server down.",
66        description: "Signals the server to stop accepting new requests, waits for in-flight requests to complete, flushes logs, and exits cleanly.",
67        usage: "server:shutdown",
68        requires_auth: true,
69        requires_admin: true,
70        params: &[],
71    },
72    CommandEntry {
73        command: "server:logs",
74        summary: "Displays recent server logs.",
75        description: "Prints logs in order from most recent to oldest, allowing for optional filter for last X days.",
76        usage: "server:logs [days]",
77        requires_auth: false,
78        requires_admin: false,
79        params: &[("days", "Optional number of days to display logs for")],
80    },
81    CommandEntry {
82        command: "server:audit",
83        summary: "Displays recent audit logs.",
84        description: "Prints audit logs in order from most recent to oldest, allowing for optional filter for last X days.",
85        usage: "server:audit [days]",
86        requires_auth: false,
87        requires_admin: false,
88        params: &[("days", "Optional number of days to display audit logs for")],
89    },
90    // --db--
91    CommandEntry {
92        command: "db:stats",
93        summary: "Displays database statistics.",
94        description: "Prints the number of rows in each table, total row count, and estimated size of each table and database.",
95        usage: "db:stats",
96        requires_auth: false,
97        requires_admin: false,
98        params: &[],
99    },
100    CommandEntry {
101        command: "db:table",
102        summary: "Displays records from a specific table.",
103        description: "Prints the records from the specified table, with an option to view a specific page of results.",
104        usage: "db:table <name>, <page>",
105        requires_auth: false,
106        requires_admin: false,
107        params: &[
108            ("name", "The name of the table to display"),
109            ("page", "The page of results to display"),
110        ],
111    },
112];
113
114/// Prints a summary of all available commands, grouped by namespace.
115///
116/// This is used when the user uses the `help` command with no parameters given.
117pub fn print_all() {
118    println!();
119    println!("{}", "  Available Commands".cyan().bold());
120    println!(
121        "{}",
122        "  ─────────────────────────────────────────────────────".dimmed()
123    );
124
125    let namespaces = ["help", "server", "db", "user", "test"];
126
127    for ns in namespaces {
128        println!();
129        println!("  {}", ns.white().bold());
130
131        for entry in COMMANDS {
132            let ns_prefix = format!("{}:", ns);
133            let belongs = entry.command == ns
134                || entry.command.starts_with(&ns_prefix)
135                || (ns == "help" && entry.command.starts_with("help "));
136
137            if belongs {
138                let auth_marker = if entry.requires_auth {
139                    " *".yellow().to_string()
140                } else {
141                    String::new()
142                };
143                println!(
144                    "    {:<30} {}{}",
145                    entry.command.green(),
146                    entry.summary.dimmed(),
147                    auth_marker
148                );
149            }
150        }
151    }
152
153    println!();
154    println!(
155        "  {} {}",
156        "*".yellow(),
157        "marked commands require server:login before use.".dimmed()
158    );
159    println!(
160        "  {}",
161        "Run `help <command>` for detailed usage on any command.".dimmed()
162    );
163    println!();
164}
165
166/// Prints detailed help for a specific command, including its description, usage, parameters, and auth requirements.
167///
168/// This is used when the user uses the `help` command with a specific command name as a parameter.
169pub fn print_command(command: &str) {
170    let entry = COMMANDS.iter().find(|e| {
171        e.command == command
172            || e.command == format!("server:{}", command)
173            || e.command == format!("help {}", command)
174    });
175
176    match entry {
177        None => {
178            println!("{} {}", "No help entry found for:".red(), command.white());
179            println!("{}", "Run `help` to see all available commands.".dimmed());
180        }
181        Some(e) => {
182            println!();
183            println!("  {}", e.command.cyan().bold());
184            println!(
185                "{}",
186                "  ─────────────────────────────────────────────────────".dimmed()
187            );
188            println!(
189                "  {:<16} {}",
190                "Description:".white(),
191                e.description.dimmed()
192            );
193            println!("  {:<16} {}", "Usage:".white(), e.usage.green());
194            println!(
195                "  {:<16} {}",
196                "Auth required:".white(),
197                if e.requires_auth {
198                    "yes".yellow().to_string()
199                } else {
200                    "no".dimmed().to_string()
201                }
202            );
203
204            println!(
205                "  {:<16} {}",
206                "Admin permissions required:".white(),
207                if e.requires_admin {
208                    "yes".yellow().to_string()
209                } else {
210                    "no".dimmed().to_string()
211                }
212            );
213
214            if !e.params.is_empty() {
215                println!("  {}", "Parameters:".white());
216                for (name, desc) in e.params {
217                    println!("    {:<16} {}", name.green(), desc.dimmed());
218                }
219            }
220
221            println!();
222        }
223    }
224}