diff --git a/src/client_server/account.rs b/src/client_server/account.rs index 81119ba3..f48543e2 100644 --- a/src/client_server/account.rs +++ b/src/client_server/account.rs @@ -2,6 +2,7 @@ use std::{collections::BTreeMap, convert::TryInto}; use super::{State, DEVICE_ID_LENGTH, SESSION_ID_LENGTH, TOKEN_LENGTH}; use crate::{pdu::PduBuilder, utils, ConduitResult, Database, Error, Ruma}; +use log::info; use ruma::{ api::client::{ error::ErrorKind, @@ -510,6 +511,8 @@ pub async fn register_route( )?; } + info!("{} registered on this server", user_id); + db.flush().await?; Ok(register::Response { @@ -686,6 +689,8 @@ pub async fn deactivate_route( // Remove devices and mark account as deactivated db.users.deactivate_account(&sender_user)?; + info!("{} deactivated their account", sender_user); + db.flush().await?; Ok(deactivate::Response { diff --git a/src/client_server/directory.rs b/src/client_server/directory.rs index 202417e3..048b4100 100644 --- a/src/client_server/directory.rs +++ b/src/client_server/directory.rs @@ -1,5 +1,6 @@ use super::State; use crate::{server_server, ConduitResult, Database, Error, Result, Ruma}; +use log::info; use ruma::{ api::{ client::{ @@ -82,8 +83,13 @@ pub async fn set_room_visibility_route( db: State<'_, Database>, body: Ruma>, ) -> ConduitResult { + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); + match body.visibility { - room::Visibility::Public => db.rooms.set_public(&body.room_id, true)?, + room::Visibility::Public => { + db.rooms.set_public(&body.room_id, true)?; + info!("{} made {} public", sender_user, body.room_id); + } room::Visibility::Private => db.rooms.set_public(&body.room_id, false)?, } diff --git a/src/client_server/room.rs b/src/client_server/room.rs index fdc9529a..a50f69c8 100644 --- a/src/client_server/room.rs +++ b/src/client_server/room.rs @@ -1,5 +1,6 @@ use super::State; use crate::{pdu::PduBuilder, ConduitResult, Database, Error, Ruma}; +use log::info; use ruma::{ api::client::{ error::ErrorKind, @@ -323,6 +324,8 @@ pub async fn create_room_route( db.rooms.set_public(&room_id, true)?; } + info!("{} created a room", sender_user); + db.flush().await?; Ok(create_room::Response::new(room_id).into()) diff --git a/src/client_server/session.rs b/src/client_server/session.rs index c8775ef5..da3d8d88 100644 --- a/src/client_server/session.rs +++ b/src/client_server/session.rs @@ -1,5 +1,6 @@ use super::{State, DEVICE_ID_LENGTH, TOKEN_LENGTH}; use crate::{utils, ConduitResult, Database, Error, Ruma}; +use log::info; use ruma::{ api::client::{ error::ErrorKind, @@ -93,6 +94,8 @@ pub async fn login_route( body.initial_device_display_name.clone(), )?; + info!("{} logged in", user_id); + db.flush().await?; Ok(login::Response { diff --git a/src/database.rs b/src/database.rs index 51c3895a..576a250e 100644 --- a/src/database.rs +++ b/src/database.rs @@ -39,9 +39,7 @@ impl Database { /// Tries to remove the old database but ignores all errors. pub fn try_remove(server_name: &str) -> Result<()> { let mut path = ProjectDirs::from("xyz", "koesters", "conduit") - .ok_or(Error::BadConfig( - "The OS didn't return a valid home directory path.", - ))? + .ok_or_else(|| Error::bad_config("The OS didn't return a valid home directory path."))? .data_dir() .to_path_buf(); path.push(server_name); @@ -59,15 +57,15 @@ impl Database { .map(|x| Ok::<_, Error>(x.to_owned())) .unwrap_or_else(|_| { let path = ProjectDirs::from("xyz", "koesters", "conduit") - .ok_or(Error::BadConfig( - "The OS didn't return a valid home directory path.", - ))? + .ok_or_else(|| { + Error::bad_config("The OS didn't return a valid home directory path.") + })? .data_dir() .join(server_name); Ok(path .to_str() - .ok_or(Error::BadConfig("Database path contains invalid unicode."))? + .ok_or_else(|| Error::bad_config("Database path contains invalid unicode."))? .to_owned()) })?; @@ -79,7 +77,7 @@ impl Database { .get_int("cache_capacity") .unwrap_or(1024 * 1024 * 1024), ) - .map_err(|_| Error::BadConfig("Cache capacity needs to be a u64."))?, + .map_err(|_| Error::bad_config("Cache capacity needs to be a u64."))?, ) .print_profile_on_drop(false) .open()?; diff --git a/src/database/globals.rs b/src/database/globals.rs index 37f10eec..359d0643 100644 --- a/src/database/globals.rs +++ b/src/database/globals.rs @@ -62,12 +62,12 @@ impl Globals { .unwrap_or("localhost") .to_string() .try_into() - .map_err(|_| Error::BadConfig("Invalid server_name."))?, + .map_err(|_| Error::bad_config("Invalid server_name."))?, max_request_size: config .get_int("max_request_size") .unwrap_or(20 * 1024 * 1024) // Default to 20 MB .try_into() - .map_err(|_| Error::BadConfig("Invalid max_request_size."))?, + .map_err(|_| Error::bad_config("Invalid max_request_size."))?, registration_disabled: config.get_bool("registration_disabled").unwrap_or(false), encryption_disabled: config.get_bool("encryption_disabled").unwrap_or(false), federation_enabled: config.get_bool("federation_enabled").unwrap_or(false), diff --git a/src/error.rs b/src/error.rs index f521da43..4c24fd75 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,7 +1,14 @@ +use std::{collections::HashMap, sync::RwLock, time::Duration, time::Instant}; + use log::error; -use ruma::api::client::{error::ErrorKind, r0::uiaa::UiaaInfo}; +use ruma::{ + api::client::{error::ErrorKind, r0::uiaa::UiaaInfo}, + events::room::message, +}; use thiserror::Error; +use crate::{database::admin::AdminCommand, Database}; + #[cfg(feature = "conduit_bin")] use { crate::RumaResponse, @@ -53,6 +60,11 @@ impl Error { error!("BadDatabase: {}", message); Self::BadDatabase(message) } + + pub fn bad_config(message: &'static str) -> Self { + error!("BadConfig: {}", message); + Self::BadConfig(message) + } } #[cfg(feature = "conduit_bin")] @@ -95,3 +107,50 @@ where .respond_to(r) } } + +pub struct ConduitLogger { + pub db: Database, + pub last_logs: RwLock>, +} + +impl log::Log for ConduitLogger { + fn enabled(&self, _metadata: &log::Metadata<'_>) -> bool { + true + } + + fn log(&self, record: &log::Record<'_>) { + let output = format!("{} - {}", record.level(), record.args()); + + println!("{}", output); + + if self.enabled(record.metadata()) + && record + .module_path() + .map_or(false, |path| path.starts_with("conduit::")) + { + if self + .last_logs + .read() + .unwrap() + .get(&output) + .map_or(false, |i| i.elapsed() < Duration::from_secs(60 * 30)) + { + return; + } + + if let Ok(mut_last_logs) = &mut self.last_logs.try_write() { + mut_last_logs.insert(output.clone(), Instant::now()); + } + + self.db.admin.send(AdminCommand::SendTextMessage( + message::TextMessageEventContent { + body: output, + formatted: None, + relates_to: None, + }, + )); + } + } + + fn flush(&self) {} +} diff --git a/src/main.rs b/src/main.rs index 8fb5fda9..f2edc137 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,8 @@ mod ruma_wrapper; mod utils; pub use database::Database; -pub use error::{Error, Result}; +pub use error::{ConduitLogger, Error, Result}; +use log::LevelFilter; pub use pdu::PduEvent; pub use rocket::State; pub use ruma_wrapper::{ConduitResult, Ruma, RumaResponse}; @@ -19,6 +20,9 @@ pub use ruma_wrapper::{ConduitResult, Ruma, RumaResponse}; use rocket::{fairing::AdHoc, routes}; fn setup_rocket() -> rocket::Rocket { + // Force log level off, so we can use our own logger + std::env::set_var("ROCKET_LOG", "off"); + rocket::ignite() .mount( "/", @@ -133,6 +137,12 @@ fn setup_rocket() -> rocket::Rocket { let data = Database::load_or_create(rocket.config().await).expect("valid config"); data.sending.start_handler(&data.globals, &data.rooms); + log::set_boxed_logger(Box::new(ConduitLogger { + db: data.clone(), + last_logs: Default::default(), + })) + .unwrap(); + log::set_max_level(LevelFilter::Info); Ok(rocket.manage(data)) })) @@ -140,10 +150,5 @@ fn setup_rocket() -> rocket::Rocket { #[rocket::main] async fn main() { - // Default log level - if std::env::var("ROCKET_LOG").is_err() { - std::env::set_var("ROCKET_LOG", "critical"); - } - setup_rocket().launch().await.unwrap(); } diff --git a/src/ruma_wrapper.rs b/src/ruma_wrapper.rs index 7722a425..8da3e17b 100644 --- a/src/ruma_wrapper.rs +++ b/src/ruma_wrapper.rs @@ -97,7 +97,7 @@ where handle.read_to_end(&mut body).await.unwrap(); let http_request = http_request.body(body.clone()).unwrap(); - log::info!("{:?}", http_request); + log::debug!("{:?}", http_request); match ::Incoming::try_from(http_request) { Ok(t) => Success(Ruma { diff --git a/src/server_server.rs b/src/server_server.rs index 0f24e153..d8d0fa52 100644 --- a/src/server_server.rs +++ b/src/server_server.rs @@ -58,12 +58,12 @@ where T: Debug, { if !globals.federation_enabled() { - return Err(Error::BadConfig("Federation is disabled.")); + return Err(Error::bad_config("Federation is disabled.")); } - let resolver = AsyncResolver::tokio_from_system_conf() - .await - .map_err(|_| Error::BadConfig("Failed to set up trust dns resolver with system config."))?; + let resolver = AsyncResolver::tokio_from_system_conf().await.map_err(|_| { + Error::bad_config("Failed to set up trust dns resolver with system config.") + })?; let mut host = None; @@ -213,7 +213,7 @@ where #[cfg_attr(feature = "conduit_bin", get("/_matrix/federation/v1/version"))] pub fn get_server_version(db: State<'_, Database>) -> ConduitResult { if !db.globals.federation_enabled() { - return Err(Error::BadConfig("Federation is disabled.")); + return Err(Error::bad_config("Federation is disabled.")); } Ok(get_server_version::Response { @@ -276,7 +276,7 @@ pub async fn get_public_rooms_filtered_route( body: Ruma>, ) -> ConduitResult { if !db.globals.federation_enabled() { - return Err(Error::BadConfig("Federation is disabled.")); + return Err(Error::bad_config("Federation is disabled.")); } let response = client_server::get_public_rooms_filtered_helper( @@ -323,7 +323,7 @@ pub async fn get_public_rooms_route( body: Ruma>, ) -> ConduitResult { if !db.globals.federation_enabled() { - return Err(Error::BadConfig("Federation is disabled.")); + return Err(Error::bad_config("Federation is disabled.")); } let response = client_server::get_public_rooms_filtered_helper( @@ -370,7 +370,7 @@ pub fn send_transaction_message_route<'a>( body: Ruma>, ) -> ConduitResult { if !db.globals.federation_enabled() { - return Err(Error::BadConfig("Federation is disabled.")); + return Err(Error::bad_config("Federation is disabled.")); } //dbg!(&*body); @@ -423,7 +423,7 @@ pub fn get_missing_events_route<'a>( body: Ruma>, ) -> ConduitResult { if !db.globals.federation_enabled() { - return Err(Error::BadConfig("Federation is disabled.")); + return Err(Error::bad_config("Federation is disabled.")); } let mut queued_events = body.latest_events.clone(); @@ -468,7 +468,7 @@ pub fn get_profile_information_route<'a>( body: Ruma>, ) -> ConduitResult { if !db.globals.federation_enabled() { - return Err(Error::BadConfig("Federation is disabled.")); + return Err(Error::bad_config("Federation is disabled.")); } let mut displayname = None; @@ -500,7 +500,7 @@ pub fn get_user_devices_route<'a>( body: Ruma>, ) -> ConduitResult { if !db.globals.federation_enabled() { - return Err(Error::BadConfig("Federation is disabled.")); + return Err(Error::bad_config("Federation is disabled.")); } let mut displayname = None;