ran cargo fmt
This commit is contained in:
parent
6e105a8a41
commit
73ef497609
4 changed files with 350 additions and 192 deletions
|
@ -75,18 +75,28 @@ impl service::rooms::alias::Data for KeyValueDatabase {
|
|||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
fn all_local_aliases<'a>(&'a self) -> Box<dyn Iterator<Item = Result<(OwnedRoomId, String)>> + 'a> {
|
||||
Box::new(self.alias_roomid.iter().map(|(room_alias_bytes, room_id_bytes)| {
|
||||
let room_alias_localpart = utils::string_from_bytes(&room_alias_bytes)
|
||||
.map_err(|_| Error::bad_database("Invalid alias bytes in aliasid_alias."))?;
|
||||
|
||||
let room_id = utils::string_from_bytes(&room_id_bytes)
|
||||
.map_err(|_| Error::bad_database("Invalid room_id bytes in aliasid_alias."))?
|
||||
.try_into()
|
||||
.map_err(|_| Error::bad_database("Invalid room_id in aliasid_alias."))?;
|
||||
fn all_local_aliases<'a>(
|
||||
&'a self,
|
||||
) -> Box<dyn Iterator<Item = Result<(OwnedRoomId, String)>> + 'a> {
|
||||
Box::new(
|
||||
self.alias_roomid
|
||||
.iter()
|
||||
.map(|(room_alias_bytes, room_id_bytes)| {
|
||||
let room_alias_localpart = utils::string_from_bytes(&room_alias_bytes)
|
||||
.map_err(|_| {
|
||||
Error::bad_database("Invalid alias bytes in aliasid_alias.")
|
||||
})?;
|
||||
|
||||
Ok((room_id, room_alias_localpart))
|
||||
}))
|
||||
let room_id = utils::string_from_bytes(&room_id_bytes)
|
||||
.map_err(|_| {
|
||||
Error::bad_database("Invalid room_id bytes in aliasid_alias.")
|
||||
})?
|
||||
.try_into()
|
||||
.map_err(|_| Error::bad_database("Invalid room_id in aliasid_alias."))?;
|
||||
|
||||
Ok((room_id, room_alias_localpart))
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@ use std::{collections::BTreeMap, convert::TryFrom, sync::Arc, time::Instant};
|
|||
use clap::{Parser, Subcommand};
|
||||
use regex::Regex;
|
||||
use ruma::{
|
||||
api::appservice::Registration, events::{
|
||||
api::appservice::Registration,
|
||||
events::{
|
||||
relation::InReplyTo,
|
||||
room::{
|
||||
canonical_alias::RoomCanonicalAliasEventContent,
|
||||
create::RoomCreateEventContent,
|
||||
|
@ -11,15 +13,15 @@ use ruma::{
|
|||
history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent},
|
||||
join_rules::{JoinRule, RoomJoinRulesEventContent},
|
||||
member::{MembershipState, RoomMemberEventContent},
|
||||
message::{RoomMessageEventContent, Relation::Reply},
|
||||
message::{Relation::Reply, RoomMessageEventContent},
|
||||
name::RoomNameEventContent,
|
||||
power_levels::RoomPowerLevelsEventContent,
|
||||
topic::RoomTopicEventContent,
|
||||
},
|
||||
TimelineEventType, relation::InReplyTo,
|
||||
TimelineEventType,
|
||||
},
|
||||
MilliSecondsSinceUnixEpoch, EventId, OwnedRoomAliasId, RoomAliasId,
|
||||
RoomId, OwnedRoomId, RoomVersionId, ServerName, UserId, OwnedUserId,
|
||||
EventId, MilliSecondsSinceUnixEpoch, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomAliasId,
|
||||
RoomId, RoomVersionId, ServerName, UserId,
|
||||
};
|
||||
use serde_json::value::to_raw_value;
|
||||
use tokio::sync::{mpsc, Mutex, RwLock};
|
||||
|
@ -43,23 +45,23 @@ enum AdminCommand {
|
|||
#[command(subcommand)]
|
||||
/// Commands for managing appservices
|
||||
Appservice(AppserviceCommand),
|
||||
|
||||
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing local users
|
||||
User(UserCommand),
|
||||
|
||||
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing rooms
|
||||
Room(RoomCommand),
|
||||
|
||||
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing federation
|
||||
Federation(FederationCommand),
|
||||
|
||||
|
||||
#[command(subcommand)]
|
||||
/// Commands for managing the server
|
||||
Server(ServerCommand),
|
||||
|
||||
|
||||
#[command(subcommand)]
|
||||
// TODO: should i split out debug commands to a separate thing? the
|
||||
// debug commands seem like they could fit in the other categories fine
|
||||
|
@ -129,7 +131,7 @@ enum UserCommand {
|
|||
///
|
||||
/// User will not be removed from all rooms by default.
|
||||
/// Use --leave-rooms to force the user to leave all rooms
|
||||
Deactivate{
|
||||
Deactivate {
|
||||
#[arg(short, long)]
|
||||
leave_rooms: bool,
|
||||
user_id: Box<UserId>,
|
||||
|
@ -157,7 +159,7 @@ enum UserCommand {
|
|||
/// Also deactivate admin accounts
|
||||
force: bool,
|
||||
},
|
||||
|
||||
|
||||
/// List local users in the database
|
||||
List,
|
||||
}
|
||||
|
@ -166,9 +168,7 @@ enum UserCommand {
|
|||
#[derive(Subcommand)]
|
||||
enum RoomCommand {
|
||||
/// List all rooms the server knows about
|
||||
List {
|
||||
page: Option<usize>,
|
||||
},
|
||||
List { page: Option<usize> },
|
||||
|
||||
#[command(subcommand)]
|
||||
/// Manage rooms' aliases
|
||||
|
@ -187,20 +187,20 @@ enum RoomAliasCommand {
|
|||
#[arg(short, long)]
|
||||
/// Set the alias even if a room is already using it
|
||||
force: bool,
|
||||
|
||||
|
||||
/// The room id to set the alias on
|
||||
room_id: Box<RoomId>,
|
||||
|
||||
|
||||
/// The alias localpart to use (`alias`, not `#alias:servername.tld`)
|
||||
room_alias_localpart: Box<String>,
|
||||
},
|
||||
|
||||
|
||||
/// Remove an alias
|
||||
Remove {
|
||||
/// The alias localpart to remove (`alias`, not `#alias:servername.tld`)
|
||||
room_alias_localpart: Box<String>,
|
||||
},
|
||||
|
||||
|
||||
/// Show which room is using an alias
|
||||
Which {
|
||||
/// The alias localpart to look up (`alias`, not `#alias:servername.tld`)
|
||||
|
@ -222,7 +222,7 @@ enum RoomDirectoryCommand {
|
|||
/// The room id of the room to publish
|
||||
room_id: Box<RoomId>,
|
||||
},
|
||||
|
||||
|
||||
/// Unpublish a room to the room directory
|
||||
Unpublish {
|
||||
/// The room id of the room to unpublish
|
||||
|
@ -231,9 +231,7 @@ enum RoomDirectoryCommand {
|
|||
|
||||
/// List rooms that are published
|
||||
// TODO: is this really necessary?
|
||||
List {
|
||||
page: Option<usize>,
|
||||
},
|
||||
List { page: Option<usize> },
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
|
@ -241,13 +239,13 @@ enum RoomDirectoryCommand {
|
|||
enum FederationCommand {
|
||||
/// List all rooms we are currently handling an incoming pdu from
|
||||
IncomingFederation,
|
||||
|
||||
|
||||
/// Disables incoming federation handling for a room.
|
||||
DisableRoom { room_id: Box<RoomId> },
|
||||
|
||||
|
||||
/// Enables incoming federation handling for a room again.
|
||||
EnableRoom { room_id: Box<RoomId> },
|
||||
|
||||
|
||||
#[command(verbatim_doc_comment)]
|
||||
/// Verify json signatures
|
||||
/// [commandbody]
|
||||
|
@ -298,7 +296,7 @@ enum DebugCommand {
|
|||
enum ServerCommand {
|
||||
/// Show configuration values
|
||||
ShowConfig,
|
||||
|
||||
|
||||
/// Print database memory usage statistics
|
||||
MemoryUsage,
|
||||
|
||||
|
@ -366,7 +364,7 @@ impl Service {
|
|||
if let Some(reply) = reply {
|
||||
message_content.relates_to = Some(Reply { in_reply_to: InReplyTo { event_id: reply.into() } })
|
||||
}
|
||||
|
||||
|
||||
services()
|
||||
.rooms
|
||||
.timeline
|
||||
|
@ -394,9 +392,18 @@ impl Service {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn process_message(&self, room_message: String, event_id: Arc<EventId>, sender: OwnedUserId) {
|
||||
pub fn process_message(
|
||||
&self,
|
||||
room_message: String,
|
||||
event_id: Arc<EventId>,
|
||||
sender: OwnedUserId,
|
||||
) {
|
||||
self.sender
|
||||
.send(AdminRoomEvent::ProcessMessage(room_message, event_id, sender))
|
||||
.send(AdminRoomEvent::ProcessMessage(
|
||||
room_message,
|
||||
event_id,
|
||||
sender,
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
@ -407,7 +414,11 @@ impl Service {
|
|||
}
|
||||
|
||||
// Parse and process a message from the admin room
|
||||
async fn process_admin_message(&self, room_message: String, sender: &UserId) -> RoomMessageEventContent {
|
||||
async fn process_admin_message(
|
||||
&self,
|
||||
room_message: String,
|
||||
sender: &UserId,
|
||||
) -> RoomMessageEventContent {
|
||||
let mut lines = room_message.lines().filter(|l| !l.trim().is_empty());
|
||||
let command_line = lines.next().expect("each string has at least one line");
|
||||
let body: Vec<_> = lines.collect();
|
||||
|
@ -423,7 +434,10 @@ impl Service {
|
|||
}
|
||||
};
|
||||
|
||||
match self.process_admin_command(admin_command, body, sender).await {
|
||||
match self
|
||||
.process_admin_command(admin_command, body, sender)
|
||||
.await
|
||||
{
|
||||
Ok(reply_message) => reply_message,
|
||||
Err(error) => {
|
||||
let markdown_message = format!(
|
||||
|
@ -471,13 +485,16 @@ impl Service {
|
|||
let reply_message_content = match command {
|
||||
AdminCommand::Appservice(command) => match command {
|
||||
AppserviceCommand::Register => {
|
||||
if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```"
|
||||
if body.len() > 2
|
||||
&& body[0].trim().starts_with("```")
|
||||
&& body.last().unwrap().trim() == "```"
|
||||
{
|
||||
let appservice_config = body[1..body.len() - 1].join("\n");
|
||||
let parsed_config =
|
||||
serde_yaml::from_str::<Registration>(&appservice_config);
|
||||
match parsed_config {
|
||||
Ok(yaml) => match services().appservice.register_appservice(yaml).await {
|
||||
Ok(yaml) => match services().appservice.register_appservice(yaml).await
|
||||
{
|
||||
Ok(id) => RoomMessageEventContent::text_plain(format!(
|
||||
"Appservice registered with ID: {id}."
|
||||
)),
|
||||
|
@ -507,18 +524,20 @@ impl Service {
|
|||
"Failed to unregister appservice: {e}"
|
||||
)),
|
||||
},
|
||||
AppserviceCommand::Show { appservice_identifier } => {
|
||||
AppserviceCommand::Show {
|
||||
appservice_identifier,
|
||||
} => {
|
||||
match services()
|
||||
.appservice
|
||||
.get_registration(&appservice_identifier)
|
||||
.await {
|
||||
.await
|
||||
{
|
||||
Some(registration) => {
|
||||
let config_str = serde_yaml::to_string(®istration)
|
||||
.expect("config should've been validated on register");
|
||||
let output = format!(
|
||||
"Config for {}:\n\n```yaml\n{}\n```",
|
||||
appservice_identifier,
|
||||
config_str,
|
||||
appservice_identifier, config_str,
|
||||
);
|
||||
let output_html = format!(
|
||||
"Config for {}:\n\n<pre><code class=\"language-yaml\">{}</code></pre>",
|
||||
|
@ -526,28 +545,22 @@ impl Service {
|
|||
escape_html(&config_str),
|
||||
);
|
||||
RoomMessageEventContent::text_html(output, output_html)
|
||||
},
|
||||
}
|
||||
None => RoomMessageEventContent::text_plain("Appservice does not exist."),
|
||||
}
|
||||
}
|
||||
AppserviceCommand::List => {
|
||||
let appservices = services()
|
||||
.appservice
|
||||
.iter_ids()
|
||||
.await;
|
||||
let appservices = services().appservice.iter_ids().await;
|
||||
let count = appservices.len();
|
||||
let output = format!(
|
||||
"Appservices ({}): {}",
|
||||
count,
|
||||
appservices.join(", ")
|
||||
);
|
||||
let output = format!("Appservices ({}): {}", count, appservices.join(", "));
|
||||
RoomMessageEventContent::text_plain(output)
|
||||
}
|
||||
}
|
||||
},
|
||||
AdminCommand::User(command) => match command {
|
||||
UserCommand::List => match services().users.list_local_users() {
|
||||
Ok(users) => {
|
||||
let mut msg: String = format!("Found {} local user account(s):\n", users.len());
|
||||
let mut msg: String =
|
||||
format!("Found {} local user account(s):\n", users.len());
|
||||
msg += &users.join("\n");
|
||||
RoomMessageEventContent::text_plain(&msg)
|
||||
}
|
||||
|
@ -615,7 +628,10 @@ impl Service {
|
|||
"Created user with user_id: {user_id} and password: {password}"
|
||||
))
|
||||
}
|
||||
UserCommand::Deactivate { leave_rooms, user_id } => {
|
||||
UserCommand::Deactivate {
|
||||
leave_rooms,
|
||||
user_id,
|
||||
} => {
|
||||
let user_id = Arc::<UserId>::from(user_id);
|
||||
if services().users.exists(&user_id)? {
|
||||
RoomMessageEventContent::text_plain(format!(
|
||||
|
@ -677,9 +693,11 @@ impl Service {
|
|||
"Couldn't reset the password for user {user_id}: {e}"
|
||||
)),
|
||||
}
|
||||
},
|
||||
}
|
||||
UserCommand::DeactivateAll { leave_rooms, force } => {
|
||||
if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```"
|
||||
if body.len() > 2
|
||||
&& body[0].trim().starts_with("```")
|
||||
&& body.last().unwrap().trim() == "```"
|
||||
{
|
||||
let usernames = body.clone().drain(1..body.len() - 1).collect::<Vec<_>>();
|
||||
|
||||
|
@ -736,37 +754,57 @@ impl Service {
|
|||
"Expected code block in command body. Add --help for details.",
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
AdminCommand::Room(command) => match command {
|
||||
RoomCommand::List { page } => {
|
||||
// TODO: i know there's a way to do this with clap, but i can't seem to find it
|
||||
let page = page.unwrap_or(1);
|
||||
let mut rooms = services().rooms.metadata.iter_ids()
|
||||
let mut rooms = services()
|
||||
.rooms
|
||||
.metadata
|
||||
.iter_ids()
|
||||
.filter_map(|r| r.ok())
|
||||
.map(|id| (
|
||||
id.clone(),
|
||||
services().rooms.state_cache.room_joined_count(&id).ok().flatten().unwrap_or(0),
|
||||
services().rooms.state_accessor.get_name(&id).ok().flatten().unwrap_or(id.to_string()),
|
||||
))
|
||||
.map(|id| {
|
||||
(
|
||||
id.clone(),
|
||||
services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_joined_count(&id)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or(0),
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.get_name(&id)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or(id.to_string()),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
rooms.sort_by_key(|r| r.1);
|
||||
rooms.reverse();
|
||||
|
||||
let rooms: Vec<_> = rooms.into_iter()
|
||||
let rooms: Vec<_> = rooms
|
||||
.into_iter()
|
||||
.skip(page.saturating_sub(1) * PAGE_SIZE)
|
||||
.take(PAGE_SIZE)
|
||||
.collect();
|
||||
|
||||
|
||||
if rooms.is_empty() {
|
||||
return Ok(RoomMessageEventContent::text_plain("No more rooms."));
|
||||
};
|
||||
|
||||
|
||||
let output_plain = format!(
|
||||
"Rooms:\n{}",
|
||||
rooms
|
||||
.iter()
|
||||
.map(|(id, members, name)| format!("{id}\tMembers: {members}\tName: {name}"))
|
||||
.map(|(id, members, name)| format!(
|
||||
"{id}\tMembers: {members}\tName: {name}"
|
||||
))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
);
|
||||
|
@ -785,18 +823,35 @@ impl Service {
|
|||
RoomMessageEventContent::text_html(output_plain, output_html)
|
||||
}
|
||||
// TODO: clean up and deduplicate code
|
||||
RoomCommand::Alias(command) => {
|
||||
match command {
|
||||
RoomAliasCommand::Set { ref room_alias_localpart, .. } | RoomAliasCommand::Remove { ref room_alias_localpart } | RoomAliasCommand::Which { ref room_alias_localpart } => {
|
||||
let room_alias_str = format!("#{}:{}", room_alias_localpart, services().globals.server_name());
|
||||
let room_alias = match RoomAliasId::parse_box(room_alias_str) {
|
||||
Ok(alias) => alias,
|
||||
Err(err) => return Ok(RoomMessageEventContent::text_plain(format!("Failed to parse alias: {}", err))),
|
||||
};
|
||||
RoomCommand::Alias(command) => match command {
|
||||
RoomAliasCommand::Set {
|
||||
ref room_alias_localpart,
|
||||
..
|
||||
}
|
||||
| RoomAliasCommand::Remove {
|
||||
ref room_alias_localpart,
|
||||
}
|
||||
| RoomAliasCommand::Which {
|
||||
ref room_alias_localpart,
|
||||
} => {
|
||||
let room_alias_str = format!(
|
||||
"#{}:{}",
|
||||
room_alias_localpart,
|
||||
services().globals.server_name()
|
||||
);
|
||||
let room_alias = match RoomAliasId::parse_box(room_alias_str) {
|
||||
Ok(alias) => alias,
|
||||
Err(err) => {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to parse alias: {}",
|
||||
err
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
match command {
|
||||
RoomAliasCommand::Set { force, room_id, .. } => {
|
||||
match (force, services().rooms.alias.resolve_local_alias(&room_alias)) {
|
||||
match command {
|
||||
RoomAliasCommand::Set { force, room_id, .. } => {
|
||||
match (force, services().rooms.alias.resolve_local_alias(&room_alias)) {
|
||||
(true, Ok(Some(id))) => match services().rooms.alias.set_alias(&room_alias, &room_id, sender) {
|
||||
Ok(()) => RoomMessageEventContent::text_plain(format!("Successfully overwrote alias (formerly {})", id)),
|
||||
Err(err) => RoomMessageEventContent::text_plain(format!("Failed to remove alias: {}", err)),
|
||||
|
@ -809,107 +864,189 @@ impl Service {
|
|||
Err(err) => RoomMessageEventContent::text_plain(format!("Failed to remove alias: {}", err)),
|
||||
}
|
||||
(_, Err(err)) => RoomMessageEventContent::text_plain(format!("Unable to lookup alias: {}", err)),
|
||||
}
|
||||
},
|
||||
RoomAliasCommand::Remove { .. } => {
|
||||
match services().rooms.alias.resolve_local_alias(&room_alias) {
|
||||
Ok(Some(id)) => match services().rooms.alias.remove_alias(&room_alias, sender) {
|
||||
Ok(()) => RoomMessageEventContent::text_plain(format!("Removed alias from {}", id)),
|
||||
Err(err) => RoomMessageEventContent::text_plain(format!("Failed to remove alias: {}", err)),
|
||||
}
|
||||
Ok(None) => RoomMessageEventContent::text_plain("Alias isn't in use."),
|
||||
Err(err) => RoomMessageEventContent::text_plain(format!("Unable to lookup alias: {}", err)),
|
||||
}
|
||||
},
|
||||
RoomAliasCommand::Which { .. } => {
|
||||
match services().rooms.alias.resolve_local_alias(&room_alias) {
|
||||
Ok(Some(id)) => RoomMessageEventContent::text_plain(format!("Alias resolves to {}", id)),
|
||||
Ok(None) => RoomMessageEventContent::text_plain("Alias isn't in use."),
|
||||
Err(err) => RoomMessageEventContent::text_plain(&format!("Unable to lookup alias: {}", err)),
|
||||
}
|
||||
},
|
||||
RoomAliasCommand::List { .. } => unreachable!(),
|
||||
}
|
||||
}
|
||||
RoomAliasCommand::List { room_id } => match room_id {
|
||||
Some(room_id) => {
|
||||
let aliases: Result<Vec<_>, _> = services().rooms.alias.local_aliases_for_room(&room_id).collect();
|
||||
match aliases {
|
||||
Ok(aliases) => {
|
||||
let plain_list: String = aliases.iter()
|
||||
.map(|alias| format!("- {}\n", alias))
|
||||
.collect();
|
||||
|
||||
let html_list: String = aliases.iter()
|
||||
.map(|alias| format!("<li>{}</li>\n", escape_html(&alias.to_string())))
|
||||
.collect();
|
||||
|
||||
let plain = format!("Aliases for {}:\n{}", room_id, plain_list);
|
||||
let html = format!("Aliases for {}:\n<ul>{}</ul>", room_id, html_list);
|
||||
RoomMessageEventContent::text_html(plain, html)
|
||||
RoomAliasCommand::Remove { .. } => {
|
||||
match services().rooms.alias.resolve_local_alias(&room_alias) {
|
||||
Ok(Some(id)) => match services()
|
||||
.rooms
|
||||
.alias
|
||||
.remove_alias(&room_alias, sender)
|
||||
{
|
||||
Ok(()) => RoomMessageEventContent::text_plain(format!(
|
||||
"Removed alias from {}",
|
||||
id
|
||||
)),
|
||||
Err(err) => RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to remove alias: {}",
|
||||
err
|
||||
)),
|
||||
},
|
||||
Err(err) => RoomMessageEventContent::text_plain(&format!("Unable to list aliases: {}", err)),
|
||||
Ok(None) => {
|
||||
RoomMessageEventContent::text_plain("Alias isn't in use.")
|
||||
}
|
||||
Err(err) => RoomMessageEventContent::text_plain(format!(
|
||||
"Unable to lookup alias: {}",
|
||||
err
|
||||
)),
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let aliases: Result<Vec<_>, _> = services().rooms.alias.all_local_aliases().collect();
|
||||
match aliases {
|
||||
Ok(aliases) => {
|
||||
let server_name = services().globals.server_name();
|
||||
let plain_list: String = aliases.iter()
|
||||
.map(|(id, alias)| format!("- #{}:{} -> {}\n", alias, server_name, id))
|
||||
.collect();
|
||||
|
||||
let html_list: String = aliases.iter()
|
||||
.map(|(id, alias)| format!("<li>#{}:{} -> {}</li>\n", escape_html(&alias.to_string()), server_name, escape_html(&id.to_string())))
|
||||
.collect();
|
||||
|
||||
let plain = format!("Aliases:\n{}", plain_list);
|
||||
let html = format!("Aliases:\n<ul>{}</ul>", html_list);
|
||||
RoomMessageEventContent::text_html(plain, html)
|
||||
},
|
||||
Err(err) => RoomMessageEventContent::text_plain(&format!("Unable to list aliases: {}", err)),
|
||||
RoomAliasCommand::Which { .. } => {
|
||||
match services().rooms.alias.resolve_local_alias(&room_alias) {
|
||||
Ok(Some(id)) => RoomMessageEventContent::text_plain(format!(
|
||||
"Alias resolves to {}",
|
||||
id
|
||||
)),
|
||||
Ok(None) => {
|
||||
RoomMessageEventContent::text_plain("Alias isn't in use.")
|
||||
}
|
||||
Err(err) => RoomMessageEventContent::text_plain(&format!(
|
||||
"Unable to lookup alias: {}",
|
||||
err
|
||||
)),
|
||||
}
|
||||
}
|
||||
RoomAliasCommand::List { .. } => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
RoomAliasCommand::List { room_id } => match room_id {
|
||||
Some(room_id) => {
|
||||
let aliases: Result<Vec<_>, _> = services()
|
||||
.rooms
|
||||
.alias
|
||||
.local_aliases_for_room(&room_id)
|
||||
.collect();
|
||||
match aliases {
|
||||
Ok(aliases) => {
|
||||
let plain_list: String = aliases
|
||||
.iter()
|
||||
.map(|alias| format!("- {}\n", alias))
|
||||
.collect();
|
||||
|
||||
let html_list: String = aliases
|
||||
.iter()
|
||||
.map(|alias| {
|
||||
format!(
|
||||
"<li>{}</li>\n",
|
||||
escape_html(&alias.to_string())
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let plain = format!("Aliases for {}:\n{}", room_id, plain_list);
|
||||
let html =
|
||||
format!("Aliases for {}:\n<ul>{}</ul>", room_id, html_list);
|
||||
RoomMessageEventContent::text_html(plain, html)
|
||||
}
|
||||
Err(err) => RoomMessageEventContent::text_plain(&format!(
|
||||
"Unable to list aliases: {}",
|
||||
err
|
||||
)),
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let aliases: Result<Vec<_>, _> =
|
||||
services().rooms.alias.all_local_aliases().collect();
|
||||
match aliases {
|
||||
Ok(aliases) => {
|
||||
let server_name = services().globals.server_name();
|
||||
let plain_list: String = aliases
|
||||
.iter()
|
||||
.map(|(id, alias)| {
|
||||
format!("- #{}:{} -> {}\n", alias, server_name, id)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let html_list: String = aliases
|
||||
.iter()
|
||||
.map(|(id, alias)| {
|
||||
format!(
|
||||
"<li>#{}:{} -> {}</li>\n",
|
||||
escape_html(&alias.to_string()),
|
||||
server_name,
|
||||
escape_html(&id.to_string())
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let plain = format!("Aliases:\n{}", plain_list);
|
||||
let html = format!("Aliases:\n<ul>{}</ul>", html_list);
|
||||
RoomMessageEventContent::text_html(plain, html)
|
||||
}
|
||||
Err(err) => RoomMessageEventContent::text_plain(&format!(
|
||||
"Unable to list aliases: {}",
|
||||
err
|
||||
)),
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
RoomCommand::Directory(command) => match command {
|
||||
RoomDirectoryCommand::Publish { room_id } => match services().rooms.directory.set_public(&room_id) {
|
||||
Ok(()) => RoomMessageEventContent::text_plain("Room published"),
|
||||
Err(err) => RoomMessageEventContent::text_plain(&format!("Unable to update room: {}", err)),
|
||||
RoomDirectoryCommand::Publish { room_id } => {
|
||||
match services().rooms.directory.set_public(&room_id) {
|
||||
Ok(()) => RoomMessageEventContent::text_plain("Room published"),
|
||||
Err(err) => RoomMessageEventContent::text_plain(&format!(
|
||||
"Unable to update room: {}",
|
||||
err
|
||||
)),
|
||||
}
|
||||
}
|
||||
RoomDirectoryCommand::Unpublish { room_id } => match services().rooms.directory.set_not_public(&room_id) {
|
||||
Ok(()) => RoomMessageEventContent::text_plain("Room unpublished"),
|
||||
Err(err) => RoomMessageEventContent::text_plain(&format!("Unable to update room: {}", err)),
|
||||
RoomDirectoryCommand::Unpublish { room_id } => {
|
||||
match services().rooms.directory.set_not_public(&room_id) {
|
||||
Ok(()) => RoomMessageEventContent::text_plain("Room unpublished"),
|
||||
Err(err) => RoomMessageEventContent::text_plain(&format!(
|
||||
"Unable to update room: {}",
|
||||
err
|
||||
)),
|
||||
}
|
||||
}
|
||||
RoomDirectoryCommand::List { page } => {
|
||||
let page = page.unwrap_or(1);
|
||||
let mut rooms = services().rooms.directory.public_rooms()
|
||||
let mut rooms = services()
|
||||
.rooms
|
||||
.directory
|
||||
.public_rooms()
|
||||
.filter_map(|r| r.ok())
|
||||
.map(|id| (
|
||||
id.clone(),
|
||||
services().rooms.state_cache.room_joined_count(&id).ok().flatten().unwrap_or(0),
|
||||
services().rooms.state_accessor.get_name(&id).ok().flatten().unwrap_or(id.to_string()),
|
||||
))
|
||||
.map(|id| {
|
||||
(
|
||||
id.clone(),
|
||||
services()
|
||||
.rooms
|
||||
.state_cache
|
||||
.room_joined_count(&id)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or(0),
|
||||
services()
|
||||
.rooms
|
||||
.state_accessor
|
||||
.get_name(&id)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or(id.to_string()),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
rooms.sort_by_key(|r| r.1);
|
||||
rooms.reverse();
|
||||
|
||||
let rooms: Vec<_> = rooms.into_iter()
|
||||
let rooms: Vec<_> = rooms
|
||||
.into_iter()
|
||||
.skip(page.saturating_sub(1) * PAGE_SIZE)
|
||||
.take(PAGE_SIZE)
|
||||
.collect();
|
||||
|
||||
|
||||
if rooms.is_empty() {
|
||||
return Ok(RoomMessageEventContent::text_plain("No more rooms."));
|
||||
};
|
||||
|
||||
|
||||
let output_plain = format!(
|
||||
"Rooms:\n{}",
|
||||
rooms
|
||||
.iter()
|
||||
.map(|(id, members, name)| format!("{id}\tMembers: {members}\tName: {name}"))
|
||||
.map(|(id, members, name)| format!(
|
||||
"{id}\tMembers: {members}\tName: {name}"
|
||||
))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
);
|
||||
|
@ -927,8 +1064,8 @@ impl Service {
|
|||
);
|
||||
RoomMessageEventContent::text_html(output_plain, output_html)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
AdminCommand::Federation(command) => match command {
|
||||
FederationCommand::DisableRoom { room_id } => {
|
||||
services().rooms.metadata.disable_room(&room_id, true)?;
|
||||
|
@ -939,11 +1076,7 @@ impl Service {
|
|||
RoomMessageEventContent::text_plain("Room enabled.")
|
||||
}
|
||||
FederationCommand::IncomingFederation => {
|
||||
let map = services()
|
||||
.globals
|
||||
.roomid_federationhandletime
|
||||
.read()
|
||||
.await;
|
||||
let map = services().globals.roomid_federationhandletime.read().await;
|
||||
let mut msg: String = format!("Handling {} incoming pdus:\n", map.len());
|
||||
|
||||
for (r, (e, i)) in map.iter() {
|
||||
|
@ -957,9 +1090,11 @@ impl Service {
|
|||
);
|
||||
}
|
||||
RoomMessageEventContent::text_plain(&msg)
|
||||
},
|
||||
}
|
||||
FederationCommand::SignJson => {
|
||||
if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```"
|
||||
if body.len() > 2
|
||||
&& body[0].trim().starts_with("```")
|
||||
&& body.last().unwrap().trim() == "```"
|
||||
{
|
||||
let string = body[1..body.len() - 1].join("\n");
|
||||
match serde_json::from_str(&string) {
|
||||
|
@ -974,16 +1109,20 @@ impl Service {
|
|||
.expect("canonical json is valid json");
|
||||
RoomMessageEventContent::text_plain(json_text)
|
||||
}
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!("Invalid json: {e}")),
|
||||
Err(e) => {
|
||||
RoomMessageEventContent::text_plain(format!("Invalid json: {e}"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RoomMessageEventContent::text_plain(
|
||||
"Expected code block in command body. Add --help for details.",
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
FederationCommand::VerifyJson => {
|
||||
if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```"
|
||||
if body.len() > 2
|
||||
&& body[0].trim().starts_with("```")
|
||||
&& body.last().unwrap().trim() == "```"
|
||||
{
|
||||
let string = body[1..body.len() - 1].join("\n");
|
||||
match serde_json::from_str(&string) {
|
||||
|
@ -1018,8 +1157,7 @@ impl Service {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ruma::signatures::verify_json(&valid_key_map, &value).is_ok() {
|
||||
RoomMessageEventContent::text_plain("Signature correct")
|
||||
} else if let Err(e) =
|
||||
|
@ -1034,20 +1172,22 @@ impl Service {
|
|||
)
|
||||
}
|
||||
}
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!("Invalid json: {e}")),
|
||||
Err(e) => {
|
||||
RoomMessageEventContent::text_plain(format!("Invalid json: {e}"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RoomMessageEventContent::text_plain(
|
||||
"Expected code block in command body. Add --help for details.",
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
AdminCommand::Server(command) => match command {
|
||||
ServerCommand::ShowConfig => {
|
||||
// Construct and send the response
|
||||
RoomMessageEventContent::text_plain(format!("{}", services().globals.config))
|
||||
},
|
||||
}
|
||||
ServerCommand::MemoryUsage => {
|
||||
let response1 = services().memory_usage().await;
|
||||
let response2 = services().globals.db.memory_usage();
|
||||
|
@ -1055,18 +1195,18 @@ impl Service {
|
|||
RoomMessageEventContent::text_plain(format!(
|
||||
"Services:\n{response1}\n\nDatabase:\n{response2}"
|
||||
))
|
||||
},
|
||||
}
|
||||
ServerCommand::ClearDatabaseCaches { amount } => {
|
||||
services().globals.db.clear_caches(amount);
|
||||
|
||||
RoomMessageEventContent::text_plain("Done.")
|
||||
},
|
||||
}
|
||||
ServerCommand::ClearServiceCaches { amount } => {
|
||||
services().clear_caches(amount).await;
|
||||
|
||||
RoomMessageEventContent::text_plain("Done.")
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
AdminCommand::Debug(command) => match command {
|
||||
DebugCommand::GetAuthChain { event_id } => {
|
||||
let event_id = Arc::<EventId>::from(event_id);
|
||||
|
@ -1093,9 +1233,11 @@ impl Service {
|
|||
} else {
|
||||
RoomMessageEventContent::text_plain("Event not found.")
|
||||
}
|
||||
},
|
||||
}
|
||||
DebugCommand::ParsePdu => {
|
||||
if body.len() > 2 && body[0].trim().starts_with("```") && body.last().unwrap().trim() == "```"
|
||||
if body.len() > 2
|
||||
&& body[0].trim().starts_with("```")
|
||||
&& body.last().unwrap().trim() == "```"
|
||||
{
|
||||
let string = body[1..body.len() - 1].join("\n");
|
||||
match serde_json::from_str(&string) {
|
||||
|
@ -1107,9 +1249,9 @@ impl Service {
|
|||
match serde_json::from_value::<PduEvent>(
|
||||
serde_json::to_value(value).expect("value is json"),
|
||||
) {
|
||||
Ok(pdu) => RoomMessageEventContent::text_plain(format!(
|
||||
"EventId: {event_id:?}\n{pdu:#?}"
|
||||
)),
|
||||
Ok(pdu) => RoomMessageEventContent::text_plain(
|
||||
format!("EventId: {event_id:?}\n{pdu:#?}"),
|
||||
),
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"EventId: {event_id:?}\nCould not parse event: {e}"
|
||||
)),
|
||||
|
@ -1127,7 +1269,7 @@ impl Service {
|
|||
} else {
|
||||
RoomMessageEventContent::text_plain("Expected code block in command body.")
|
||||
}
|
||||
},
|
||||
}
|
||||
DebugCommand::GetPdu { event_id } => {
|
||||
let mut outlier = false;
|
||||
let mut pdu_json = services()
|
||||
|
@ -1165,8 +1307,8 @@ impl Service {
|
|||
}
|
||||
None => RoomMessageEventContent::text_plain("PDU not found."),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Ok(reply_message_content)
|
||||
|
@ -1659,7 +1801,9 @@ impl Service {
|
|||
}
|
||||
|
||||
fn escape_html(s: &str) -> String {
|
||||
s.replace('&', "&").replace('<', "<").replace('>', ">")
|
||||
s.replace('&', "&")
|
||||
.replace('<', "<")
|
||||
.replace('>', ">")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -19,7 +19,7 @@ pub trait Data: Send + Sync {
|
|||
&'a self,
|
||||
room_id: &RoomId,
|
||||
) -> Box<dyn Iterator<Item = Result<OwnedRoomAliasId>> + 'a>;
|
||||
|
||||
|
||||
/// Returns all local aliases on the server
|
||||
fn all_local_aliases<'a>(
|
||||
&'a self,
|
||||
|
|
|
@ -506,7 +506,11 @@ impl Service {
|
|||
.state_cache
|
||||
.is_joined(server_user, &admin_room)?
|
||||
{
|
||||
services().admin.process_message(body, pdu.event_id.clone(), pdu.sender.clone());
|
||||
services().admin.process_message(
|
||||
body,
|
||||
pdu.event_id.clone(),
|
||||
pdu.sender.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue