veloren_server_cli/
cli.rs

1#![expect(
2    clippy::needless_pass_by_ref_mut //until we find a better way for specs
3)]
4
5use clap::{Parser, builder::ValueParser};
6use common::comp;
7use server::persistence::SqlLogMode;
8use std::{str::FromStr, sync::mpsc::Sender};
9use tracing::error;
10
11// Custom value parser for case-insensitive parsing of AdminRole
12fn admin_role_value_parser() -> ValueParser {
13    ValueParser::new(move |s: &str| -> Result<comp::AdminRole, String> {
14        comp::AdminRole::from_str(&s.to_lowercase()).map_err(|err| err.to_string())
15    })
16}
17
18#[derive(Clone, Debug, Parser)]
19pub enum Admin {
20    /// Adds an admin
21    Add {
22        /// Name of the admin to whom to assign a role
23        username: String,
24        /// Role to assign to the admin
25        #[arg(value_parser = admin_role_value_parser())]
26        role: comp::AdminRole,
27    },
28    Remove {
29        /// Name of the admin from whom to remove any existing roles
30        username: String,
31    },
32}
33
34#[derive(Clone, Debug, Parser)]
35pub enum Shutdown {
36    /// Closes the server immediately
37    Immediate,
38    /// Shuts down the server gracefully
39    Graceful {
40        /// Number of seconds to wait before shutting down
41        seconds: u64,
42        #[arg(short, long, default_value = "The server is shutting down")]
43        /// Shutdown reason
44        reason: String,
45    },
46    /// Cancel any pending graceful shutdown.
47    Cancel,
48}
49
50#[derive(Clone, Debug, Parser)]
51pub enum SharedCommand {
52    /// Perform operations on the admin list
53    Admin {
54        #[command(subcommand)]
55        command: Admin,
56    },
57}
58
59#[derive(Debug, Clone, Parser)]
60pub enum Message {
61    #[command(flatten)]
62    Shared(SharedCommand),
63    /// Shut down the server (or cancel a shut down)
64    Shutdown {
65        #[command(subcommand)]
66        command: Shutdown,
67    },
68    /// Loads up the chunks at map center and adds a entity that mimics a
69    /// player to keep them from despawning
70    #[cfg(feature = "worldgen")]
71    LoadArea {
72        /// View distance of the loaded area
73        view_distance: u32,
74    },
75    /// Enable or disable sql logging
76    SqlLogMode {
77        #[arg(default_value_t, value_parser = clap::value_parser!(SqlLogMode))]
78        mode: SqlLogMode,
79    },
80    /// Disconnects all connected clients
81    DisconnectAllClients,
82    /// returns active player names
83    ListPlayers,
84    ListLogs,
85    /// sends a msg to everyone on the server
86    SendGlobalMsg {
87        msg: String,
88    },
89}
90
91#[derive(Debug, Clone)]
92pub enum MessageReturn {
93    Players(Vec<String>),
94    Logs(Vec<String>),
95}
96
97#[derive(Parser)]
98#[command(
99    name = "Veloren server TUI",
100    version = common::util::DISPLAY_VERSION_LONG.as_str(),
101    about = "The veloren server tui allows sending commands directly to the running server.",
102    author = "The veloren devs <https://gitlab.com/veloren/veloren>",
103)]
104#[clap(no_binary_name = true)]
105pub struct TuiApp {
106    #[command(subcommand)]
107    command: Message,
108}
109
110#[derive(Debug, Clone, Copy, Parser)]
111pub struct BenchParams {
112    /// View distance of the loaded area (in chunks)
113    #[arg(long)]
114    pub view_distance: u32,
115    /// Duration to run after loading completes (in seconds).
116    #[arg(long)]
117    pub duration: u32,
118}
119
120#[derive(Parser)]
121pub enum ArgvCommand {
122    #[command(flatten)]
123    Shared(SharedCommand),
124    /// Load an area, run the server for some time, and then exit (useful for
125    /// profiling).
126    Bench(BenchParams),
127}
128
129#[derive(Parser)]
130#[command(
131    name = "Veloren server CLI",
132    version = common::util::DISPLAY_VERSION_LONG.as_str(),
133    about = "The veloren server cli provides an easy to use interface to start a veloren server.",
134    author = "The veloren devs <https://gitlab.com/veloren/veloren>",
135)]
136pub struct ArgvApp {
137    #[arg(long, short)]
138    /// Enables the tui
139    pub tui: bool,
140    #[arg(long, short)]
141    /// Doesn't listen on STDIN
142    ///
143    /// Useful if you want to send the server in background, and your kernels
144    /// terminal driver will send SIGTTIN to it otherwise. (https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Redirections) and you dont want to use `stty -tostop`
145    /// or `nohub` or `tmux` or `screen` or `<<< \"\\004\"` to the program.
146    pub non_interactive: bool,
147    #[arg(long)]
148    /// Run without auth enabled
149    pub no_auth: bool,
150    #[arg(default_value_t, long, short, value_parser = clap::value_parser!(SqlLogMode))]
151    /// Enables SQL logging
152    pub sql_log_mode: SqlLogMode,
153    #[command(subcommand)]
154    pub command: Option<ArgvCommand>,
155}
156
157pub fn parse_command(input: &str, msg_s: &mut Sender<Message>) {
158    match TuiApp::try_parse_from(shell_words::split(input).unwrap_or_default()) {
159        Ok(message) => {
160            msg_s
161                .send(message.command)
162                .unwrap_or_else(|e| error!(?e, "Failed to send CLI message"));
163        },
164        Err(e) => error!("{}", e),
165    }
166}