atomic_server_lib/
serve.rs1use actix_cors::Cors;
2use actix_web::{middleware, web, HttpServer};
3
4use crate::errors::AtomicServerResult;
5
6fn rebuild_indexes(appstate: &crate::appstate::AppState) -> AtomicServerResult<()> {
8 let appstate_clone = appstate.clone();
9
10 actix_web::rt::spawn(async move {
11 appstate_clone
12 .store
13 .clear_index()
14 .expect("Failed to clear value index");
15 appstate_clone
16 .store
17 .build_index(true)
18 .expect("Failed to build value index");
19 });
20
21 tracing::info!("Removing existing search index...");
22 appstate
23 .search_state
24 .writer
25 .write()
26 .expect("Could not get a lock on search writer")
27 .delete_all_documents()?;
28 appstate.search_state.add_all_resources(&appstate.store)?;
29 Ok(())
30}
31
32const PAYLOAD_MAX: usize = 50_242_880;
34
35pub async fn serve(config: crate::config::Config) -> AtomicServerResult<()> {
37 println!("Atomic-server {} \nUse --help for instructions. Visit https://docs.atomicdata.dev and https://github.com/atomicdata-dev/atomic-server for more info.", env!("CARGO_PKG_VERSION"));
38 let tracing_chrome_flush_guard = crate::trace::init_tracing(&config);
39
40 let appstate = crate::appstate::AppState::init(config.clone())?;
42
43 if config.opts.rebuild_indexes {
45 rebuild_indexes(&appstate)?;
46 }
47
48 let server = HttpServer::new(move || {
49 let cors = Cors::permissive();
50
51 actix_web::App::new()
52 .app_data(web::PayloadConfig::new(PAYLOAD_MAX))
53 .app_data(web::Data::new(appstate.clone()))
54 .wrap(cors)
55 .wrap(tracing_actix_web::TracingLogger::default())
56 .wrap(middleware::Compress::default())
57 .configure(crate::routes::config_routes)
59 .default_service(web::to(|| {
60 tracing::error!("Wrong route, should not happen with normal requests");
61 actix_web::HttpResponse::NotFound()
62 }))
63 .app_data(
64 web::JsonConfig::default()
65 .error_handler(crate::jsonerrors::json_error_handler),
67 )
68 });
69
70 let message = format!("{}\n\nVisit {}\n\n", BANNER, config.server_url);
71
72 if config.opts.https {
73 if cfg!(feature = "https") {
74 #[cfg(feature = "https")]
75 {
76 {
78 if crate::https::should_renew_certs_check(&config)? {
79 crate::https::request_cert(&config).await?;
80 }
81 }
82 let https_config = crate::https::get_https_config(&config)
83 .expect("HTTPS TLS Configuration with Let's Encrypt failed.");
84 let endpoint = format!("{}:{}", config.opts.ip, config.opts.port_https);
85 tracing::info!("Binding HTTPS server to endpoint {}", endpoint);
86 println!("{}", message);
87 server
88 .bind_rustls(&endpoint, https_config)
89 .map_err(|e| format!("Cannot bind to endpoint {}: {}", &endpoint, e))?
90 .shutdown_timeout(TIMEOUT)
91 .run()
92 .await?;
93 }
94 } else {
95 return Err("The HTTPS feature has been disabled for this build. Please compile atomic-server with the HTTP feature. `cargo install atomic-server`".into());
96 }
97 } else {
98 let endpoint = format!("{}:{}", config.opts.ip, config.opts.port);
99 tracing::info!("Binding HTTP server to endpoint {}", endpoint);
100 println!("{}", message);
101 server
102 .bind(&format!("{}:{}", config.opts.ip, config.opts.port))
103 .map_err(|e| format!("Cannot bind to endpoint {}: {}", &endpoint, e))?
104 .shutdown_timeout(TIMEOUT)
105 .run()
106 .await?;
107 }
108
109 tracing::info!("Cleaning up");
110 if let Some(guard) = tracing_chrome_flush_guard {
113 guard.flush()
114 }
115
116 tracing::info!("Server stopped");
117 Ok(())
118}
119
120const TIMEOUT: u64 = 15;
122
123const BANNER: &str = r#"
124 __ _
125 ____ _/ /_____ ____ ___ (_)____ ________ ______ _____ _____
126 / __ `/ __/ __ \/ __ `__ \/ / ___/_____/ ___/ _ \/ ___/ | / / _ \/ ___/
127/ /_/ / /_/ /_/ / / / / / / / /__/_____(__ ) __/ / | |/ / __/ /
128\__,_/\__/\____/_/ /_/ /_/_/\___/ /____/\___/_/ |___/\___/_/
129"#;