medullah_web/http/
server.rs

1use std::future::Future;
2
3use log::error;
4use ntex::web;
5
6use crate::app_setup::{
7    get_server_host_config, load_environment_variables, make_app_state, MedullahSetup,
8};
9use crate::env_logger::init_env_logger;
10use crate::http::kernel::{ntex_default_service, register_routes, setup_cors, setup_logger, Route};
11use crate::http::Method;
12use crate::prelude::{AppResult, MedullahState};
13
14pub struct ServerConfig<TB>
15where
16    TB: FnOnce() -> Vec<Route> + Send + Copy + 'static,
17{
18    pub app: String,
19    pub env_prefix: String,
20    pub private_key: String,
21    pub public_key: String,
22    pub auth_iss_public_key: String,
23
24    #[cfg(feature = "static")]
25    pub static_config: StaticFileConfig,
26
27    /// whether the app bootstrap has started
28    pub has_started_bootstrap: bool,
29
30    /// list of allowed CORS origins
31    pub allowed_origins: Vec<String>,
32
33    /// list of allowed CORS origins
34    pub allowed_methods: Vec<Method>,
35
36    pub boot_thread: TB,
37}
38
39#[cfg(feature = "static")]
40pub struct StaticFileConfig {
41    pub path: String,
42    pub dir: String,
43}
44
45pub fn init_bootstrap(service: &str) -> AppResult<()> {
46    load_environment_variables(service);
47    init_env_logger();
48    Ok(())
49}
50
51pub async fn start_ntex_server<Callback, Fut, TB>(
52    config: ServerConfig<TB>,
53    callback: Callback,
54) -> std::io::Result<()>
55where
56    Callback: FnOnce(MedullahState) -> Fut + Copy + Send + 'static,
57    Fut: Future<Output = AppResult<()>> + Send + 'static,
58    TB: FnOnce() -> Vec<Route> + Send + Copy + 'static,
59{
60    if !config.has_started_bootstrap {
61        init_bootstrap(&config.app).expect("failed to init bootstrap: ");
62    }
63
64    let app_state = make_app_state(MedullahSetup {
65        public_key: config.public_key,
66        private_key: config.private_key,
67        env_prefix: config.env_prefix.clone(),
68        auth_iss_public_key: config.auth_iss_public_key,
69        allowed_origins: config.allowed_origins,
70        allowed_methods: config.allowed_methods,
71    })
72    .await;
73
74    let (host, port, workers) = get_server_host_config(&config.env_prefix);
75
76    match callback(app_state.clone()).await {
77        Ok(_) => {}
78        Err(err) => {
79            error!("app bootstrap callback returned error: {:?}", err);
80            panic!("boostrap failed");
81        }
82    }
83
84    let boot = config.boot_thread;
85    web::HttpServer::new(move || {
86        let routes = boot();
87        let app = web::App::new()
88            .state(app_state.clone())
89            .configure(|cfg| register_routes(cfg, routes))
90            .wrap(setup_logger())
91            .wrap(
92                setup_cors(
93                    app_state.allowed_origins.clone(),
94                    app_state.allowed_methods.clone(),
95                )
96                .finish(),
97            )
98            .default_service(ntex_default_service());
99
100        if cfg!(feature = "static") {
101            #[cfg(feature = "static")]
102            {
103                return app.service(ntex_files::Files::new(
104                    &config.static_config.path,
105                    &config.static_config.dir,
106                ));
107            }
108        }
109
110        app
111    })
112    .bind((host, port))?
113    .workers(workers)
114    .run()
115    .await
116}