~starkingdoms/starkingdoms

ref: 3f9784408f5c43e366106d0f547d80d9b33ffa37 starkingdoms/starkingdoms-api/src/main.rs -rw-r--r-- 3.4 KiB
3f978440 — ghostlyzsh attaching and despawning modules works 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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<Sha256>,
    pub config: Config,
    pub db: Client,
}

#[actix_web::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    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 <config_path>");
            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(())
}