diff options
author | Sven-Hendrik Haase <svenstaro@gmail.com> | 2025-03-07 10:00:48 +0000 |
---|---|---|
committer | Sven-Hendrik Haase <svenstaro@gmail.com> | 2025-03-07 11:14:03 +0000 |
commit | 11ea8a19d1481b0660e5a2765da6e67d3e8aa72c (patch) | |
tree | 341cb7ac4bd5915deb8fe58947b3cc352687556d /src/main.rs | |
parent | Reformat style.scss (diff) | |
download | miniserve-11ea8a19d1481b0660e5a2765da6e67d3e8aa72c.tar.gz miniserve-11ea8a19d1481b0660e5a2765da6e67d3e8aa72c.zip |
Add asynchronous directory size counting
This is enabled by default and without an option to toggle it off as it's asynchronous and shouldn't
block the server thread.
Diffstat (limited to '')
-rw-r--r-- | src/main.rs | 45 |
1 files changed, 42 insertions, 3 deletions
diff --git a/src/main.rs b/src/main.rs index 856d22d..adda3f7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,7 @@ use actix_web::{ }; use actix_web_httpauth::middleware::HttpAuthentication; use anyhow::Result; +use bytesize::ByteSize; use clap::{CommandFactory, Parser, crate_version}; use colored::*; use dav_server::{ @@ -21,7 +22,8 @@ use dav_server::{ actix::{DavRequest, DavResponse}, }; use fast_qr::QRBuilder; -use log::{error, warn}; +use log::{error, info, warn}; +use serde::Deserialize; mod archive; mod args; @@ -38,6 +40,7 @@ mod webdav_fs; use crate::config::MiniserveConfig; use crate::errors::{RuntimeError, StartupError}; +use crate::file_op::recursive_dir_size; use crate::webdav_fs::RestrictedFs; static STYLESHEET: &str = grass::include!("data/style.scss"); @@ -215,7 +218,7 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), StartupError> { let srv = actix_web::HttpServer::new(move || { App::new() .wrap(configure_header(&inside_config.clone())) - .app_data(inside_config.clone()) + .app_data(web::Data::new(inside_config.clone())) .app_data(stylesheet.clone()) .wrap(from_fn(errors::error_page_middleware)) .wrap(middleware::Logger::default()) @@ -224,6 +227,7 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), StartupError> { middleware::Compress::default(), )) .route(&inside_config.healthcheck_route, web::get().to(healthcheck)) + .route(&inside_config.api_route, web::post().to(api)) .route(&inside_config.favicon_route, web::get().to(favicon)) .route(&inside_config.css_route, web::get().to(css)) .service( @@ -353,7 +357,7 @@ fn configure_app(app: &mut web::ServiceConfig, conf: &MiniserveConfig) { files = files.default_handler(fn_service(|req: ServiceRequest| async { let (req, _) = req.into_parts(); let conf = req - .app_data::<MiniserveConfig>() + .app_data::<web::Data<MiniserveConfig>>() .expect("Could not get miniserve config"); let mut path_base = req.path()[1..].to_string(); if path_base.ends_with('/') { @@ -438,6 +442,41 @@ async fn healthcheck() -> impl Responder { HttpResponse::Ok().body("OK") } +#[derive(Deserialize, Debug)] +enum ApiCommand { + /// Request the size of a particular directory + DirSize(String), +} + +/// This "API" is pretty shitty but frankly miniserve doesn't really need a very fancy API. Or at +/// least I hope so. +async fn api( + command: web::Json<ApiCommand>, + config: web::Data<MiniserveConfig>, +) -> Result<impl Responder, RuntimeError> { + match command.into_inner() { + ApiCommand::DirSize(dir) => { + // Convert the relative dir to an absolute path on the system + let sanitized_path = + file_utils::sanitize_path(&dir, true).expect("Expected a path to directory"); + let full_path = config + .path + .canonicalize() + .expect("Couldn't canonicalize path") + .join(sanitized_path); + info!("Requested directory listing for {full_path:?}"); + + let dir_size = recursive_dir_size(&full_path).await?; + if config.show_exact_bytes { + Ok(format!("{dir_size} B")) + } else { + let dir_size = ByteSize::b(dir_size); + Ok(dir_size.to_string()) + } + } + } +} + async fn favicon() -> impl Responder { let logo = include_str!("../data/logo.svg"); HttpResponse::Ok() |