conduit/src/database/admin.rs

115 lines
4.2 KiB
Rust
Raw Normal View History

2021-06-08 16:10:00 +00:00
use std::{
convert::{TryFrom, TryInto},
sync::Arc,
};
2020-11-09 11:21:04 +00:00
2021-06-08 16:10:00 +00:00
use crate::{pdu::PduBuilder, Database};
use log::warn;
2020-11-09 11:21:04 +00:00
use rocket::futures::{channel::mpsc, stream::StreamExt};
use ruma::{
events::{room::message, EventType},
UserId,
};
2021-07-14 07:07:08 +00:00
use tokio::sync::{RwLock, RwLockReadGuard};
2020-11-09 11:21:04 +00:00
pub enum AdminCommand {
RegisterAppservice(serde_yaml::Value),
ListAppservices,
SendMessage(message::MessageEventContent),
2020-11-09 11:21:04 +00:00
}
#[derive(Clone)]
pub struct Admin {
pub sender: mpsc::UnboundedSender<AdminCommand>,
}
impl Admin {
pub fn start_handler(
&self,
2021-07-14 07:07:08 +00:00
db: Arc<RwLock<Database>>,
2020-11-09 11:21:04 +00:00
mut receiver: mpsc::UnboundedReceiver<AdminCommand>,
) {
tokio::spawn(async move {
// TODO: Use futures when we have long admin commands
//let mut futures = FuturesUnordered::new();
2021-07-14 07:07:08 +00:00
let guard = db.read().await;
2020-11-09 11:21:04 +00:00
2021-07-14 07:07:08 +00:00
let conduit_user =
UserId::try_from(format!("@conduit:{}", guard.globals.server_name()))
.expect("@conduit:server_name is valid");
let conduit_room = guard
2020-11-09 11:21:04 +00:00
.rooms
.id_from_alias(
2021-07-14 07:07:08 +00:00
&format!("#admins:{}", guard.globals.server_name())
2020-11-09 11:21:04 +00:00
.try_into()
.expect("#admins:server_name is a valid room alias"),
)
.unwrap();
if conduit_room.is_none() {
warn!("Conduit instance does not have an #admins room. Logging to that room will not work. Restart Conduit after creating a user to fix this.");
}
2021-07-14 07:07:08 +00:00
drop(guard);
let send_message =
|message: message::MessageEventContent, guard: RwLockReadGuard<'_, Database>| {
if let Some(conduit_room) = &conduit_room {
guard
.rooms
.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomMessage,
content: serde_json::to_value(message)
.expect("event is valid, we just created it"),
unsigned: None,
state_key: None,
redacts: None,
},
&conduit_user,
&conduit_room,
&guard,
)
.unwrap();
}
};
2020-11-09 11:21:04 +00:00
loop {
2021-03-03 21:38:31 +00:00
tokio::select! {
2020-11-09 11:21:04 +00:00
Some(event) = receiver.next() => {
2021-07-14 07:07:08 +00:00
let guard = db.read().await;
2020-11-09 11:21:04 +00:00
match event {
AdminCommand::RegisterAppservice(yaml) => {
2021-07-14 07:07:08 +00:00
guard.appservice.register_appservice(yaml).unwrap(); // TODO handle error
}
AdminCommand::ListAppservices => {
2021-07-14 07:07:08 +00:00
if let Ok(appservices) = guard.appservice.iter_ids().map(|ids| ids.collect::<Vec<_>>()) {
2021-06-08 16:10:00 +00:00
let count = appservices.len();
let output = format!(
"Appservices ({}): {}",
count,
appservices.into_iter().filter_map(|r| r.ok()).collect::<Vec<_>>().join(", ")
);
2021-07-14 07:07:08 +00:00
send_message(message::MessageEventContent::text_plain(output), guard);
2021-06-08 16:10:00 +00:00
} else {
2021-07-14 07:07:08 +00:00
send_message(message::MessageEventContent::text_plain("Failed to get appservices."), guard);
2021-06-08 16:10:00 +00:00
}
}
AdminCommand::SendMessage(message) => {
2021-07-14 07:07:08 +00:00
send_message(message, guard)
2020-11-09 11:21:04 +00:00
}
}
}
}
}
});
}
pub fn send(&self, command: AdminCommand) {
2021-06-08 16:10:00 +00:00
self.sender.unbounded_send(command).unwrap();
2020-11-09 11:21:04 +00:00
}
}