From 63551160638a81e721cb67c424ca3e622d3bcdbc Mon Sep 17 00:00:00 2001 From: Awiteb Date: Sun, 14 Apr 2024 17:38:44 +0300 Subject: [PATCH] chore: Make the `process_admin_message` more flixable Make it return `Option` instade of `RoomMessageEventContent` Helped-by: Matthias Ahouansou Signed-off-by: Awiteb --- src/service/admin/mod.rs | 260 +++++++++++++++++++++------------------ 1 file changed, 143 insertions(+), 117 deletions(-) diff --git a/src/service/admin/mod.rs b/src/service/admin/mod.rs index 4b5b39cf..bc53e485 100644 --- a/src/service/admin/mod.rs +++ b/src/service/admin/mod.rs @@ -221,38 +221,39 @@ impl Service { tokio::select! { Some(event) = receiver.recv() => { let message_content = match event { - AdminRoomEvent::SendMessage(content) => content, + AdminRoomEvent::SendMessage(content) => Some(content), AdminRoomEvent::ProcessMessage(room_message, event_id) => self.process_admin_message(room_message, &event_id).await }; + if let Some(message_content) = message_content { + let mutex_state = Arc::clone( + services().globals + .roomid_mutex_state + .write() + .await + .entry(conduit_room.to_owned()) + .or_default(), + ); - let mutex_state = Arc::clone( - services().globals - .roomid_mutex_state - .write() - .await - .entry(conduit_room.to_owned()) - .or_default(), - ); + let state_lock = mutex_state.lock().await; - let state_lock = mutex_state.lock().await; - - services() - .rooms - .timeline - .build_and_append_pdu( - PduBuilder { - event_type: TimelineEventType::RoomMessage, - content: to_raw_value(&message_content) - .expect("event is valid, we just created it"), - unsigned: None, - state_key: None, - redacts: None, - }, - &conduit_user, - &conduit_room, - &state_lock, - ) - .await.unwrap(); + services() + .rooms + .timeline + .build_and_append_pdu( + PduBuilder { + event_type: TimelineEventType::RoomMessage, + content: to_raw_value(&message_content) + .expect("event is valid, we just created it"), + unsigned: None, + state_key: None, + redacts: None, + }, + &conduit_user, + &conduit_room, + &state_lock, + ) + .await.unwrap(); + } } } } @@ -319,12 +320,14 @@ impl Service { Ok(()) } - // Parse and process a message from the admin room + /// Parse and process a message from the admin room + /// + /// May return `Option::None` if there is no process case for the message async fn process_admin_message( &self, room_message: String, event_id: &EventId, - ) -> RoomMessageEventContent { + ) -> Option { 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(); @@ -336,7 +339,7 @@ impl Service { let message = error.replace("server.name", server_name.as_str()); let html_message = self.usage_to_html(&message, server_name); - return RoomMessageEventContent::text_html(message, html_message); + return Some(RoomMessageEventContent::text_html(message, html_message)); } }; @@ -344,7 +347,8 @@ impl Service { .process_admin_command(admin_command, body, event_id) .await { - Ok(reply_message) => reply_message, + Ok(Some(reply_message)) => Some(reply_message), + Ok(None) => None, Err(error) => { let markdown_message = format!( "Encountered an error while handling the command:\n\ @@ -355,7 +359,10 @@ impl Service {
\n{error}\n
", ); - RoomMessageEventContent::text_html(markdown_message, html_message) + Some(RoomMessageEventContent::text_html( + markdown_message, + html_message, + )) } } } @@ -382,19 +389,22 @@ impl Service { AdminCommand::try_parse_from(argv).map_err(|error| error.to_string()) } + /// Process the entered admin command + /// + /// May return `Ok(Option::None)` if there is no process case for the message async fn process_admin_command( &self, command: AdminCommand, body: Vec<&str>, event_id: &EventId, - ) -> Result { + ) -> Result> { let reply_message_content = match command { AdminCommand::RegisterAppservice => { if body.len() > 2 && body[0].trim() == "```" && body.last().unwrap().trim() == "```" { let appservice_config = body[1..body.len() - 1].join("\n"); let parsed_config = serde_yaml::from_str::(&appservice_config); - match parsed_config { + Some(match parsed_config { Ok(yaml) => match services().appservice.register_appservice(yaml).await { Ok(id) => RoomMessageEventContent::text_plain(format!( "Appservice registered with ID: {id}." @@ -406,25 +416,27 @@ impl Service { Err(e) => RoomMessageEventContent::text_plain(format!( "Could not parse appservice config: {e}" )), - } + }) } else { - RoomMessageEventContent::text_plain( + Some(RoomMessageEventContent::text_plain( "Expected code block in command body. Add --help for details.", - ) + )) } } AdminCommand::UnregisterAppservice { appservice_identifier, - } => match services() - .appservice - .unregister_appservice(&appservice_identifier) - .await - { - Ok(()) => RoomMessageEventContent::text_plain("Appservice unregistered."), - Err(e) => RoomMessageEventContent::text_plain(format!( - "Failed to unregister appservice: {e}" - )), - }, + } => Some( + match services() + .appservice + .unregister_appservice(&appservice_identifier) + .await + { + Ok(()) => RoomMessageEventContent::text_plain("Appservice unregistered."), + Err(e) => RoomMessageEventContent::text_plain(format!( + "Failed to unregister appservice: {e}" + )), + }, + ), AdminCommand::ListAppservices => { let appservices = services().appservice.iter_ids().await; let output = format!( @@ -432,7 +444,7 @@ impl Service { appservices.len(), appservices.join(", ") ); - RoomMessageEventContent::text_plain(output) + Some(RoomMessageEventContent::text_plain(output)) } AdminCommand::ListRooms => { let room_ids = services().rooms.metadata.iter_ids(); @@ -453,16 +465,16 @@ impl Service { .collect::>() .join("\n") ); - RoomMessageEventContent::text_plain(output) + Some(RoomMessageEventContent::text_plain(output)) } - AdminCommand::ListLocalUsers => match services().users.list_local_users() { + AdminCommand::ListLocalUsers => Some(match services().users.list_local_users() { Ok(users) => { let mut msg: String = format!("Found {} local user account(s):\n", users.len()); msg += &users.join("\n"); RoomMessageEventContent::text_plain(&msg) } Err(e) => RoomMessageEventContent::text_plain(e.to_string()), - }, + }), AdminCommand::IncomingFederation => { let map = services().globals.roomid_federationhandletime.read().await; let mut msg: String = format!("Handling {} incoming pdus:\n", map.len()); @@ -477,7 +489,7 @@ impl Service { elapsed.as_secs() % 60 ); } - RoomMessageEventContent::text_plain(&msg) + Some(RoomMessageEventContent::text_plain(&msg)) } AdminCommand::GetAuthChain { event_id } => { let event_id = Arc::::from(event_id); @@ -498,18 +510,18 @@ impl Service { .await? .count(); let elapsed = start.elapsed(); - RoomMessageEventContent::text_plain(format!( + Some(RoomMessageEventContent::text_plain(format!( "Loaded auth chain with length {count} in {elapsed:?}" - )) + ))) } else { - RoomMessageEventContent::text_plain("Event not found.") + Some(RoomMessageEventContent::text_plain("Event not found.")) } } AdminCommand::ParsePdu => { if body.len() > 2 && body[0].trim() == "```" && body.last().unwrap().trim() == "```" { let string = body[1..body.len() - 1].join("\n"); - match serde_json::from_str(&string) { + Some(match serde_json::from_str(&string) { Ok(value) => { match ruma::signatures::reference_hash(&value, &RoomVersionId::V6) { Ok(hash) => { @@ -534,9 +546,11 @@ impl Service { Err(e) => RoomMessageEventContent::text_plain(format!( "Invalid json in command body: {e}" )), - } + }) } else { - RoomMessageEventContent::text_plain("Expected code block in command body.") + Some(RoomMessageEventContent::text_plain( + "Expected code block in command body.", + )) } } AdminCommand::GetPdu { event_id } => { @@ -553,7 +567,7 @@ impl Service { Some(json) => { let json_text = serde_json::to_string_pretty(&json) .expect("canonical json is valid json"); - RoomMessageEventContent::text_html( + Some(RoomMessageEventContent::text_html( format!( "{}\n```json\n{}\n```", if outlier { @@ -572,32 +586,35 @@ impl Service { }, HtmlEscape(&json_text) ), - ) + )) } - None => RoomMessageEventContent::text_plain("PDU not found."), + None => Some(RoomMessageEventContent::text_plain("PDU not found.")), } } AdminCommand::MemoryUsage => { let response1 = services().memory_usage().await; let response2 = services().globals.db.memory_usage(); - RoomMessageEventContent::text_plain(format!( + Some(RoomMessageEventContent::text_plain(format!( "Services:\n{response1}\n\nDatabase:\n{response2}" - )) + ))) } AdminCommand::ClearDatabaseCaches { amount } => { services().globals.db.clear_caches(amount); - RoomMessageEventContent::text_plain("Done.") + Some(RoomMessageEventContent::text_plain("Done.")) } AdminCommand::ClearServiceCaches { amount } => { services().clear_caches(amount).await; - RoomMessageEventContent::text_plain("Done.") + Some(RoomMessageEventContent::text_plain("Done.")) } AdminCommand::ShowConfig => { // Construct and send the response - RoomMessageEventContent::text_plain(format!("{}", services().globals.config)) + Some(RoomMessageEventContent::text_plain(format!( + "{}", + services().globals.config + ))) } AdminCommand::ResetPassword { username } => { let user_id = match UserId::parse_with_server_name( @@ -606,17 +623,17 @@ impl Service { ) { Ok(id) => id, Err(e) => { - return Ok(RoomMessageEventContent::text_plain(format!( + return Ok(Some(RoomMessageEventContent::text_plain(format!( "The supplied username is not a valid username: {e}" - ))) + )))) } }; // Checks if user is local if user_id.server_name() != services().globals.server_name() { - return Ok(RoomMessageEventContent::text_plain( + return Ok(Some(RoomMessageEventContent::text_plain( "The specified user is not from this server!", - )); + ))); }; // Check if the specified user is valid @@ -628,24 +645,26 @@ impl Service { ) .expect("conduit user exists") { - return Ok(RoomMessageEventContent::text_plain( + return Ok(Some(RoomMessageEventContent::text_plain( "The specified user does not exist!", - )); + ))); } let new_password = utils::random_string(AUTO_GEN_PASSWORD_LENGTH); - match services() - .users - .set_password(&user_id, Some(new_password.as_str())) - { - Ok(()) => RoomMessageEventContent::text_plain(format!( - "Successfully reset the password for user {user_id}: {new_password}" - )), - Err(e) => RoomMessageEventContent::text_plain(format!( - "Couldn't reset the password for user {user_id}: {e}" - )), - } + Some( + match services() + .users + .set_password(&user_id, Some(new_password.as_str())) + { + Ok(()) => RoomMessageEventContent::text_plain(format!( + "Successfully reset the password for user {user_id}: {new_password}" + )), + Err(e) => RoomMessageEventContent::text_plain(format!( + "Couldn't reset the password for user {user_id}: {e}" + )), + }, + ) } AdminCommand::CreateUser { username, password } => { let is_auto_generated_password = password.is_none(); @@ -658,20 +677,20 @@ impl Service { ) { Ok(id) => id, Err(e) => { - return Ok(RoomMessageEventContent::text_plain(format!( + return Ok(Some(RoomMessageEventContent::text_plain(format!( "The supplied username is not a valid username: {e}" - ))) + )))) } }; if user_id.is_historical() { - return Ok(RoomMessageEventContent::text_plain(format!( + return Ok(Some(RoomMessageEventContent::text_plain(format!( "Userid {user_id} is not allowed due to historical" - ))); + )))); } if services().users.exists(&user_id)? { - return Ok(RoomMessageEventContent::text_plain(format!( + return Ok(Some(RoomMessageEventContent::text_plain(format!( "Userid {user_id} already exists" - ))); + )))); } // Create user services().users.create(&user_id, Some(password.as_str()))?; @@ -718,17 +737,17 @@ impl Service { // we dont add a device since we're not the user, just the creator // Inhibit login does not work for guests - RoomMessageEventContent::text_plain(format!( + Some(RoomMessageEventContent::text_plain(format!( "Created user with user_id: {user_id} and password: {password}" - )) + ))) } AdminCommand::DisableRoom { room_id } => { services().rooms.metadata.disable_room(&room_id, true)?; - RoomMessageEventContent::text_plain("Room disabled.") + Some(RoomMessageEventContent::text_plain("Room disabled.")) } AdminCommand::EnableRoom { room_id } => { services().rooms.metadata.disable_room(&room_id, false)?; - RoomMessageEventContent::text_plain("Room enabled.") + Some(RoomMessageEventContent::text_plain("Room enabled.")) } AdminCommand::DeactivateUser { leave_rooms, @@ -736,14 +755,15 @@ impl Service { } => { let user_id = Arc::::from(user_id); if !services().users.exists(&user_id)? { - RoomMessageEventContent::text_plain(format!( + Some(RoomMessageEventContent::text_plain(format!( "User {user_id} doesn't exist on this server" - )) + ))) } else if user_id.server_name() != services().globals.server_name() { - RoomMessageEventContent::text_plain(format!( + Some(RoomMessageEventContent::text_plain(format!( "User {user_id} is not from this server" - )) + ))) } else { + // FIXME: Why this is here! RoomMessageEventContent::text_plain(format!( "Making {user_id} leave all rooms before deactivation..." )); @@ -754,9 +774,9 @@ impl Service { leave_all_rooms(&user_id).await?; } - RoomMessageEventContent::text_plain(format!( + Some(RoomMessageEventContent::text_plain(format!( "User {user_id} has been deactivated" - )) + ))) } } AdminCommand::DeactivateAll { leave_rooms, force } => { @@ -821,10 +841,10 @@ impl Service { html_message.push_str("\n\n"); } if !markdown_message.is_empty() { - return Ok(RoomMessageEventContent::text_html( + return Ok(Some(RoomMessageEventContent::text_html( markdown_message, html_message, - )); + ))); } let mut deactivation_count = 0; @@ -856,16 +876,16 @@ impl Service { } if admins.is_empty() { - RoomMessageEventContent::text_plain(format!( + Some(RoomMessageEventContent::text_plain(format!( "Deactivated {deactivation_count} accounts." - )) + ))) } else { - RoomMessageEventContent::text_plain(format!("Deactivated {} accounts.\nSkipped admin accounts: {:?}. Use --force to deactivate admin accounts", deactivation_count, admins.join(", "))) + Some(RoomMessageEventContent::text_plain(format!("Deactivated {} accounts.\nSkipped admin accounts: {:?}. Use --force to deactivate admin accounts", deactivation_count, admins.join(", ")))) } } else { - RoomMessageEventContent::text_plain( + Some(RoomMessageEventContent::text_plain( "Expected code block in command body. Add --help for details.", - ) + )) } } AdminCommand::SignJson => { @@ -882,14 +902,16 @@ impl Service { .expect("our request json is what ruma expects"); let json_text = serde_json::to_string_pretty(&value) .expect("canonical json is valid json"); - RoomMessageEventContent::text_plain(json_text) + Some(RoomMessageEventContent::text_plain(json_text)) } - Err(e) => RoomMessageEventContent::text_plain(format!("Invalid json: {e}")), + Err(e) => Some(RoomMessageEventContent::text_plain(format!( + "Invalid json: {e}" + ))), } } else { - RoomMessageEventContent::text_plain( + Some(RoomMessageEventContent::text_plain( "Expected code block in command body. Add --help for details.", - ) + )) } } AdminCommand::VerifyJson => { @@ -908,18 +930,22 @@ impl Service { let pub_key_map = pub_key_map.read().await; match ruma::signatures::verify_json(&pub_key_map, &value) { - Ok(_) => RoomMessageEventContent::text_plain("Signature correct"), - Err(e) => RoomMessageEventContent::text_plain(format!( + Ok(_) => { + Some(RoomMessageEventContent::text_plain("Signature correct")) + } + Err(e) => Some(RoomMessageEventContent::text_plain(format!( "Signature verification failed: {e}" - )), + ))), } } - Err(e) => RoomMessageEventContent::text_plain(format!("Invalid json: {e}")), + Err(e) => Some(RoomMessageEventContent::text_plain(format!( + "Invalid json: {e}" + ))), } } else { - RoomMessageEventContent::text_plain( + Some(RoomMessageEventContent::text_plain( "Expected code block in command body. Add --help for details.", - ) + )) } } };