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