1use colored::Colorize;
4
5struct CommandEntry {
6 command: &'static str, summary: &'static str, description: &'static str, usage: &'static str, requires_auth: bool, requires_admin: bool, params: &'static [(&'static str, &'static str)], }
14
15const COMMANDS: &[CommandEntry] = &[
16 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 CommandEntry {
37 command: "server:update-database",
38 summary: "Updates server to use updated database.",
39 description: "Reinitializes database for updating purposes, an identical process to startup, so that the server can use the most up to date database.",
40 usage: "server:update-database",
41 requires_auth: false,
42 requires_admin: false,
43 params: &[],
44 },
45 CommandEntry {
46 command: "server:signup",
47 summary: "Creates a new user account.",
48 description: "Prompts for a username, password, and optional email address to create a new user account.",
49 usage: "server:signup",
50 requires_auth: false,
51 requires_admin: false,
52 params: &[],
53 },
54 CommandEntry {
55 command: "server:login",
56 summary: "Authenticates an operator session in the terminal.",
57 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.",
58 usage: "server:login",
59 requires_auth: false,
60 requires_admin: false,
61 params: &[],
62 },
63 CommandEntry {
64 command: "server:status",
65 summary: "Shows uptime and basic server info.",
66 description: "Prints how long the server has been running, what address it is listening on, and whether testing mode is active.",
67 usage: "server:status",
68 requires_auth: false,
69 requires_admin: false,
70 params: &[],
71 },
72 CommandEntry {
73 command: "server:logout",
74 summary: "Ends the current operator session.",
75 description: "Clears the authenticated session immediately. Any subsequent write commands will require logging in again.",
76 usage: "server:logout",
77 requires_auth: true,
78 requires_admin: false,
79 params: &[],
80 },
81 CommandEntry {
82 command: "server:shutdown",
83 summary: "Gracefully shuts the server down.",
84 description: "Signals the server to stop accepting new requests, waits for in-flight requests to complete, flushes logs, and exits cleanly.",
85 usage: "server:shutdown",
86 requires_auth: true,
87 requires_admin: true,
88 params: &[],
89 },
90 CommandEntry {
91 command: "server:logs",
92 summary: "Displays recent server logs.",
93 description: "Prints logs in order from most recent to oldest, allowing for optional filter for last X days.",
94 usage: "server:logs [days]",
95 requires_auth: false,
96 requires_admin: false,
97 params: &[("days", "Optional number of days to display logs for")],
98 },
99 CommandEntry {
100 command: "server:audit",
101 summary: "Displays recent audit logs.",
102 description: "Prints audit logs in order from most recent to oldest, allowing for optional filter for last X days.",
103 usage: "server:audit [days]",
104 requires_auth: false,
105 requires_admin: false,
106 params: &[("days", "Optional number of days to display audit logs for")],
107 },
108 CommandEntry {
110 command: "db:stats",
111 summary: "Displays database statistics.",
112 description: "Prints the number of rows in each table, total row count, and estimated size of each table and database.",
113 usage: "db:stats",
114 requires_auth: false,
115 requires_admin: false,
116 params: &[],
117 },
118 CommandEntry {
119 command: "db:table",
120 summary: "Displays records from a specific table.",
121 description: "Prints the records from the specified table, with an option to view a specific page of results.",
122 usage: "db:table <name>, <page>",
123 requires_auth: false,
124 requires_admin: false,
125 params: &[
126 ("name", "The name of the table to display"),
127 ("page", "The page of results to display"),
128 ],
129 },
130 CommandEntry {
131 command: "db:delete",
132 summary: "Deletes the database and resets it to new",
133 description: "Deletes the database and resets it to a new state. This action is irreversible and will remove all data.",
134 usage: "db:delete",
135 requires_auth: true,
136 requires_admin: true,
137 params: &[],
138 },
139 CommandEntry {
141 command: "user:delete",
142 summary: "Deletes a user account.",
143 description: "Removes a user account from the database. This action is irreversible.",
144 usage: "user:delete <id>",
145 requires_auth: true,
146 requires_admin: true,
147 params: &[("id", "The ID of the user to delete")],
148 },
149 CommandEntry {
151 command: "test:run",
152 summary: "Runs functional tests on the server.",
153 description: "Executes a suite of functional tests to verify that the server is operating correctly. This is only available if testing mode is enabled.",
154 usage: "test:run",
155 requires_auth: false,
156 requires_admin: false,
157 params: &[],
158 },
159 CommandEntry {
161 command: "config:show",
162 summary: "Displays the current server configuration.",
163 description: "Prints the current server configuration settings.",
164 usage: "config:show",
165 requires_auth: true,
166 requires_admin: true,
167 params: &[],
168 },
169 CommandEntry {
170 command: "config:<key>",
171 summary: "Sets a configuration value.",
172 description: "Updates a specific configuration setting in the server using the format `config:<key> <value>`. For example: `config:server_port 8080`. This action requires admin privileges.",
173 usage: "config:<key> <value>",
174 requires_auth: true,
175 requires_admin: true,
176 params: &[("value", "The new value for the configuration key")],
177 },
178];
179
180pub fn print_all() {
184 println!();
185 println!("{}", " Available Commands".cyan().bold());
186 println!(
187 "{}",
188 " ─────────────────────────────────────────────────────".dimmed()
189 );
190
191 let namespaces = ["help", "server", "db", "user", "test", "config"];
192
193 for ns in namespaces {
194 println!();
195 println!(" {}", ns.white().bold());
196
197 for entry in COMMANDS {
198 let ns_prefix = format!("{}:", ns);
199 let belongs = entry.command == ns
200 || entry.command.starts_with(&ns_prefix)
201 || (ns == "help" && entry.command.starts_with("help "));
202
203 if belongs {
204 let auth_marker = if entry.requires_auth {
205 " *".yellow().to_string()
206 } else {
207 String::new()
208 };
209 println!(
210 " {:<30} {}{}",
211 entry.command.green(),
212 entry.summary.dimmed(),
213 auth_marker
214 );
215 }
216 }
217 }
218
219 println!();
220 println!(
221 " {} {}",
222 "*".yellow(),
223 "marked commands require server:login before use.".dimmed()
224 );
225 println!(
226 " {}",
227 "Run `help <command>` for detailed usage on any command.".dimmed()
228 );
229 println!();
230}
231
232pub fn print_command(command: &str) {
236 let entry = COMMANDS.iter().find(|e| {
237 e.command == command
238 || e.command == format!("server:{}", command)
239 || e.command == format!("help {}", command)
240 });
241
242 match entry {
243 None => {
244 println!("{} {}", "No help entry found for:".red(), command.white());
245 println!("{}", "Run `help` to see all available commands.".dimmed());
246 }
247 Some(e) => {
248 println!();
249 println!(" {}", e.command.cyan().bold());
250 println!(
251 "{}",
252 " ─────────────────────────────────────────────────────".dimmed()
253 );
254 println!(
255 " {:<16} {}",
256 "Description:".white(),
257 e.description.dimmed()
258 );
259 println!(" {:<16} {}", "Usage:".white(), e.usage.green());
260 println!(
261 " {:<16} {}",
262 "Auth required:".white(),
263 if e.requires_auth {
264 "yes".yellow().to_string()
265 } else {
266 "no".dimmed().to_string()
267 }
268 );
269
270 println!(
271 " {:<16} {}",
272 "Admin permissions required:".white(),
273 if e.requires_admin {
274 "yes".yellow().to_string()
275 } else {
276 "no".dimmed().to_string()
277 }
278 );
279
280 if !e.params.is_empty() {
281 println!(" {}", "Parameters:".white());
282 for (name, desc) in e.params {
283 println!(" {:<16} {}", name.green(), desc.dimmed());
284 }
285 }
286
287 println!();
288 }
289 }
290}