headless_lms_server/programs/
start_server.rs1use crate::{
2 config::{self, ServerConfigBuilder, ServerRuntimeConfig, set_server_runtime_config},
3 setup_tracing,
4};
5use actix_session::{
6 SessionMiddleware,
7 config::{CookieContentSecurity, PersistentSession, SessionLifecycle, TtlExtensionPolicy},
8 storage::CookieSessionStore,
9};
10use actix_web::{
11 App, HttpServer,
12 cookie::{Key, SameSite},
13 middleware::Logger,
14};
15use dotenvy::dotenv;
16use listenfd::ListenFd;
17use rustls::crypto::ring;
18use secrecy::ExposeSecret;
19
20pub async fn main() -> anyhow::Result<()> {
22 dotenv().ok();
23 setup_tracing()?;
24
25 ring::default_provider()
27 .install_default()
28 .expect("failed to install rustls ring crypto provider");
29
30 let runtime_config = ServerRuntimeConfig::try_from_env()?;
31 let private_cookie_key = runtime_config.private_cookie_key.clone();
32 let test_mode = runtime_config.test_mode;
33 let allow_no_https_for_development = runtime_config.allow_no_https_for_development;
34 let host = runtime_config.host.clone();
35 let port = runtime_config.port.clone();
36 set_server_runtime_config(runtime_config.clone())?;
37
38 if test_mode {
39 info!("***********************************");
40 info!("* Starting backend in test mode *");
41 info!("***********************************");
42 }
43 let server_config = ServerConfigBuilder::from_runtime_config(&runtime_config)
44 .await
45 .expect("Failed to create server config builder from runtime config")
46 .build()
47 .await
48 .expect("Failed to create server config");
49 let mut server = HttpServer::new(move || {
50 let server_config = server_config.clone();
51 App::new()
52 .configure(move |config| config::configure(config, server_config))
53 .wrap(
54 SessionMiddleware::builder(
55 CookieSessionStore::default(),
56 Key::from(private_cookie_key.expose_secret().as_bytes()),
57 )
58 .cookie_name("session".to_string())
59 .cookie_secure(!allow_no_https_for_development)
60 .cookie_same_site(SameSite::Strict) .cookie_http_only(true) .cookie_path("/api".to_string()) .cookie_content_security(CookieContentSecurity::Private)
64 .session_lifecycle(SessionLifecycle::PersistentSession(
65 PersistentSession::default()
66 .session_ttl(actix_web::cookie::time::Duration::days(100))
67 .session_ttl_extension_policy(TtlExtensionPolicy::OnEveryRequest),
68 ))
69 .build(),
70 )
71 .wrap(Logger::new(
72 "Completed %r %s %b bytes - %D ms, request_id=%{request-id}o",
73 ))
74 });
75
76 let mut listenfd = ListenFd::from_env();
78 server = match listenfd.take_tcp_listener(0)? {
79 Some(listener) => server.listen(listener)?,
80 None => {
81 let bind_address = format!("{}:{}", host, port);
82 info!("Binding to address: {}", bind_address);
83 server.bind(bind_address)?
84 }
85 };
86
87 info!("Starting server.");
88 server.run().await?;
89
90 Ok(())
91}