**NOTE:** If there are any features, tools, or admin internals dependent on this output that would break, let me know!
I'm hoping this is acceptable, since it's a human-readable command.
Current output:
```shell
uwu> server list-backups
#1 Mon, 9 Feb 2026 20:36:25 +0000: 66135580 bytes, 595 files#2 Wed, 11 Feb 2026 02:33:15 +0000: 270963746 bytes, 1002 files#3 Sat, 14 Feb 2026 22:11:19 +0000: 675905487 bytes, 2139 files
```
Should be:
```shell
uwu> server list-backups
#1 Mon, 9 Feb 2026 20:36:25 +0000: 66135580 bytes, 595 files
#2 Wed, 11 Feb 2026 02:33:15 +0000: 270963746 bytes, 1002 files
#3 Sat, 14 Feb 2026 22:11:19 +0000: 675905487 bytes, 2139 files
```
155 lines
3.5 KiB
Rust
155 lines
3.5 KiB
Rust
use std::{path::PathBuf, sync::Arc};
|
|
|
|
use conduwuit::{
|
|
Err, Result,
|
|
utils::{stream::IterStream, time},
|
|
warn,
|
|
};
|
|
use futures::TryStreamExt;
|
|
|
|
use crate::admin_command;
|
|
|
|
#[admin_command]
|
|
pub(super) async fn uptime(&self) -> Result {
|
|
let elapsed = self
|
|
.services
|
|
.server
|
|
.started
|
|
.elapsed()
|
|
.expect("standard duration");
|
|
|
|
let result = time::pretty(elapsed);
|
|
self.write_str(&format!("{result}.")).await
|
|
}
|
|
|
|
#[admin_command]
|
|
pub(super) async fn show_config(&self) -> Result {
|
|
self.bail_restricted()?;
|
|
|
|
self.write_str(&format!("{}", *self.services.server.config))
|
|
.await
|
|
}
|
|
|
|
#[admin_command]
|
|
pub(super) async fn reload_config(&self, path: Option<PathBuf>) -> Result {
|
|
// The path argument is only what's optionally passed via the admin command,
|
|
// so we need to merge it with the existing paths if any were given at startup.
|
|
let mut paths = Vec::new();
|
|
|
|
// Add previously saved paths to the argument list
|
|
self.services
|
|
.config
|
|
.config_paths
|
|
.clone()
|
|
.unwrap_or_default()
|
|
.iter()
|
|
.for_each(|p| paths.push(p.to_owned()));
|
|
|
|
// If a path is given, and it's not already in the list,
|
|
// add it last, so that it overrides earlier files
|
|
if let Some(p) = path {
|
|
if !paths.contains(&p) {
|
|
paths.push(p);
|
|
}
|
|
}
|
|
|
|
self.services.config.reload(&paths)?;
|
|
|
|
self.write_str(&format!("Successfully reconfigured from paths: {paths:?}"))
|
|
.await
|
|
}
|
|
|
|
#[admin_command]
|
|
pub(super) async fn memory_usage(&self) -> Result {
|
|
let services_usage = self.services.memory_usage().await?;
|
|
let database_usage = self.services.db.db.memory_usage()?;
|
|
let allocator_usage =
|
|
conduwuit::alloc::memory_usage().map_or(String::new(), |s| format!("\nAllocator:\n{s}"));
|
|
|
|
self.write_str(&format!(
|
|
"Services:\n{services_usage}\nDatabase:\n{database_usage}{allocator_usage}",
|
|
))
|
|
.await
|
|
}
|
|
|
|
#[admin_command]
|
|
pub(super) async fn clear_caches(&self) -> Result {
|
|
self.services.clear_cache().await;
|
|
|
|
self.write_str("Done.").await
|
|
}
|
|
|
|
#[admin_command]
|
|
pub(super) async fn list_backups(&self) -> Result {
|
|
self.services
|
|
.db
|
|
.db
|
|
.backup_list()?
|
|
.try_stream()
|
|
.try_for_each(|result| writeln!(self, "{result}"))
|
|
.await
|
|
}
|
|
|
|
#[admin_command]
|
|
pub(super) async fn backup_database(&self) -> Result {
|
|
self.bail_restricted()?;
|
|
|
|
let db = Arc::clone(&self.services.db);
|
|
let result = self
|
|
.services
|
|
.server
|
|
.runtime()
|
|
.spawn_blocking(move || match db.db.backup() {
|
|
| Ok(()) => "Done".to_owned(),
|
|
| Err(e) => format!("Failed: {e}"),
|
|
})
|
|
.await?;
|
|
|
|
let count = self.services.db.db.backup_count()?;
|
|
self.write_str(&format!("{result}. Currently have {count} backups."))
|
|
.await
|
|
}
|
|
|
|
#[admin_command]
|
|
pub(super) async fn admin_notice(&self, message: Vec<String>) -> Result {
|
|
let message = message.join(" ");
|
|
self.services.admin.send_text(&message).await;
|
|
|
|
self.write_str("Notice was sent to #admins").await
|
|
}
|
|
|
|
#[admin_command]
|
|
pub(super) async fn reload_mods(&self) -> Result {
|
|
self.bail_restricted()?;
|
|
|
|
self.services.server.reload()?;
|
|
|
|
self.write_str("Reloading server...").await
|
|
}
|
|
|
|
#[admin_command]
|
|
#[cfg(unix)]
|
|
pub(super) async fn restart(&self, force: bool) -> Result {
|
|
use conduwuit::utils::sys::current_exe_deleted;
|
|
|
|
if !force && current_exe_deleted() {
|
|
return Err!(
|
|
"The server cannot be restarted because the executable changed. If this is expected \
|
|
use --force to override."
|
|
);
|
|
}
|
|
|
|
self.services.server.restart()?;
|
|
|
|
self.write_str("Restarting server...").await
|
|
}
|
|
|
|
#[admin_command]
|
|
pub(super) async fn shutdown(&self) -> Result {
|
|
self.bail_restricted()?;
|
|
|
|
warn!("shutdown command");
|
|
self.services.server.shutdown()?;
|
|
|
|
self.write_str("Shutting down server...").await
|
|
}
|