feature: add cleanup

Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
2025-11-16 18:03:32 +05:30
parent fad5ee8a30
commit 63a0268695
7 changed files with 397 additions and 55 deletions

234
Cargo.lock generated
View File

@@ -2,6 +2,15 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "atomic-waker" name = "atomic-waker"
version = "1.1.2" version = "1.1.2"
@@ -9,10 +18,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]] [[package]]
name = "axum" name = "autocfg"
version = "0.8.6" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18ed336352031311f4e0b4dd2ff392d4fbb370777c9d18d7fc9d7359f73871" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "axum"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425"
dependencies = [ dependencies = [
"axum-core", "axum-core",
"bytes", "bytes",
@@ -68,10 +83,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]] [[package]]
name = "bytes" name = "bumpalo"
version = "1.10.1" version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "bytes"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
[[package]]
name = "cc"
version = "1.2.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36"
dependencies = [
"find-msvc-tools",
"shlex",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@@ -79,6 +110,25 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "chrono"
version = "0.4.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-link",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.35" version = "0.8.35"
@@ -88,6 +138,12 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "find-msvc-tools"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@@ -215,9 +271,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "1.7.0" version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
dependencies = [ dependencies = [
"atomic-waker", "atomic-waker",
"bytes", "bytes",
@@ -236,9 +292,9 @@ dependencies = [
[[package]] [[package]]
name = "hyper-util" name = "hyper-util"
version = "0.1.17" version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-core", "futures-core",
@@ -250,12 +306,46 @@ dependencies = [
"tower-service", "tower-service",
] ]
[[package]]
name = "iana-time-zone"
version = "0.1.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.15" version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "js-sys"
version = "0.3.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.177" version = "0.2.177"
@@ -333,6 +423,15 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.21.3" version = "1.21.3"
@@ -451,6 +550,12 @@ dependencies = [
"bitflags", "bitflags",
] ]
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.20" version = "1.0.20"
@@ -528,6 +633,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]] [[package]]
name = "signal-hook-registry" name = "signal-hook-registry"
version = "1.4.6" version = "1.4.6"
@@ -567,9 +678,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.109" version = "2.0.110"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -704,12 +815,110 @@ dependencies = [
"wit-bindgen", "wit-bindgen",
] ]
[[package]]
name = "wasm-bindgen"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
dependencies = [
"unicode-ident",
]
[[package]]
name = "windows-core"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-implement"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "windows-link" name = "windows-link"
version = "0.2.1" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-result"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
"windows-link",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.60.2" version = "0.60.2"
@@ -804,6 +1013,7 @@ name = "yamaf"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"axum", "axum",
"chrono",
"futures-util", "futures-util",
"mime_guess", "mime_guess",
"rand", "rand",

View File

@@ -7,8 +7,12 @@ edition = "2024"
[dependencies] [dependencies]
axum = { version = "0.8.6", features = ["multipart"] } axum = { version = "0.8.6", features = ["multipart"] }
chrono = "*"
futures-util = "0.3.31" futures-util = "0.3.31"
mime_guess= "*" mime_guess= "*"
rand = "*" rand = "*"
tokio = { version = "1.48.0", features = ["full"] } tokio = { version = "1.48.0", features = ["full"] }
tokio-util = { version = "0.7.17", features = ["io"] } tokio-util = { version = "0.7.17", features = ["io"] }
[features]
cleanup = []

View File

@@ -18,7 +18,19 @@
| EXTERNAL_HOST | User facing domain name, used to return accessible URLs | ${INTERNAL_HOST} | | EXTERNAL_HOST | User facing domain name, used to return accessible URLs | ${INTERNAL_HOST} |
| EXTERNAL_HAS_TLS | URLs in html have https if set, otherwise http | - | | EXTERNAL_HAS_TLS | URLs in html have https if set, otherwise http | - |
| MAX_FILES | This does not actually limit the number of files, and used to calculate bodysize | 10 | | MAX_FILES | This does not actually limit the number of files, and used to calculate bodysize | 10 |
| MAX_FILESIZE_MB | Determines the max filesize possible, used to return failure and calculate bodysize | 100M | | MAX_FILESIZE_MB | Determines the max filesize possible, used to return failure and calculate bodysize | 100M |
| MIN_FILEDAYS | Minimum number of days for file retention | 30 days |
| MAX_FILEDAYS | Maximum number of days for file retention | 365 days |
** Retention
File retention is as per the following formula
#+begin_src text
retention = min_days + (max_days - min_days) * (1 - file_size / max_size)) ^ e
#+end_src
Cleanup happens everyday when midnight (IST) has passed
[fn:1] https://git.weirdnatto.in/natto1784/simple-filehost/ [fn:1] https://git.weirdnatto.in/natto1784/simple-filehost/

View File

@@ -47,17 +47,14 @@
cargoArtifacts = craneLib.buildDepsOnly commonArgs; cargoArtifacts = craneLib.buildDepsOnly commonArgs;
yamaf = craneLib.buildPackage ( yamaf = pkgs.callPackage ./nix/yamaf.nix {
commonArgs inherit craneLib lib src;
// { };
inherit cargoArtifacts;
doCheck = false;
}
);
in in
{ {
packages = { packages = {
inherit yamaf; inherit yamaf;
yamaf-all = yamaf.override { withCleanup = true; };
default = yamaf; default = yamaf;
image = pkgs.dockerTools.buildImage { image = pkgs.dockerTools.buildImage {
name = "yamaf"; name = "yamaf";

15
nix/yamaf.nix Normal file
View File

@@ -0,0 +1,15 @@
{
craneLib,
lib,
src,
withCleanup ? false,
}:
let
cargoArtifacts = craneLib.buildDepsOnly { inherit src; };
in
craneLib.buildPackage {
inherit cargoArtifacts src;
doCheck = false;
cargoExtraArgs = lib.optionalString withCleanup "--features cleanup";
}

View File

@@ -1,31 +1,45 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>{{TITLE}}</title> <title>{{TITLE}}</title>
</head> </head>
<body> <body>
<h1>{{TITLE}}</h1> <h1>{{TITLE}}</h1>
<p>
Use curl to upload: <p>
<br> Use curl to upload:
<code> <br>
curl -F file=@"[file]" {{USER_URL}} <code>
</code> curl -F file=@"[file]" {{USER_URL}}
<br> </code>
<br> <br>
If key is enabled then a field "key" will be required. <br>
<br> If key is enabled then a field "key" will be required.
Make sure the key is the first field in the multipart before any files. <br>
<br> Make sure the key is the first field in the multipart before any files.
<code> <br>
curl -F "key=[key]" -F file=@"[file]" -F file=@"[file2]" {{USER_URL}} <code>
</code> curl -F "key=[key]" -F file=@"[file]" -F file=@"[file2]" {{USER_URL}}
</p> </code>
<form method="post" enctype="multipart/form-data"> </p>
{{KEY_FIELD}}
<input type="file" name="file" multiple> <form method="post" enctype="multipart/form-data">
<br> {{KEY_FIELD}}
<button type="submit">Upload</button> <input type="file" name="file" multiple>
</form> <br>
<div id="progress-container"></div> <button type="submit">Upload</button>
</form>
<!-- CLEANUP_START -->
<h4>Cleanup</h4>
File retention is as per the following formula
<pre><code>
max_size = {{MAX_SIZE}} // in megabytes
max_days = {{MAX_DAYS}}
min_days = {{MIN_DAYS}}
retention = min_days + (max_days - min_days) * (1 - file_size / max_size)) ^ e
</code></pre>
Cleanup happens everyday when midnight (IST) has passed
<!-- CLEANUP_END -->
</html> </html>

View File

@@ -6,11 +6,10 @@ use axum::{
response::{Html, IntoResponse, Response}, response::{Html, IntoResponse, Response},
routing::get, routing::get,
}; };
use rand::{Rng, distr::Alphanumeric}; use rand::{Rng, distr::Alphanumeric};
use std::{env, net::SocketAddr, sync::LazyLock}; use std::{env, net::SocketAddr, sync::LazyLock};
use std::{env::VarError, path::PathBuf}; use std::{env::VarError, path::PathBuf};
use tokio::fs::File; use tokio::fs;
use tokio_util::io::ReaderStream; use tokio_util::io::ReaderStream;
struct Config { struct Config {
@@ -23,12 +22,14 @@ struct Config {
external_protocol: &'static str, external_protocol: &'static str,
max_filesize: usize, max_filesize: usize,
max_bodysize: usize, max_bodysize: usize,
min_filedays: usize,
max_filedays: usize,
} }
static CONFIG: LazyLock<Config> = LazyLock::new(|| { static CONFIG: LazyLock<Config> = LazyLock::new(|| {
let root_dir = env::var("ROOT_DIR").unwrap_or_else(|_| "/var/files".to_string()); let root_dir = env::var("ROOT_DIR").unwrap_or_else(|_| "/var/files".to_string());
let key = env::var("KEY"); let key = env::var("KEY");
let title = env::var("TITLE").unwrap_or_else(|_| "Simpler Filehost".to_string()); let title = env::var("TITLE").unwrap_or_else(|_| "Yet Another Mid Ahh Filehost".to_string());
let internal_host = env::var("INTERNAL_HOST").unwrap_or_else(|_| "127.0.0.1".to_string()); let internal_host = env::var("INTERNAL_HOST").unwrap_or_else(|_| "127.0.0.1".to_string());
let internal_port = env::var("INTERNAL_PORT") let internal_port = env::var("INTERNAL_PORT")
@@ -54,6 +55,18 @@ static CONFIG: LazyLock<Config> = LazyLock::new(|| {
<< 20; << 20;
let max_bodysize = max_files * max_filesize * 2; let max_bodysize = max_files * max_filesize * 2;
let min_filedays = env::var("MIN_FILEDAYS")
.ok()
.and_then(|x| x.parse().ok())
.unwrap_or(30);
let max_filedays = env::var("MAX_FILEDAYS")
.ok()
.and_then(|x| x.parse().ok())
.unwrap_or(365);
assert!(max_filedays >= min_filedays);
Config { Config {
root_dir, root_dir,
key, key,
@@ -64,6 +77,8 @@ static CONFIG: LazyLock<Config> = LazyLock::new(|| {
external_protocol, external_protocol,
max_filesize, max_filesize,
max_bodysize, max_bodysize,
min_filedays,
max_filedays,
} }
}); });
@@ -86,6 +101,35 @@ async fn main() {
addr, CONFIG.root_dir addr, CONFIG.root_dir
); );
/* cleanup cronjob */
#[cfg(feature = "cleanup")]
tokio::spawn(async move {
use chrono::{Local, NaiveDate};
let mut last_cleanup_day: NaiveDate = Local::now().date_naive();
loop {
use tokio::time::{Duration, sleep};
/* every 30 minutes */
sleep(Duration::from_secs(30 * 60)).await;
let now = Local::now();
let today = now.date_naive();
/* if the date changed, midnight has passed */
if today > last_cleanup_day {
println!("attempting cleanup at {}", now.to_string());
if let Err(e) = cleanup_directory().await {
eprintln!("cleanup failed: {}", e);
} else {
println!("cleanup succeeded!");
last_cleanup_day = today;
}
}
}
});
axum::serve(listener, app).await.unwrap(); axum::serve(listener, app).await.unwrap();
} }
@@ -108,6 +152,19 @@ static INDEX_HTML: LazyLock<String> = LazyLock::new(|| {
}, },
); );
if cfg!(feature = "cleanup") {
html = html
.replace("{{MAX_SIZE}}", &(CONFIG.max_filesize >> 20).to_string())
.replace("{{MAX_DAYS}}", &CONFIG.max_filedays.to_string())
.replace("{{MIN_DAYS}}", &CONFIG.min_filedays.to_string());
} else {
if let Some(start) = html.find("<!-- CLEANUP_START -->") {
if let Some(end) = html.find("<!-- CLEANUP_END -->") {
html.replace_range(start..end + "<!-- CLEANUP_END -->".len(), "");
}
}
}
html html
}); });
@@ -205,7 +262,7 @@ async fn upload(mut payload: Multipart) -> Result<impl IntoResponse, YamafError>
let save_path = std::path::Path::new(&CONFIG.root_dir).join(&filename); let save_path = std::path::Path::new(&CONFIG.root_dir).join(&filename);
let mut file = File::create(&save_path) let mut file = fs::File::create(&save_path)
.await .await
.map_err(|_| YamafError::InternalError("Internal i/o error".into()))?; .map_err(|_| YamafError::InternalError("Internal i/o error".into()))?;
@@ -223,7 +280,7 @@ async fn upload(mut payload: Multipart) -> Result<impl IntoResponse, YamafError>
.ok_or_else(|| YamafError::BadRequest("File too large".into()))?; .ok_or_else(|| YamafError::BadRequest("File too large".into()))?;
if written > CONFIG.max_filesize { if written > CONFIG.max_filesize {
_ = tokio::fs::remove_file(&save_path).await; _ = fs::remove_file(&save_path).await;
return Err(YamafError::FileTooBig(filename)); return Err(YamafError::FileTooBig(filename));
} }
@@ -260,10 +317,10 @@ async fn upload(mut payload: Multipart) -> Result<impl IntoResponse, YamafError>
async fn serve_file(Path(filename): Path<String>) -> Result<impl IntoResponse, YamafError> { async fn serve_file(Path(filename): Path<String>) -> Result<impl IntoResponse, YamafError> {
let path = PathBuf::from(&CONFIG.root_dir).join(&filename); let path = PathBuf::from(&CONFIG.root_dir).join(&filename);
let metadata = tokio::fs::metadata(&path) let metadata = fs::metadata(&path)
.await .await
.map_err(|_| YamafError::FileNotFound)?; .map_err(|_| YamafError::FileNotFound)?;
let file = File::open(&path) let file = fs::File::open(&path)
.await .await
.map_err(|_| YamafError::FileNotFound)?; .map_err(|_| YamafError::FileNotFound)?;
let mime = mime_guess::from_path(&path).first_or_octet_stream(); let mime = mime_guess::from_path(&path).first_or_octet_stream();
@@ -289,3 +346,36 @@ async fn serve_file(Path(filename): Path<String>) -> Result<impl IntoResponse, Y
Ok((StatusCode::OK, headers, body).into_response()) Ok((StatusCode::OK, headers, body).into_response())
} }
#[cfg(feature = "cleanup")]
async fn cleanup_directory() -> Result<(), std::io::Error> {
let dir = std::path::Path::new(&CONFIG.root_dir);
let mut entries = fs::read_dir(dir).await?;
while let Some(entry) = entries.next_entry().await? {
use std::os::unix::fs::MetadataExt;
use std::time::SystemTime;
let path = entry.path();
let meta = entry.metadata().await?;
let modified = meta.modified().unwrap_or(SystemTime::UNIX_EPOCH);
let age = SystemTime::now()
.duration_since(modified)
.unwrap_or_default();
/* min_days + (max_days - min_days) * (1 - size/max_size)^e */
let retention = (CONFIG.min_filedays as f64
+ (CONFIG.max_filedays - CONFIG.min_filedays) as f64
* (1.0 - (meta.size() as f64 / CONFIG.max_filesize as f64))
.powf(std::f64::consts::E))
* 24.0
* 60.0;
if meta.is_file() && age.as_secs_f64() > retention {
fs::remove_file(&path).await?;
println!("Deleted {:?}", path);
}
}
Ok(())
}