Parent [>]
1mod cli;
2mod error;
3mod filters;
4mod routes;
5mod theme;
6
7use std::sync::OnceLock;
8
9use clap::Parser;
10use tokio::net::TcpListener;
11
12use crate::error::Result;
13use crate::theme::{BASE_CSS, MARKDOWN_CSS};
14
15/// Package name, sourced from `Cargo.toml` at compile time.
16pub const PKG_NAME: &str = env!("CARGO_PKG_NAME");
17
18/// Package version, sourced from `Cargo.toml` at compile time.
19pub const PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
20
21/// Hostname used in breadcrumbs and clone URLs, set once from `--hostname`.
22static HOSTNAME: OnceLock<String> = OnceLock::new();
23
24/// SSH clone URL path prefix, set once from `--ssh-prefix`.
25static SSH_PREFIX: OnceLock<String> = OnceLock::new();
26
27/// Returns the configured hostname, or `"index"` if none was provided.
28pub fn hostname() -> &'static str {
29    HOSTNAME.get().map_or("index", |s| s.as_str())
30}
31
32/// Returns the configured SSH prefix, or an empty string if none was provided.
33pub fn ssh_prefix() -> &'static str {
34    SSH_PREFIX.get().map_or("", |s| s.as_str())
35}
36
37#[tokio::main]
38async fn main() -> Result<()> {
39    let args = cli::Args::parse();
40
41    if let Some(hostname) = args.hostname {
42        let _ = HOSTNAME.set(hostname);
43    }
44    if let Some(ssh_prefix) = args.ssh_prefix {
45        let _ = SSH_PREFIX.set(ssh_prefix);
46    }
47
48    // Concatenate base styles, markdown styles, and theme variables into a
49    // single stylesheet served at /style.css.
50    let theme_vars = match args.theme_file {
51        Some(path) => std::fs::read_to_string(path)?,
52        None => args.theme.css().to_owned(),
53    };
54    let css = format!("{theme_vars}\n{BASE_CSS}\n{MARKDOWN_CSS}");
55
56    let state = routes::AppState {
57        root: args.root,
58        css,
59    };
60
61    let router = routes::router(state);
62    let addr = format!("0.0.0.0:{}", args.port);
63    let socket = TcpListener::bind(&addr).await?;
64
65    axum::serve(socket, router).await?;
66
67    Ok(())
68}