use std::{ fmt::Display, sync::{Arc, Mutex}, }; use anyhow::Context as _; use axum::{Extension, Router, routing::get}; use tokio::net::TcpListener; use tower_http::compression::CompressionLayer; use crate::{cli::ServeArgs, library::Library}; pub mod api; pub mod assets; pub mod pages; #[derive(Debug, Clone, Copy, clap::ValueEnum)] pub enum TextureKind { /// <1.14 textures. Legacy, /// >=1.14 textures. Modern, } impl Display for TextureKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { TextureKind::Legacy => write!(f, "legacy"), TextureKind::Modern => write!(f, "modern"), } } } pub async fn start_webserver( args: &ServeArgs, library: Library, ) -> anyhow::Result<()> { let library = Arc::new(Mutex::new(library)); let app = Router::new() .route("/", get(pages::index)) .route("/book/{hash}", get(pages::book)) .route("/random", get(pages::random_book)) .nest("/api", api::router(library.clone())) .nest("/assets", assets::router()) .layer(CompressionLayer::new()) .layer(Extension(library)) .layer(Extension(args.ui_textures)); let address = args .webserver_host_address .parse::() .context("Converting addr arg to socketaddr")?; let listener = TcpListener::bind(address) .await .context("Binding listener")?; tracing::info!("Binding webserver to {0}.", address); axum::serve(listener, app) .await .context("Serving webserver")?; Ok(()) }