use crate::config::Config; use crate::error::APIErrorResponse; use actix_web::middleware::Logger; use actix_web::web::{Data, JsonConfig}; use actix_web::{App, Error, HttpResponse, HttpServer}; use actix_web_prom::PrometheusMetricsBuilder; use hmac::digest::KeyInit; use hmac::Hmac; use log::{error, info}; use mongodb::options::{ClientOptions, ResolverConfig}; use mongodb::Client; use sha2::Sha256; use std::fs; use std::path::PathBuf; pub mod error; #[macro_use] pub mod macros; pub mod config; pub mod response; pub mod tokens; #[derive(Clone)] pub struct AppState { pub key: Hmac, pub config: Config, pub db: Client, } #[actix_web::main] async fn main() -> Result<(), Box> { better_panic::install(); simple_logger::init_with_env().unwrap(); // load config let mut args = std::env::args(); let config_path = match args.nth(1) { Some(path) => path, None => { eprintln!("usage: starkingdoms-api "); std::process::exit(1); } }; let config_pathbuf = PathBuf::from(config_path); info!( "StarKingdoms API v{} starting up", env!("CARGO_PKG_VERSION") ); info!("Loading config from {}", config_pathbuf.display()); let config_str = match fs::read_to_string(&config_pathbuf) { Ok(c_str) => c_str, Err(e) => { error!( "Error loading configuration from {}: {}", config_pathbuf.display(), e ); std::process::exit(1); } }; let config: Config = match toml::from_str(&config_str) { Ok(config) => config, Err(e) => { error!( "Error parsing configuration in {}: {}", config_pathbuf.display(), e ); std::process::exit(1); } }; info!("Creating JWT key"); let key = Hmac::new_from_slice(config.application_key.as_bytes()).unwrap(); // get db from env info!("Connecting to database at {}", config.mongodb_url); let options = ClientOptions::parse_with_resolver_config( &config.mongodb_url, ResolverConfig::cloudflare(), ) .await?; let client = Client::with_options(options)?; info!("Creating user email unique index"); let state = AppState { key, config: config.clone(), db: client, }; info!("Database connected, state loaded"); info!("Prometheus init"); let prom = PrometheusMetricsBuilder::new("starkingdoms_api") .endpoint("/metrics") .build() .expect("Prometheus setup failed"); let server = HttpServer::new(move || { App::new() .wrap(prom.clone()) .app_data(JsonConfig::default().error_handler(|err, _req| { Error::from({ let err2: APIErrorResponse = (&err).into(); actix_web::error::InternalError::from_response( err, HttpResponse::BadRequest().json(err2), ) }) })) .wrap(Logger::default()) .app_data(Data::new(state.clone())) .wrap(actix_cors::Cors::permissive()) }) .bind(("0.0.0.0", 8080))?; info!("HttpServer created, bound"); info!("HttpServer start"); server.run().await?; info!("Goodbye!"); Ok(()) }