use actix_web::{HttpServer, web, App, middleware}; use actix_cors::Cors; use http_error::HttpError; use sqlx::PgPool; use std::{env, sync::OnceLock}; mod http_error; mod routes; mod controllers; mod models; mod logic; mod auth; static JWT_SECRET: OnceLock = OnceLock::new(); static STRIPE_KEY: OnceLock = OnceLock::new(); static TOKEN_PACK_PRICE: OnceLock = OnceLock::new(); static TOKENS_PER_PACK: OnceLock = OnceLock::new(); static STRIPE_WEBHOOK_SECRET: OnceLock = OnceLock::new(); #[actix_web::main] async fn main() -> std::io::Result<()> { //Environment variables dotenvy::from_filename(".env").expect("Failed to load .env file"); let port: u16 = env_var("PORT"); let app_env: String = env_var("APP_ENV"); let database_url: String = env_var("DATABASE_URL"); JWT_SECRET.set(env_var("JWT_SECRET")).expect("Failed to set JWT"); STRIPE_KEY.set(env_var("STRIPE_KEY")).expect("Failed to set Stripe key"); TOKEN_PACK_PRICE.set(env_var("TOKEN_PACK_PRICE")).expect("Failed to set token pack price"); TOKENS_PER_PACK.set(env_var("TOKENS_PER_PACK")).expect("Failed to set tokens per pack"); STRIPE_WEBHOOK_SECRET.set(env_var("STRIPE_WEBHOOK_SECRET")).expect("Failed to set stripe webhook secret"); //Database let pool = PgPool::connect(&database_url) .await .expect("Failed to start Postgres"); //Server HttpServer::new(move || { let cors = if app_env == "development" { Cors::default() .allowed_origin("http://localhost:5173") .allowed_methods(vec!["GET", "POST", "PUT", "PATCH", "DELETE"]) .allow_any_header() .supports_credentials() } else { Cors::default() .allowed_origin_fn(|origin, _req| { origin.as_bytes().ends_with(b".chatrpg.com") }) .allowed_methods(vec!["GET", "POST", "PUT", "PATCH", "DELETE"]) .allow_any_header() .supports_credentials() }; App::new() .wrap(middleware::Compress::default()) .wrap(cors) .app_data( web::JsonConfig::default().error_handler(|err, _req| { HttpError::JsonDeserializationError(err.to_string()).into() }) ) .app_data(web::Data::new(pool.clone())) .configure(routes::user::config) .configure(routes::webhook::config) .configure(routes::game::game::config) .configure(routes::game::character::config) .configure(routes::game::session::config) }) .bind(("0.0.0.0", port)) .expect("Failed to bind to port") .run() .await .expect("Failed to start server"); Ok(()) } fn env_var(key: &str) -> T where T::Err: std::fmt::Debug, { env::var(key) .unwrap_or_else(|_| panic!("Environment variable {} not set", key)) .parse() .unwrap_or_else(|_| panic!("{} could not be parsed", key)) }