foxtive_ntex/http/server/
mod.rs1mod config;
2
3#[cfg(feature = "static")]
4pub use config::StaticFileConfig;
5pub use config::{JsonConfig, ServerConfig};
6
7use crate::FoxtiveNtexState;
8use crate::http::kernel::{ntex_default_service, register_routes, setup_cors, setup_logger};
9use crate::setup::{FoxtiveNtexSetup, make_ntex_state};
10use foxtive::Error;
11use foxtive::prelude::AppResult;
12use foxtive::setup::load_environment_variables;
13use foxtive::setup::trace::Tracing;
14use ntex::io::IoConfig;
15use ntex::{SharedCfg, web};
16use std::future::Future;
17use tracing::{debug, error};
18
19pub fn init_bootstrap(service: &str, config: Tracing) -> AppResult<()> {
20 foxtive::setup::trace::init_tracing(config)?;
21 load_environment_variables(service);
22 Ok(())
23}
24
25pub async fn start_ntex_server<Callback, Fut>(
26 config: ServerConfig,
27 callback: Callback,
28) -> AppResult<()>
29where
30 Callback: FnOnce(FoxtiveNtexState) -> Fut + Copy + Send + 'static,
31 Fut: Future<Output = AppResult<()>> + Send + 'static,
32{
33 if !config.has_started_bootstrap {
34 let t_config = config.tracing.unwrap_or_default();
35 debug!("Starting bootstrap");
36 init_bootstrap(&config.app, t_config).expect("failed to init bootstrap: ");
37 }
38
39 debug!("Creating Foxtive-Ntex state");
40 let json_config = config.json_config.unwrap_or_default();
41 let app_state = make_ntex_state(FoxtiveNtexSetup {
42 allowed_origins: config.allowed_origins,
43 allowed_methods: config.allowed_methods,
44 foxtive_setup: config.foxtive_setup,
45 json_config: json_config.clone(),
46 })
47 .await?;
48
49 debug!("Executing app bootstrap callback");
50 match callback(app_state.clone()).await {
51 Ok(_) => {}
52 Err(err) => {
53 error!("app bootstrap callback returned error: {err:?}");
54 panic!("boostrap failed");
55 }
56 }
57
58 let boot = config.boot_thread;
59 let ntex_json_config = web::types::JsonConfig::default().limit(json_config.limit);
60
61 let shared_config = SharedCfg::new("WEB").add(
62 IoConfig::new()
63 .set_keepalive_timeout(config.keep_alive)
64 .set_connect_timeout(config.client_timeout)
65 .set_disconnect_timeout(config.client_disconnect),
66 );
67
68 let server = web::HttpServer::new(async move || {
69 let routes = boot();
70
71 let app = web::App::new()
72 .state(ntex_json_config.clone())
73 .state(app_state.clone())
74 .configure(|cfg| register_routes(cfg, routes))
75 .middleware(setup_logger())
76 .middleware(
77 setup_cors(
78 app_state.allowed_origins.clone(),
79 app_state.allowed_methods.clone(),
80 )
81 .finish(),
82 )
83 .default_service(ntex_default_service());
84
85 if cfg!(feature = "static") {
86 #[cfg(feature = "static")]
87 {
88 return app.service(ntex_files::Files::new(
89 &config.static_config.path,
90 &config.static_config.dir,
91 ));
92 }
93 }
94
95 app
96 })
97 .config(shared_config)
98 .backlog(config.backlog)
99 .workers(config.workers)
100 .maxconn(config.max_connections)
101 .maxconnrate(config.max_connections_rate)
102 .bind((config.host, config.port))?
104 .run();
105
106 let srv = server.clone();
108
109 let shutdown_signal = config
111 .shutdown_signal
112 .unwrap_or_else(default_shutdown_signal);
113
114 ntex::rt::spawn(async move {
116 shutdown_signal.await;
117
118 debug!("Shutdown signal received");
119
120 srv.stop(true).await;
122 });
123
124 server.await.map_err(Error::from)?;
126
127 if let Some(on_shutdown) = config.on_shutdown {
129 debug!("Running shutdown handler");
130 on_shutdown.await;
131 }
132
133 Ok(())
134}
135
136use std::pin::Pin;
137
138pub fn default_shutdown_signal() -> Pin<Box<dyn Future<Output = ()> + Send>> {
139 Box::pin(async {
140 let ctrl_c = async {
141 tokio::signal::ctrl_c()
142 .await
143 .expect("failed to listen for ctrl_c");
144 };
145
146 #[cfg(unix)]
147 let terminate = async {
148 use tokio::signal::unix::{signal, SignalKind};
149 let mut sigterm =
150 signal(SignalKind::terminate()).expect("failed to listen for SIGTERM");
151 sigterm.recv().await;
152 };
153
154 #[cfg(not(unix))]
155 let terminate = std::future::pending::<()>();
156
157 tokio::select! {
158 _ = ctrl_c => {},
159 _ = terminate => {},
160 }
161 })
162}