mod api; mod assets; mod auth; mod cli; mod db; mod error; mod fs; use std::net::{IpAddr, SocketAddr}; use std::sync::Arc; use anyhow::{bail, Context}; use clap::Parser; use tower_http::trace::TraceLayer; use crate::cli::Cli; use crate::db::Db; use crate::error::AppState; #[tokio::main] async fn main() -> anyhow::Result<()> { tracing_subscriber::fmt() .with_env_filter( tracing_subscriber::EnvFilter::try_from_default_env() .unwrap_or_else(|_| "info,tower_http=warn".into()), ) .init(); let cli = Cli::parse(); let root = cli .root .canonicalize() .with_context(|| format!("cannot resolve root folder: {}", cli.root.display()))?; if !root.is_dir() { bail!("root folder is not a directory: {}", root.display()); } let db = Db::open(&cli.db).await?; let state = Arc::new(AppState { db, root: root.clone(), https: cli.https, }); let app = api::router(state).layer(TraceLayer::new_for_http()); let ip: IpAddr = cli.bind.parse().context("invalid --bind address")?; let addr = SocketAddr::new(ip, cli.port); let listener = tokio::net::TcpListener::bind(addr) .await .with_context(|| format!("cannot bind to {addr}"))?; tracing::info!(root = %root.display(), "filebrowser-ng starting"); tracing::info!(addr = %addr, "listening (pass --bind 0.0.0.0 to expose beyond localhost)"); axum::serve(listener, app).await?; Ok(()) }