| 1 | use std::path::PathBuf; |
| 2 | |
| 3 | use malice::{ |
| 4 | routes::router, |
| 5 | state::{AppState, ensure_dirs, load_or_create_master_key}, |
| 6 | }; |
| 7 | use malice_static::{bind_listener, serve}; |
| 8 | |
| 9 | fn env_flag(name: &str, default: bool) -> bool { |
| 10 | match std::env::var(name) { |
| 11 | Ok(value) => { |
| 12 | let value = value.trim().to_ascii_lowercase(); |
| 13 | match value.as_str() { |
| 14 | "1" | "true" | "yes" | "on" => true, |
| 15 | "0" | "false" | "no" | "off" => false, |
| 16 | _ => default, |
| 17 | } |
| 18 | } |
| 19 | Err(_) => default, |
| 20 | } |
| 21 | } |
| 22 | |
| 23 | fn data_dir() -> PathBuf { |
| 24 | std::env::var("MALICE_DATA_DIR") |
| 25 | .map(PathBuf::from) |
| 26 | .unwrap_or_else(|_| PathBuf::from("local-data")) |
| 27 | } |
| 28 | |
| 29 | fn web_dir() -> Option<String> { |
| 30 | if let Ok(dir) = std::env::var("MALICE_WEB_DIR") { |
| 31 | assert!( |
| 32 | std::path::Path::new(&dir).join("index.html").is_file(), |
| 33 | "MALICE_WEB_DIR must point to built frontend assets containing index.html" |
| 34 | ); |
| 35 | return Some(dir); |
| 36 | } |
| 37 | |
| 38 | let local = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("web/dist"); |
| 39 | local |
| 40 | .join("index.html") |
| 41 | .is_file() |
| 42 | .then(|| local.to_string_lossy().into_owned()) |
| 43 | } |
| 44 | |
| 45 | #[tokio::main] |
| 46 | async fn main() { |
| 47 | tracing_subscriber::fmt() |
| 48 | .with_env_filter( |
| 49 | tracing_subscriber::EnvFilter::try_from_default_env() |
| 50 | .unwrap_or_else(|_| "malice=info,tower_http=info".into()), |
| 51 | ) |
| 52 | .with_target(false) |
| 53 | .compact() |
| 54 | .init(); |
| 55 | |
| 56 | let data_dir = data_dir(); |
| 57 | ensure_dirs(&data_dir); |
| 58 | let master_key = |
| 59 | load_or_create_master_key(&data_dir).expect("loading the master key must succeed"); |
| 60 | let cookie_secure = env_flag("MALICE_SESSION_COOKIE_SECURE", true); |
| 61 | let allow_http_homeserver = env_flag("MALICE_ALLOW_HTTP_HOMESERVER", false); |
| 62 | let state = AppState::new(data_dir, master_key, cookie_secure, allow_http_homeserver); |
| 63 | let app = router(state.clone(), web_dir()); |
| 64 | let listener = bind_listener().await; |
| 65 | serve( |
| 66 | listener, |
| 67 | app, |
| 68 | async move { state.shutdown_gracefully().await }, |
| 69 | ) |
| 70 | .await; |
| 71 | } |