diff --git a/src/admin/admin.rs b/src/admin/admin.rs new file mode 100644 index 0000000000000000000000000000000000000000..e55f6d61060d85d2f623d46658a6c7a52f03f380 --- /dev/null +++ b/src/admin/admin.rs @@ -0,0 +1,66 @@ +use clap::Parser; +use conduit::Result; +use ruma::events::room::message::RoomMessageEventContent; + +use crate::{ + appservice, appservice::AppserviceCommand, check, check::CheckCommand, debug, debug::DebugCommand, federation, + federation::FederationCommand, media, media::MediaCommand, query, query::QueryCommand, room, room::RoomCommand, + server, server::ServerCommand, user, user::UserCommand, +}; + +#[derive(Parser)] +#[command(name = "admin", version = env!("CARGO_PKG_VERSION"))] +pub(crate) enum AdminCommand { + #[command(subcommand)] + /// - Commands for managing appservices + Appservices(AppserviceCommand), + + #[command(subcommand)] + /// - Commands for managing local users + Users(UserCommand), + + #[command(subcommand)] + /// - Commands for managing rooms + Rooms(RoomCommand), + + #[command(subcommand)] + /// - Commands for managing federation + Federation(FederationCommand), + + #[command(subcommand)] + /// - Commands for managing the server + Server(ServerCommand), + + #[command(subcommand)] + /// - Commands for managing media + Media(MediaCommand), + + #[command(subcommand)] + /// - Commands for checking integrity + Check(CheckCommand), + + #[command(subcommand)] + /// - Commands for debugging things + Debug(DebugCommand), + + #[command(subcommand)] + /// - Low-level queries for database getters and iterators + Query(QueryCommand), +} + +#[tracing::instrument(skip_all, name = "command")] +pub(crate) async fn process(command: AdminCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> { + let reply_message_content = match command { + AdminCommand::Appservices(command) => appservice::process(command, body).await?, + AdminCommand::Media(command) => media::process(command, body).await?, + AdminCommand::Users(command) => user::process(command, body).await?, + AdminCommand::Rooms(command) => room::process(command, body).await?, + AdminCommand::Federation(command) => federation::process(command, body).await?, + AdminCommand::Server(command) => server::process(command, body).await?, + AdminCommand::Debug(command) => debug::process(command, body).await?, + AdminCommand::Query(command) => query::process(command, body).await?, + AdminCommand::Check(command) => check::process(command, body).await?, + }; + + Ok(reply_message_content) +} diff --git a/src/admin/handler.rs b/src/admin/handler.rs index 409abc18f4a44f754a3819e29798269d878ff07e..46712077a788d99bcfa709d4c97a8dceec69d09d 100644 --- a/src/admin/handler.rs +++ b/src/admin/handler.rs @@ -11,64 +11,16 @@ OwnedEventId, }; -extern crate conduit_service as service; - use conduit::{utils::string::common_prefix, Result}; -pub(crate) use service::admin::Command; -use service::admin::{CommandOutput, CommandResult, HandlerResult}; +use service::admin::{Command, CommandOutput, CommandResult, HandlerResult}; -use crate::{ - appservice, appservice::AppserviceCommand, check, check::CheckCommand, debug, debug::DebugCommand, federation, - federation::FederationCommand, media, media::MediaCommand, query, query::QueryCommand, room, room::RoomCommand, - server, server::ServerCommand, services, user, user::UserCommand, -}; -pub(crate) const PAGE_SIZE: usize = 100; - -#[derive(Parser)] -#[command(name = "admin", version = env!("CARGO_PKG_VERSION"))] -pub(crate) enum AdminCommand { - #[command(subcommand)] - /// - Commands for managing appservices - Appservices(AppserviceCommand), - - #[command(subcommand)] - /// - Commands for managing local users - Users(UserCommand), - - #[command(subcommand)] - /// - Commands for managing rooms - Rooms(RoomCommand), - - #[command(subcommand)] - /// - Commands for managing federation - Federation(FederationCommand), - - #[command(subcommand)] - /// - Commands for managing the server - Server(ServerCommand), - - #[command(subcommand)] - /// - Commands for managing media - Media(MediaCommand), - - #[command(subcommand)] - /// - Commands for checking integrity - Check(CheckCommand), - - #[command(subcommand)] - /// - Commands for debugging things - Debug(DebugCommand), - - #[command(subcommand)] - /// - Low-level queries for database getters and iterators - Query(QueryCommand), -} +use crate::{admin, admin::AdminCommand, services}; #[must_use] -pub(crate) fn handle(command: Command) -> HandlerResult { Box::pin(handle_command(command)) } +pub(super) fn handle(command: Command) -> HandlerResult { Box::pin(handle_command(command)) } #[must_use] -pub(crate) fn complete(line: &str) -> String { complete_admin_command(AdminCommand::command(), line) } +pub(super) fn complete(line: &str) -> String { complete_command(AdminCommand::command(), line) } #[tracing::instrument(skip_all, name = "admin")] async fn handle_command(command: Command) -> CommandResult { @@ -80,7 +32,7 @@ async fn handle_command(command: Command) -> CommandResult { } async fn process_command(command: &Command) -> CommandOutput { - process_admin_message(&command.command) + process(&command.command) .await .and_then(|content| reply(content, command.reply_id.clone())) } @@ -104,11 +56,11 @@ fn reply(mut content: RoomMessageEventContent, reply_id: Option<OwnedEventId>) - } // Parse and process a message from the admin room -async fn process_admin_message(msg: &str) -> CommandOutput { +async fn process(msg: &str) -> CommandOutput { let mut lines = msg.lines().filter(|l| !l.trim().is_empty()); let command = lines.next().expect("each string has at least one line"); let body = lines.collect::<Vec<_>>(); - let parsed = match parse_admin_command(command) { + let parsed = match parse_command(command) { Ok(parsed) => parsed, Err(error) => { let server_name = services().globals.server_name(); @@ -118,7 +70,7 @@ async fn process_admin_message(msg: &str) -> CommandOutput { }; let timer = Instant::now(); - let result = process_admin_command(parsed, body).await; + let result = admin::process(parsed, body).await; let elapsed = timer.elapsed(); conduit::debug!(?command, ok = result.is_ok(), "command processed in {elapsed:?}"); match result { @@ -129,31 +81,14 @@ async fn process_admin_message(msg: &str) -> CommandOutput { } } -#[tracing::instrument(skip_all, name = "command")] -async fn process_admin_command(command: AdminCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> { - let reply_message_content = match command { - AdminCommand::Appservices(command) => appservice::process(command, body).await?, - AdminCommand::Media(command) => media::process(command, body).await?, - AdminCommand::Users(command) => user::process(command, body).await?, - AdminCommand::Rooms(command) => room::process(command, body).await?, - AdminCommand::Federation(command) => federation::process(command, body).await?, - AdminCommand::Server(command) => server::process(command, body).await?, - AdminCommand::Debug(command) => debug::process(command, body).await?, - AdminCommand::Query(command) => query::process(command, body).await?, - AdminCommand::Check(command) => check::process(command, body).await?, - }; - - Ok(reply_message_content) -} - // Parse chat messages from the admin room into an AdminCommand object -fn parse_admin_command(command_line: &str) -> Result<AdminCommand, String> { - let argv = parse_command_line(command_line); +fn parse_command(command_line: &str) -> Result<AdminCommand, String> { + let argv = parse_line(command_line); AdminCommand::try_parse_from(argv).map_err(|error| error.to_string()) } -fn complete_admin_command(mut cmd: clap::Command, line: &str) -> String { - let argv = parse_command_line(line); +fn complete_command(mut cmd: clap::Command, line: &str) -> String { + let argv = parse_line(line); let mut ret = Vec::<String>::with_capacity(argv.len().saturating_add(1)); 'token: for token in argv.into_iter().skip(1) { @@ -196,7 +131,7 @@ fn complete_admin_command(mut cmd: clap::Command, line: &str) -> String { } // Parse chat messages from the admin room into an AdminCommand object -fn parse_command_line(command_line: &str) -> Vec<String> { +fn parse_line(command_line: &str) -> Vec<String> { let mut argv = command_line .split_whitespace() .map(str::to_owned) diff --git a/src/admin/mod.rs b/src/admin/mod.rs index b183f3f6483652d2b391e6a88394498688f06124..ff2aefd5c8fbb666b78d6990f442c597183d7395 100644 --- a/src/admin/mod.rs +++ b/src/admin/mod.rs @@ -1,18 +1,20 @@ #![recursion_limit = "168"] #![allow(clippy::wildcard_imports)] +pub(crate) mod admin; +pub(crate) mod handler; +mod tests; +pub(crate) mod utils; + pub(crate) mod appservice; pub(crate) mod check; pub(crate) mod debug; pub(crate) mod federation; -pub(crate) mod handler; pub(crate) mod media; pub(crate) mod query; pub(crate) mod room; pub(crate) mod server; -mod tests; pub(crate) mod user; -pub(crate) mod utils; extern crate conduit_api as api; extern crate conduit_core as conduit; @@ -23,6 +25,8 @@ pub(crate) use crate::utils::{escape_html, get_room_info}; +pub(crate) const PAGE_SIZE: usize = 100; + mod_ctor! {} mod_dtor! {} diff --git a/src/admin/room/room_commands.rs b/src/admin/room/room_commands.rs index 1a387c7e1127004e398b7072a36403d4da9ea2af..cf0f3ddbd6fc35b318c8baf2b63ac4a6046390f6 100644 --- a/src/admin/room/room_commands.rs +++ b/src/admin/room/room_commands.rs @@ -2,7 +2,7 @@ use ruma::events::room::message::RoomMessageEventContent; -use crate::{escape_html, get_room_info, handler::PAGE_SIZE, services, Result}; +use crate::{escape_html, get_room_info, services, Result, PAGE_SIZE}; pub(super) async fn list( _body: Vec<&str>, page: Option<usize>, exclude_disabled: bool, exclude_banned: bool, diff --git a/src/admin/room/room_directory_commands.rs b/src/admin/room/room_directory_commands.rs index c9b4eb9e0ddcc72d7c6607356df42610298a7008..912e970c6fb894230e2886bd237c77ebdb857dbd 100644 --- a/src/admin/room/room_directory_commands.rs +++ b/src/admin/room/room_directory_commands.rs @@ -3,7 +3,7 @@ use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId}; use super::RoomDirectoryCommand; -use crate::{escape_html, get_room_info, handler::PAGE_SIZE, services, Result}; +use crate::{escape_html, get_room_info, services, Result, PAGE_SIZE}; pub(super) async fn process(command: RoomDirectoryCommand, _body: Vec<&str>) -> Result<RoomMessageEventContent> { match command { diff --git a/src/admin/tests.rs b/src/admin/tests.rs index 69ccd896c7643fc2aef79c0e969568ee37d1f5fc..296d4888784847fccc38e66945fae5f35db6fd22 100644 --- a/src/admin/tests.rs +++ b/src/admin/tests.rs @@ -12,7 +12,7 @@ fn get_help_inner(input: &str) { use clap::Parser; - use crate::handler::AdminCommand; + use crate::admin::AdminCommand; let Err(error) = AdminCommand::try_parse_from(["argv[0] doesn't matter", input]) else { panic!("no error!");