this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Format

+175 -204
+1 -1
Cargo.toml
··· 9 9 useless_attribute = "deny" 10 10 arithmetic_side_effects = "warn" 11 11 missing_docs = "forbid" 12 - style = { level = "warn", priority = -1 } 12 + style = { level = "warn", priority = -1 } 13 13 missing_panics_doc = "warn" 14 14 pedantic = { level = "warn", priority = -1 }
+2 -2
mise/tasks/check.toml
··· 34 34 hide = true 35 35 run = "cargo test" 36 36 dir = "./server" 37 - env.LUMINA_POSTGRES_PASSWORD="lumina_pw" 38 - 37 + env.LUMINA_POSTGRES_PASSWORD = "lumina_pw" 38 + 39 39 [local-devel-test-client] 40 40 hide = true 41 41 run = "gleam test"
+16 -31
server/src/database.rs
··· 22 22 use crate::EnvVar::*; 23 23 use crate::errors::LuminaError::{self}; 24 24 use crate::helpers::events::EventLogger; 25 + use crate::postgres; 25 26 use crate::timeline; 26 27 use crate::{info_elog, success_elog, warn_elog}; 27 28 use bb8::Pool; ··· 29 30 use bb8_redis::RedisConnectionManager; 30 31 use cynthia_con::{CynthiaColors, CynthiaStyles}; 31 32 use std::time::Duration; 32 - use crate::postgres; 33 33 use tokio_postgres::NoTls; 34 34 35 35 pub(crate) async fn setup() -> Result<PgConn, LuminaError> { ··· 82 82 }; 83 83 uuu.2 = port.clone(); 84 84 // Parse the port as u16, if it fails, return an error 85 - pg_config.port(port.parse::<u16>().map_err(|_| { 86 - LuminaError::ConfInvalid( 87 - LUMINA_POSTGRES_PORT, 88 - ) 89 - })?); 85 + pg_config.port( 86 + port.parse::<u16>() 87 + .map_err(|_| LuminaError::ConfInvalid(LUMINA_POSTGRES_PORT))?, 88 + ); 90 89 match std::env::var("LUMINA_POSTGRES_HOST") { 91 90 Ok(val) => { 92 91 uuu.1 = val.clone(); ··· 125 124 126 125 // Create Postgres connection pool 127 126 let pg_manager = PostgresConnectionManager::new(pg_config.clone(), NoTls); 128 - let pg_pool = Pool::builder() 129 - .build(pg_manager) 130 - .await?; 127 + let pg_pool = Pool::builder().build(pg_manager).await?; 131 128 { 132 - let pg_conn = pg_pool 133 - .get() 134 - .await?; 129 + let pg_conn = pg_pool.get().await?; 135 130 pg_conn 136 131 .batch_execute(include_str!("../../SQL/create_pg.sql")) 137 132 .await?; 138 133 // Populate bloom filters 139 - let mut redis_conn = redis_pool 140 - .get() 141 - .await?; 134 + let mut redis_conn = redis_pool.get().await?; 142 135 let email_key = "bloom:email"; 143 136 let username_key = "bloom:username"; 144 137 ··· 152 145 .arg(email_key) 153 146 .arg(email) 154 147 .query_async(&mut *redis_conn) 155 - .await 156 - ?; 148 + .await?; 157 149 let _: () = redis::cmd("BF.ADD") 158 150 .arg(username_key) 159 151 .arg(username) 160 152 .query_async(&mut *redis_conn) 161 - .await 162 - ?; 153 + .await?; 163 154 } 164 155 info_elog!(ev_log, "Bloom filters populated from PostgreSQL.",); 165 156 }; ··· 318 309 .arg("MATCH") 319 310 .arg(pattern) 320 311 .query_async(&mut **redis_conn) 321 - .await 322 - ?; 312 + .await?; 323 313 324 314 cursor = result.0; 325 315 let keys = result.1; ··· 331 321 let ttl: i64 = redis::cmd("TTL") 332 322 .arg(&key) 333 323 .query_async(&mut **redis_conn) 334 - .await 335 - ?; 324 + .await?; 336 325 if ttl == -1 || ttl == 0 { 337 326 expired_keys.push(key); 338 327 } ··· 342 331 let _: () = redis::cmd("DEL") 343 332 .arg(&expired_keys) 344 333 .query_async(&mut **redis_conn) 345 - .await 346 - ?; 334 + .await?; 347 335 } 348 336 349 337 if cursor == 0 { ··· 383 371 .unwrap(), 384 372 ) 385 373 .query_async(&mut **redis_conn) 386 - .await 387 - ?; 374 + .await?; 388 375 return Ok(()); 389 376 }; 390 377 ··· 404 391 .unwrap(), 405 392 ) 406 393 .query_async(&mut **redis_conn) 407 - .await 408 - ?; 394 + .await?; 409 395 } 410 396 Err(_) => { 411 397 // If query fails, just update timestamp to avoid repeated failures ··· 417 403 .unwrap(), 418 404 ) 419 405 .query_async(&mut **redis_conn) 420 - .await 421 - ?; 406 + .await?; 422 407 } 423 408 } 424 409
+34 -29
server/src/errors.rs
··· 89 89 90 90 impl std::fmt::Display for LuminaError { 91 91 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 92 - write!(f, "{}", 93 - match self { 94 - LuminaError::ConfInvalid(s) => match s { 95 - crate::EnvVar::LUMINA_SERVER_ADDR => "LUMINA_SERVER_ADDR is an invalid address".to_string(), 96 - crate::EnvVar::LUMINA_SERVER_PORT => "LUMINA_SERVER_PORT is not a valid port number".to_string(), 97 - crate::EnvVar::LUMINA_POSTGRES_PORT => "LUMINA_POSTGRES_PORT is not a valid port number".to_string(), 98 - }, 92 + write!( 93 + f, 94 + "{}", 95 + match self { 96 + LuminaError::ConfInvalid(s) => match s { 97 + crate::EnvVar::LUMINA_SERVER_ADDR => 98 + "LUMINA_SERVER_ADDR is an invalid address".to_string(), 99 + crate::EnvVar::LUMINA_SERVER_PORT => 100 + "LUMINA_SERVER_PORT is not a valid port number".to_string(), 101 + crate::EnvVar::LUMINA_POSTGRES_PORT => 102 + "LUMINA_POSTGRES_PORT is not a valid port number".to_string(), 103 + }, 99 104 100 - LuminaError::DbError(e) => match e { 101 - LuminaDbError::Redis(re) => format!("Redis error: {}", re), 102 - LuminaDbError::Postgres(pe) => format!("Postgres error: {}", pe), 103 - }, 104 - LuminaError::Bb8RunErrorPg(e) => format!("Postgres connection pool error: {}", e), 105 - LuminaError::Bb8RunErrorRedis(e) => format!("Redis connection pool error: {}", e), 106 - LuminaError::RocketFaillure(e) => format!("Rocket error: {}", e), 107 - LuminaError::BcryptError => "Bcrypt error".to_string(), 108 - LuminaError::RegisterEmailInUse => "Email already in use".to_string(), 109 - LuminaError::RegisterUsernameInUse => "Username already in use".to_string(), 110 - LuminaError::RegisterEmailNotValid => "Email not valid".to_string(), 111 - LuminaError::RegisterUsernameInvalid(s) => format!("Username invalid: {}", s), 112 - LuminaError::RegisterPasswordNotValid(s) => format!("Password not valid: {}", s), 113 - LuminaError::AuthenticationWrongPassword => "Wrong password".to_string(), 114 - LuminaError::UUidError => "UUID error".to_string(), 115 - LuminaError::RegexError => "Regex error".to_string(), 116 - LuminaError::SerializationError(s) => format!("Serialization error: {}", s), 117 - LuminaError::JoinFaillure => "Process join failure".to_string(), 118 - LuminaError::Unknown => "Unknown error".to_string(), 119 - } 120 - ) 105 + LuminaError::DbError(e) => match e { 106 + LuminaDbError::Redis(re) => format!("Redis error: {}", re), 107 + LuminaDbError::Postgres(pe) => format!("Postgres error: {}", pe), 108 + }, 109 + LuminaError::Bb8RunErrorPg(e) => format!("Postgres connection pool error: {}", e), 110 + LuminaError::Bb8RunErrorRedis(e) => format!("Redis connection pool error: {}", e), 111 + LuminaError::RocketFaillure(e) => format!("Rocket error: {}", e), 112 + LuminaError::BcryptError => "Bcrypt error".to_string(), 113 + LuminaError::RegisterEmailInUse => "Email already in use".to_string(), 114 + LuminaError::RegisterUsernameInUse => "Username already in use".to_string(), 115 + LuminaError::RegisterEmailNotValid => "Email not valid".to_string(), 116 + LuminaError::RegisterUsernameInvalid(s) => format!("Username invalid: {}", s), 117 + LuminaError::RegisterPasswordNotValid(s) => format!("Password not valid: {}", s), 118 + LuminaError::AuthenticationWrongPassword => "Wrong password".to_string(), 119 + LuminaError::UUidError => "UUID error".to_string(), 120 + LuminaError::RegexError => "Regex error".to_string(), 121 + LuminaError::SerializationError(s) => format!("Serialization error: {}", s), 122 + LuminaError::JoinFaillure => "Process join failure".to_string(), 123 + LuminaError::Unknown => "Unknown error".to_string(), 124 + } 125 + ) 121 126 } 122 - } 127 + }
+14 -9
server/src/main.rs
··· 66 66 } 67 67 impl std::fmt::Display for EnvVar { 68 68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 69 - write!(f, "{}", 70 - match self { 71 - EnvVar::LUMINA_SERVER_ADDR => "LUMINA_SERVER_ADDR", 72 - EnvVar::LUMINA_SERVER_PORT => "LUMINA_SERVER_PORT", 73 - EnvVar::LUMINA_POSTGRES_PORT => "LUMINA_POSTGRES_PORT", 74 - } 75 - ) 76 - }} 69 + write!( 70 + f, 71 + "{}", 72 + match self { 73 + EnvVar::LUMINA_SERVER_ADDR => "LUMINA_SERVER_ADDR", 74 + EnvVar::LUMINA_SERVER_PORT => "LUMINA_SERVER_PORT", 75 + EnvVar::LUMINA_POSTGRES_PORT => "LUMINA_POSTGRES_PORT", 76 + } 77 + ) 78 + } 79 + } 77 80 use crate::EnvVar::*; 78 81 use crate::database::{DatabaseConnections, PgConn}; 79 82 use crate::errors::LuminaError; ··· 147 150 None 148 151 } 149 152 150 - Err(LuminaError::DbError(crate::errors::LuminaDbError::Postgres(a))) => { 153 + Err(LuminaError::DbError(crate::errors::LuminaDbError::Postgres( 154 + a, 155 + ))) => { 151 156 error_elog!(ev_log, "While connecting to postgres database: {}", a); 152 157 None 153 158 }
+42 -14
server/src/tests.rs
··· 16 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 17 */ 18 18 19 - use std::mem; 20 19 use crate::database::{self, DatabaseConnections}; 20 + use crate::errors::LuminaError; 21 21 use crate::timeline; 22 - use crate::errors::LuminaError; 22 + use std::mem; 23 23 24 24 #[tokio::test] 25 25 async fn test_database_setup() { 26 - let result = database::setup().await.expect("Database setup should succeed."); 27 - assert!(result.get_postgres_pool().get().await.is_ok(), "Should get Postgres connection"); 28 - assert!(result.get_redis_pool().get().await.is_ok(), "Should get Redis connection"); 26 + let result = database::setup() 27 + .await 28 + .expect("Database setup should succeed."); 29 + assert!( 30 + result.get_postgres_pool().get().await.is_ok(), 31 + "Should get Postgres connection" 32 + ); 33 + assert!( 34 + result.get_redis_pool().get().await.is_ok(), 35 + "Should get Redis connection" 36 + ); 29 37 } 30 38 31 39 #[tokio::test] ··· 93 101 assert!(result.is_none(), "Cache should be invalidated"); 94 102 } 95 103 96 - 97 104 #[test] 98 105 fn print_sizes() { 99 - println!("Size of LuminaError: {} bytes", mem::size_of::<LuminaError>()); 100 - println!("Size of errors::LuminaDbError: {} bytes", mem::size_of::<crate::errors::LuminaDbError>()); 106 + println!( 107 + "Size of LuminaError: {} bytes", 108 + mem::size_of::<LuminaError>() 109 + ); 110 + println!( 111 + "Size of errors::LuminaDbError: {} bytes", 112 + mem::size_of::<crate::errors::LuminaDbError>() 113 + ); 101 114 println!("Size of EnvVar: {} bytes", mem::size_of::<crate::EnvVar>()); 102 - println!("Size of InnerAppState: {} bytes", mem::size_of::<crate::InnerAppState>()); 115 + println!( 116 + "Size of InnerAppState: {} bytes", 117 + mem::size_of::<crate::InnerAppState>() 118 + ); 103 119 } 104 120 105 121 #[test] 106 122 fn test_error_sizes() { 107 123 // We want to keep our error types small to minimize overhead when passing them around. 108 - assert!(mem::size_of::<LuminaError>() <= 16, "LuminaError should be 16 bytes or less"); 109 - assert!(mem::size_of::<crate::errors::LuminaDbError>() <= 16, "LuminaDbError should be 16 bytes or less"); 124 + assert!( 125 + mem::size_of::<LuminaError>() <= 16, 126 + "LuminaError should be 16 bytes or less" 127 + ); 128 + assert!( 129 + mem::size_of::<crate::errors::LuminaDbError>() <= 16, 130 + "LuminaDbError should be 16 bytes or less" 131 + ); 110 132 } 111 133 112 134 #[test] 113 135 fn test_appstate_size() { 114 136 // Appstate is moved around a lot, so we want to keep it small, which is pretty easy since it just holds a single Arc pointer to a InnerAppState. 115 - assert!(mem::size_of::<crate::AppState>() <= 8, "AppState should be 8 bytes or less"); 137 + assert!( 138 + mem::size_of::<crate::AppState>() <= 8, 139 + "AppState should be 8 bytes or less" 140 + ); 116 141 // This constraint should lower over time as we optimize InnerAppState 117 - assert!(mem::size_of::<crate::InnerAppState>() <= 88, "InnerAppState should be 88 bytes or less"); 118 - } 142 + assert!( 143 + mem::size_of::<crate::InnerAppState>() <= 88, 144 + "InnerAppState should be 88 bytes or less" 145 + ); 146 + }
+17 -48
server/src/timeline.rs
··· 92 92 }; 93 93 94 94 let cache_key = get_cache_key(timeline_id, page); 95 - let serialized = serde_json::to_string(&cached_page) 96 - ?; 95 + let serialized = serde_json::to_string(&cached_page)?; 97 96 98 97 let _: () = redis::cmd("SETEX") 99 98 .arg(cache_key) 100 99 .arg(CACHE_TTL) 101 100 .arg(serialized) 102 101 .query_async(&mut **redis_conn) 103 - .await 104 - ?; 102 + .await?; 105 103 106 104 // Also cache metadata 107 105 let meta_key = get_cache_meta_key(timeline_id); ··· 110 108 .arg(CACHE_TTL) 111 109 .arg(total_count) 112 110 .query_async(&mut **redis_conn) 113 - .await 114 - ?; 111 + .await?; 115 112 116 113 Ok(()) 117 114 } ··· 127 124 let cached_data: Option<String> = redis::cmd("GET") 128 125 .arg(cache_key) 129 126 .query_async(&mut **redis_conn) 130 - .await 131 - ?; 127 + .await?; 132 128 133 129 match cached_data { 134 130 Some(data) => { ··· 154 150 .arg("MATCH") 155 151 .arg(&pattern) 156 152 .query_async(&mut **redis_conn) 157 - .await 158 - ?; 153 + .await?; 159 154 160 155 cursor = result.0; 161 156 let keys = result.1; ··· 164 159 let _: () = redis::cmd("DEL") 165 160 .arg(&keys) 166 161 .query_async(&mut **redis_conn) 167 - .await 168 - ?; 162 + .await?; 169 163 } 170 164 171 165 if cursor == 0 { ··· 180 174 async fn fetch_timeline_total_count(db: &DbConn, timeline_id: &str) -> Result<usize, LuminaError> { 181 175 match db { 182 176 DbConn::PgsqlConnection(pg_pool, _redis_pool) => { 183 - let client = pg_pool 184 - .get() 185 - .await 186 - ?; 177 + let client = pg_pool.get().await?; 187 178 let timeline_uuid = Uuid::parse_str(timeline_id).map_err(|_| LuminaError::UUidError)?; 188 179 let row = client 189 180 .query_one( 190 181 "SELECT COUNT(*) FROM timelines WHERE tlid = $1", 191 182 &[&timeline_uuid], 192 183 ) 193 - .await 194 - ?; 184 + .await?; 195 185 196 186 let count: i64 = row.get(0); 197 187 Ok(count as usize) ··· 208 198 ) -> Result<Vec<String>, LuminaError> { 209 199 match db { 210 200 DbConn::PgsqlConnection(pg_pool, _redis_pool) => { 211 - let client = pg_pool 212 - .get() 213 - .await 214 - ?; 201 + let client = pg_pool.get().await?; 215 202 let timeline_uuid = Uuid::parse_str(timeline_id).map_err(|_| LuminaError::UUidError)?; 216 203 let rows = client 217 204 .query( ··· 243 230 244 231 // Get Redis connection 245 232 let mut redis_conn = match db { 246 - DbConn::PgsqlConnection(_, redis_pool) => redis_pool 247 - .get() 248 - .await 249 - ?, 233 + DbConn::PgsqlConnection(_, redis_pool) => redis_pool.get().await?, 250 234 }; 251 235 252 236 // Log the requested timeline id for tracking 253 237 let _: () = redis::cmd("INCR") 254 238 .arg(format!("timeline_lookup:{}", timeline_id)) 255 239 .query_async(&mut *redis_conn) 256 - .await 257 - ?; 240 + .await?; 258 241 259 242 // Check if this timeline should be cached 260 243 let should_cache = is_high_traffic_timeline(&mut redis_conn, timeline_id).await?; ··· 366 349 // Add to database 367 350 match db { 368 351 DbConn::PgsqlConnection(pg_pool, redis_pool) => { 369 - let client = pg_pool 370 - .get() 371 - .await 372 - ?; 352 + let client = pg_pool.get().await?; 373 353 let timeline_uuid = Uuid::parse_str(timeline_id).map_err(|_| LuminaError::UUidError)?; 374 354 let item_uuid = Uuid::parse_str(item_id).map_err(|_| LuminaError::UUidError)?; 375 355 client ··· 377 357 "INSERT INTO timelines (tlid, item_id, timestamp) VALUES ($1, $2, NOW())", 378 358 &[&timeline_uuid, &item_uuid], 379 359 ) 380 - .await 381 - ?; 360 + .await?; 382 361 383 362 // Invalidate cache 384 - let mut redis_conn = redis_pool 385 - .get() 386 - .await 387 - ?; 363 + let mut redis_conn = redis_pool.get().await?; 388 364 if let Err(e) = invalidate_timeline_cache(&mut redis_conn, timeline_id).await { 389 365 error_elog!( 390 366 event_logger, ··· 410 386 // Remove from database 411 387 match db { 412 388 DbConn::PgsqlConnection(pg_pool, redis_pool) => { 413 - let client = pg_pool 414 - .get() 415 - .await 416 - ?; 389 + let client = pg_pool.get().await?; 417 390 let timeline_uuid = Uuid::parse_str(timeline_id).map_err(|_| LuminaError::UUidError)?; 418 391 let item_uuid = Uuid::parse_str(item_id).map_err(|_| LuminaError::UUidError)?; 419 392 client ··· 421 394 "DELETE FROM timelines WHERE tlid = $1 AND item_id = $2", 422 395 &[&timeline_uuid, &item_uuid], 423 396 ) 424 - .await 425 - ?; 397 + .await?; 426 398 427 399 // Invalidate cache 428 - let mut redis_conn = redis_pool 429 - .get() 430 - .await 431 - ?; 400 + let mut redis_conn = redis_pool.get().await?; 432 401 if let Err(e) = invalidate_timeline_cache(&mut redis_conn, timeline_id).await { 433 402 error_elog!( 434 403 event_logger,
+49 -70
server/src/user.rs
··· 62 62 async fn get_hashed_password(self, database: &DbConn) -> Result<String, LuminaError> { 63 63 match database { 64 64 DbConn::PgsqlConnection(pg_pool, _) => { 65 - let client = pg_pool 66 - .get() 67 - .await 68 - ?; 65 + let client = pg_pool.get().await?; 69 66 let row = client 70 67 .query_one("SELECT password FROM users WHERE id = $1", &[&self.id]) 71 - .await 72 - ?; 68 + .await?; 73 69 let password: String = row.get(0); 74 70 Ok(password) 75 71 } ··· 87 83 bcrypt::hash(password, bcrypt::DEFAULT_COST).map_err(|_| LuminaError::BcryptError)?; 88 84 match db { 89 85 DbConn::PgsqlConnection(pg_pool, _) => { 90 - let client = pg_pool 91 - .get() 92 - .await 93 - ?; 86 + let client = pg_pool.get().await?; 94 87 // Some username and email validation should be done here 95 88 // Check if the email is already in use 96 89 let email_exists = client 97 90 .query("SELECT * FROM users WHERE email = $1", &[&email]) 98 - .await 99 - ?; 91 + .await?; 100 92 if !email_exists.is_empty() { 101 93 return Err(LuminaError::RegisterEmailInUse); 102 94 } 103 95 // Check if the username is already in use 104 96 let username_exists = client 105 97 .query("SELECT * FROM users WHERE username = $1", &[&username]) 106 - .await 107 - ?; 98 + .await?; 108 99 if !username_exists.is_empty() { 109 100 return Err(LuminaError::RegisterUsernameInUse); 110 101 } ··· 133 124 }; 134 125 match db { 135 126 DbConn::PgsqlConnection(pg_pool, _) => { 136 - let client = pg_pool 137 - .get() 138 - .await 139 - ?; 127 + let client = pg_pool.get().await?; 140 128 let user = client 141 129 .query_one( 142 130 &format!("SELECT id, email, username, COALESCE(foreign_instance_id, '') FROM users WHERE {} = $1", identifyer_type), ··· 163 151 let user_id = user.id; 164 152 match db { 165 153 DbConn::PgsqlConnection(pg_pool, _) => { 166 - let client = pg_pool 167 - .get() 168 - .await 169 - ?; 154 + let client = pg_pool.get().await?; 170 155 let session_key = Uuid::new_v4().to_string(); 171 156 let id = client 172 157 .query_one( 173 158 "INSERT INTO sessions (user_id, session_key) VALUES ($1, $2) RETURNING id", 174 159 &[&user_id, &session_key], 175 160 ) 176 - .await 177 - ?; 161 + .await?; 178 162 info_elog!( 179 163 ev_log, 180 164 "New session created by {}", ··· 197 181 ) -> Result<User, LuminaError> { 198 182 match db { 199 183 DbConn::PgsqlConnection(pg_pool, _) => { 200 - let client = pg_pool 201 - .get() 202 - .await 203 - ?; 184 + let client = pg_pool.get().await?; 204 185 let user = client 205 186 .query_one("SELECT users.id, users.email, users.username FROM users JOIN sessions ON users.id = sessions.user_id WHERE sessions.session_key = $1", &[&token]) 206 187 .await ··· 226 207 // Check if the email or username is already in use using fastbloom algorithm with Redis, and fallback to DB check if not found. If not in either, we can go on. 227 208 match db { 228 209 DbConn::PgsqlConnection(pg_pool, redis_pool) => { 229 - let client = pg_pool 230 - .get() 231 - .await 232 - ?; 233 - let mut redis_conn = redis_pool 234 - .get() 235 - .await 236 - ?; 210 + let client = pg_pool.get().await?; 211 + let mut redis_conn = redis_pool.get().await?; 237 212 // fastbloom_rs expects bytes, so we use the string as bytes 238 213 let email_key = String::from("bloom:email"); 239 214 let username_key = String::from("bloom:username"); ··· 247 222 // Fallback to DB check if in bloom filter 248 223 let email_db = client 249 224 .query("SELECT * FROM users WHERE email = $1", &[&email]) 250 - .await 251 - ?; 225 + .await?; 252 226 if !email_db.is_empty() { 253 227 return Err(LuminaError::RegisterEmailInUse); 254 228 } ··· 263 237 // Fallback to DB check if in bloom filter 264 238 let username_db = client 265 239 .query("SELECT * FROM users WHERE username = $1", &[&username]) 266 - .await 267 - ?; 240 + .await?; 268 241 if !username_db.is_empty() { 269 242 return Err(LuminaError::RegisterUsernameInUse); 270 243 } ··· 272 245 // Fallback to DB check if not in bloom filter 273 246 let email_db = client 274 247 .query("SELECT * FROM users WHERE email = $1", &[&email]) 275 - .await 276 - ?; 248 + .await?; 277 249 if !email_db.is_empty() { 278 250 // Update bloom filter after DB check 279 251 let _: () = redis::cmd("BF.ADD") ··· 286 258 } 287 259 let username_db = client 288 260 .query("SELECT * FROM users WHERE username = $1", &[&username]) 289 - .await 290 - ?; 261 + .await?; 291 262 if !username_db.is_empty() { 292 263 let _: () = redis::cmd("BF.ADD") 293 264 .arg(&username_key) ··· 381 352 } 382 353 if password.len() > 100 { 383 354 return Err(LuminaError::RegisterPasswordNotValid( 384 - OnRegisterPasswordNotValid::TooLong 355 + OnRegisterPasswordNotValid::TooLong, 385 356 )); 386 357 } 387 358 if !password.chars().any(char::is_uppercase) { 388 - return Err(LuminaError::RegisterPasswordNotValid( 389 - OnRegisterPasswordNotValid::MissingUppercase 359 + return Err(LuminaError::RegisterPasswordNotValid( 360 + OnRegisterPasswordNotValid::MissingUppercase, 390 361 )); 391 362 } 392 363 if !password.chars().any(char::is_lowercase) { 393 364 return Err(LuminaError::RegisterPasswordNotValid( 394 - OnRegisterPasswordNotValid::MissingLowercase 365 + OnRegisterPasswordNotValid::MissingLowercase, 395 366 )); 396 367 } 397 368 if !password.chars().any(char::is_numeric) { 398 - return Err(LuminaError::RegisterPasswordNotValid(OnRegisterPasswordNotValid::MissingNumber 369 + return Err(LuminaError::RegisterPasswordNotValid( 370 + OnRegisterPasswordNotValid::MissingNumber, 399 371 )); 400 372 } 401 373 } 402 374 Ok(()) 403 375 } 404 376 405 - 406 377 #[derive(Debug)] 407 378 pub(crate) enum OnRegisterUsernameInvalid { 408 379 TooLong, 409 380 TooShort, 410 - InvalidCharacters 381 + InvalidCharacters, 411 382 } 412 383 impl std::fmt::Display for OnRegisterUsernameInvalid { 413 384 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 414 - write!(f, "{}", match self { 415 - OnRegisterUsernameInvalid::TooLong => "Username too long", 416 - OnRegisterUsernameInvalid::TooShort => "Username too short", 417 - OnRegisterUsernameInvalid::InvalidCharacters => { 418 - "Username contains invalid characters" 385 + write!( 386 + f, 387 + "{}", 388 + match self { 389 + OnRegisterUsernameInvalid::TooLong => "Username too long", 390 + OnRegisterUsernameInvalid::TooShort => "Username too short", 391 + OnRegisterUsernameInvalid::InvalidCharacters => { 392 + "Username contains invalid characters" 393 + } 419 394 } 420 - }) 395 + ) 421 396 } 422 397 } 423 398 #[derive(Debug)] ··· 430 405 } 431 406 impl std::fmt::Display for OnRegisterPasswordNotValid { 432 407 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 433 - write!(f, "{}", match self { 434 - OnRegisterPasswordNotValid::TooShort => "Password too short", 435 - OnRegisterPasswordNotValid::TooLong => "Password too long", 436 - OnRegisterPasswordNotValid::MissingUppercase => { 437 - "Password must contain at least one uppercase letter" 438 - } 439 - OnRegisterPasswordNotValid::MissingLowercase => { 440 - "Password must contain at least one lowercase letter" 408 + write!( 409 + f, 410 + "{}", 411 + match self { 412 + OnRegisterPasswordNotValid::TooShort => "Password too short", 413 + OnRegisterPasswordNotValid::TooLong => "Password too long", 414 + OnRegisterPasswordNotValid::MissingUppercase => { 415 + "Password must contain at least one uppercase letter" 416 + } 417 + OnRegisterPasswordNotValid::MissingLowercase => { 418 + "Password must contain at least one lowercase letter" 419 + } 420 + OnRegisterPasswordNotValid::MissingNumber => { 421 + "Password must contain at least one number" 422 + } 441 423 } 442 - OnRegisterPasswordNotValid::MissingNumber => { 443 - "Password must contain at least one number" 444 - } 445 - }) 424 + ) 446 425 } 447 - } 426 + }