use std::collections::BTreeSet; use std::sync::Arc; use std::sync::Mutex; use log::error; use log::info; use sqlx::postgres::PgPoolOptions; use sqlx::PgPool; #[derive(Clone)] pub struct CaptchaState { // pub capthca_db: Arc>>, pub capthca_db: Arc>>, } impl CaptchaState { pub fn new() -> Self { Self { capthca_db: Arc::new(Mutex::new(BTreeSet::new())), } } } #[derive(Clone)] pub struct ServerState { pub pool: PgPool, } impl ServerState { pub async fn new() -> Self { // This is almost certainly bad practice for more reasons than I can count dotenvy::dotenv().ok(); let db_url = dotenvy::var("DATABASE_URL").unwrap_or_else(|_| { error!("DATABASE_URL not set in environment!"); std::process::exit(1); }); info!("Using db_url: {}", &db_url); let pool = PgPoolOptions::new() .max_connections(5) .connect(&db_url) .await .unwrap(); sqlx::migrate!("./migrations").run(&pool).await.unwrap(); match crate::db::db_new_user("imbus".to_string(), "kartellen1234".to_string(), &pool).await { Some(u) => info!("Created default user {}", u.username), None => error!("Failed to create default user..."), } match crate::db::db_new_user("demouser".to_string(), "demopw".to_string(), &pool).await { Some(u) => info!("Created default user {}", u.username), None => error!("Failed to create default user..."), } #[cfg(debug_assertions)] debug_setup(&pool).await.unwrap(); lipsum_setup(&pool).await.unwrap(); Self { pool } } } // Inserts a bunch of dummy data into the database // Mostly useful for debugging new posts, as we need to satisfy foreign key constraints. #[cfg(debug_assertions)] async fn debug_setup(pool: &PgPool) -> Result<(), sqlx::Error> { use lipsum::lipsum; use rand::prelude::*; use sqlx::query; use crate::db::db_new_user; db_new_user("user".to_string(), "pass".to_string(), pool).await; // Check if the demo post already exists let no_posts = query!("SELECT * FROM posts WHERE id = 1",) .fetch_one(pool) .await .ok() .is_none(); // If the demo user already has a post, don't insert another one if no_posts { let mut rng = rand::thread_rng(); // This requires that the user with id 1 exists in the user table for _ in 0..100 { query!( "INSERT INTO posts (user_id, content) VALUES (1, $1)", lipsum(rng.gen_range(10..100)) ) .execute(pool) .await?; } query!("INSERT INTO posts (user_id, content) VALUES (1, 'Hello world! The demo username is user and the password is pass.')",) .execute(pool) .await?; } Ok(()) } async fn lipsum_setup(pool: &PgPool) -> Result<(), sqlx::Error> { use lipsum::lipsum; use rand::prelude::*; use sqlx::query; let user_exist = query!("SELECT * FROM users",) .fetch_one(pool) .await .ok() .is_none(); if user_exist { let mut rng = rand::thread_rng(); // This requires that the user with id 1 exists in the user table for _ in 0..100 { query!( "INSERT INTO posts (user_id, content) VALUES (1, $1)", lipsum(rng.gen_range(10..100)) ) .execute(pool) .await?; } } Ok(()) }