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