]> Untitled Git - lemmy.git/blob - server/src/main.rs
8445a68ba15ec46cfb03724012c87918c07f7419
[lemmy.git] / server / src / main.rs
1 #[macro_use]
2 extern crate diesel_migrations;
3
4 use actix::prelude::*;
5 use actix_web::{
6   body::Body,
7   dev::{Service, ServiceRequest, ServiceResponse},
8   http::{
9     header::{CACHE_CONTROL, CONTENT_TYPE},
10     HeaderValue,
11   },
12   *,
13 };
14 use diesel::{
15   r2d2::{ConnectionManager, Pool},
16   PgConnection,
17 };
18 use lazy_static::lazy_static;
19 use lemmy_api_structs::blocking;
20 use lemmy_db::get_database_url_from_env;
21 use lemmy_rate_limit::{rate_limiter::RateLimiter, RateLimit};
22 use lemmy_server::{
23   apub::activity_queue::create_activity_queue,
24   code_migrations::run_advanced_migrations,
25   routes::*,
26   websocket::chat_server::ChatServer,
27   LemmyContext,
28 };
29 use lemmy_utils::{settings::Settings, LemmyError, CACHE_CONTROL_REGEX};
30 use reqwest::Client;
31 use std::sync::Arc;
32 use tokio::sync::Mutex;
33
34 lazy_static! {
35   // static ref CACHE_CONTROL_VALUE: String = format!("public, max-age={}", 365 * 24 * 60 * 60);
36   // Test out 1 hour here, this is breaking some things
37   static ref CACHE_CONTROL_VALUE: String = format!("public, max-age={}", 60 * 60);
38 }
39
40 embed_migrations!();
41
42 #[actix_web::main]
43 async fn main() -> Result<(), LemmyError> {
44   env_logger::init();
45   let settings = Settings::get();
46
47   // Set up the r2d2 connection pool
48   let db_url = match get_database_url_from_env() {
49     Ok(url) => url,
50     Err(_) => settings.get_database_url(),
51   };
52   let manager = ConnectionManager::<PgConnection>::new(&db_url);
53   let pool = Pool::builder()
54     .max_size(settings.database.pool_size)
55     .build(manager)
56     .unwrap_or_else(|_| panic!("Error connecting to {}", db_url));
57
58   // Run the migrations from code
59   blocking(&pool, move |conn| {
60     embedded_migrations::run(conn)?;
61     run_advanced_migrations(conn)?;
62     Ok(()) as Result<(), LemmyError>
63   })
64   .await??;
65
66   // Set up the rate limiter
67   let rate_limiter = RateLimit {
68     rate_limiter: Arc::new(Mutex::new(RateLimiter::default())),
69   };
70
71   println!(
72     "Starting http server at {}:{}",
73     settings.bind, settings.port
74   );
75
76   let activity_queue = create_activity_queue();
77   let chat_server = ChatServer::startup(
78     pool.clone(),
79     rate_limiter.clone(),
80     Client::default(),
81     activity_queue.clone(),
82   )
83   .start();
84
85   // Create Http server with websocket support
86   HttpServer::new(move || {
87     let context = LemmyContext::create(
88       pool.clone(),
89       chat_server.to_owned(),
90       Client::default(),
91       activity_queue.to_owned(),
92     );
93     let settings = Settings::get();
94     let rate_limiter = rate_limiter.clone();
95     App::new()
96       .wrap_fn(add_cache_headers)
97       .wrap(middleware::Logger::default())
98       .data(context)
99       // The routes
100       .configure(|cfg| api::config(cfg, &rate_limiter))
101       .configure(federation::config)
102       .configure(feeds::config)
103       .configure(|cfg| images::config(cfg, &rate_limiter))
104       .configure(index::config)
105       .configure(nodeinfo::config)
106       .configure(webfinger::config)
107       // static files
108       .service(actix_files::Files::new(
109         "/static",
110         settings.front_end_dir.to_owned(),
111       ))
112       .service(actix_files::Files::new(
113         "/docs",
114         settings.front_end_dir + "/documentation",
115       ))
116   })
117   .bind((settings.bind, settings.port))?
118   .run()
119   .await?;
120
121   Ok(())
122 }
123
124 fn add_cache_headers<S>(
125   req: ServiceRequest,
126   srv: &mut S,
127 ) -> impl Future<Output = Result<ServiceResponse, Error>>
128 where
129   S: Service<Request = ServiceRequest, Response = ServiceResponse<Body>, Error = Error>,
130 {
131   let fut = srv.call(req);
132   async move {
133     let mut res = fut.await?;
134     if let Some(content_type) = res.headers().get(CONTENT_TYPE) {
135       if CACHE_CONTROL_REGEX.is_match(content_type.to_str().unwrap()) {
136         let header_val = HeaderValue::from_static(&CACHE_CONTROL_VALUE);
137         res.headers_mut().insert(CACHE_CONTROL, header_val);
138       }
139     }
140     Ok(res)
141   }
142 }