Compare commits

6 Commits

Author SHA1 Message Date
fa60934d60 major bug: fix retention counting
Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
2025-11-17 23:15:04 +05:30
6fe202b1d1 fix formula typo
Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
2025-11-16 18:39:35 +05:30
0566e6709c return html only if user accepts it
Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
2025-11-16 18:18:56 +05:30
1516480216 check key field first
Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
2025-11-16 18:10:40 +05:30
63a0268695 feature: add cleanup
Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
2025-11-16 18:03:32 +05:30
fad5ee8a30 add LICENSE
Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
2025-11-11 22:58:02 +05:30
8 changed files with 495 additions and 124 deletions

234
Cargo.lock generated
View File

@@ -2,6 +2,15 @@
# It is not intended for manual editing.
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]]
name = "atomic-waker"
version = "1.1.2"
@@ -9,10 +18,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "axum"
version = "0.8.6"
name = "autocfg"
version = "1.5.0"
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 = [
"axum-core",
"bytes",
@@ -68,10 +83,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "bytes"
version = "1.10.1"
name = "bumpalo"
version = "3.19.0"
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]]
name = "cfg-if"
@@ -79,6 +110,25 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "encoding_rs"
version = "0.8.35"
@@ -88,6 +138,12 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
[[package]]
name = "fnv"
version = "1.0.7"
@@ -215,9 +271,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
version = "1.7.0"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e"
checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
dependencies = [
"atomic-waker",
"bytes",
@@ -236,9 +292,9 @@ dependencies = [
[[package]]
name = "hyper-util"
version = "0.1.17"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8"
checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56"
dependencies = [
"bytes",
"futures-core",
@@ -250,12 +306,46 @@ dependencies = [
"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]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "libc"
version = "0.2.177"
@@ -333,6 +423,15 @@ dependencies = [
"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]]
name = "once_cell"
version = "1.21.3"
@@ -451,6 +550,12 @@ dependencies = [
"bitflags",
]
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "ryu"
version = "1.0.20"
@@ -528,6 +633,12 @@ dependencies = [
"serde",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook-registry"
version = "1.4.6"
@@ -567,9 +678,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
name = "syn"
version = "2.0.109"
version = "2.0.110"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f"
checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
dependencies = [
"proc-macro2",
"quote",
@@ -704,12 +815,110 @@ dependencies = [
"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]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "windows-sys"
version = "0.60.2"
@@ -804,6 +1013,7 @@ name = "yamaf"
version = "0.1.0"
dependencies = [
"axum",
"chrono",
"futures-util",
"mime_guess",
"rand",

View File

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

14
LICENSE Normal file
View File

@@ -0,0 +1,14 @@
Marvel Rivals License Revision 2
(c) Amneesh Singh, 2025
Permission to use, copy, distribute, sell, or modify the compiled binaries,
source code, and documentation (the "Software") is granted only to individuals
who currently hold a higher competitive matchmaking rank in Marvel Rivals
(NetEase / Marvel Games) than the copyright holder.
All others are expressly prohibited from using, copying, distributing, selling,
or modifying the Software in any form.
The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. The authors
are NOT LIABLE FOR ANY LOSS, DAMAGE, OR MISUSE arising from its use.

View File

@@ -19,6 +19,18 @@
| 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_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/

View File

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

@@ -5,6 +5,7 @@
</head>
<body>
<h1>{{TITLE}}</h1>
<p>
Use curl to upload:
<br>
@@ -21,11 +22,24 @@
curl -F "key=[key]" -F file=@"[file]" -F file=@"[file2]" {{USER_URL}}
</code>
</p>
<form method="post" enctype="multipart/form-data">
{{KEY_FIELD}}
<input type="file" name="file" multiple>
<br>
<button type="submit">Upload</button>
</form>
<div id="progress-container"></div>
<!-- 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>

View File

@@ -6,11 +6,10 @@ use axum::{
response::{Html, IntoResponse, Response},
routing::get,
};
use rand::{Rng, distr::Alphanumeric};
use std::{env, net::SocketAddr, sync::LazyLock};
use std::{env::VarError, path::PathBuf};
use tokio::fs::File;
use tokio::fs;
use tokio_util::io::ReaderStream;
struct Config {
@@ -23,12 +22,14 @@ struct Config {
external_protocol: &'static str,
max_filesize: usize,
max_bodysize: usize,
min_filedays: usize,
max_filedays: usize,
}
static CONFIG: LazyLock<Config> = LazyLock::new(|| {
let root_dir = env::var("ROOT_DIR").unwrap_or_else(|_| "/var/files".to_string());
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_port = env::var("INTERNAL_PORT")
@@ -54,6 +55,18 @@ static CONFIG: LazyLock<Config> = LazyLock::new(|| {
<< 20;
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 {
root_dir,
key,
@@ -64,6 +77,8 @@ static CONFIG: LazyLock<Config> = LazyLock::new(|| {
external_protocol,
max_filesize,
max_bodysize,
min_filedays,
max_filedays,
}
});
@@ -86,6 +101,35 @@ async fn main() {
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();
}
@@ -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
});
@@ -153,10 +210,7 @@ fn clean_filename(filename: &str) -> String {
let mut prev_dash = false;
for c in filename.to_lowercase().chars() {
if c.is_ascii_alphanumeric() {
slug.push(c);
prev_dash = false;
} else if c == '.' {
if c.is_ascii_alphanumeric() || c == '.' {
slug.push(c);
prev_dash = false;
} else if !prev_dash {
@@ -168,14 +222,21 @@ fn clean_filename(filename: &str) -> String {
slug.trim_matches('-').to_string()
}
async fn upload(mut payload: Multipart) -> Result<impl IntoResponse, YamafError> {
async fn upload(
headers: HeaderMap,
mut payload: Multipart,
) -> Result<impl IntoResponse, YamafError> {
let mut responses = Vec::new();
let mut found_key = false;
while let Some(mut field) = payload.next_field().await.unwrap() {
match field.name() {
Some("key") => {
let wants_html = headers
.get("accept")
.and_then(|h| h.to_str().ok())
.map(|a| a.contains("text/html"))
.unwrap_or(false);
if let Ok(ref key) = CONFIG.key {
if let Some(field) = payload.next_field().await.unwrap() {
if field.name() == Some("key") {
let bytes = field
.bytes()
.await
@@ -187,16 +248,16 @@ async fn upload(mut payload: Multipart) -> Result<impl IntoResponse, YamafError>
if s != *key {
return Err(YamafError::BadRequest("Wrong key".into()));
}
found_key = true;
}
}
Some("file") => {
if CONFIG.key.is_ok() && found_key == false {
} else {
return Err(YamafError::BadRequest("Missing key".into()));
}
} else {
return Err(YamafError::BadRequest("Missing key".into()));
}
}
while let Some(mut field) = payload.next_field().await.unwrap() {
if field.name() == Some("file") {
let filename = field
.file_name()
.map_or(format!("{}-upload", random(10)), |filename| {
@@ -205,7 +266,7 @@ async fn upload(mut payload: Multipart) -> Result<impl IntoResponse, YamafError>
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
.map_err(|_| YamafError::InternalError("Internal i/o error".into()))?;
@@ -223,7 +284,7 @@ async fn upload(mut payload: Multipart) -> Result<impl IntoResponse, YamafError>
.ok_or_else(|| YamafError::BadRequest("File too large".into()))?;
if written > CONFIG.max_filesize {
_ = tokio::fs::remove_file(&save_path).await;
_ = fs::remove_file(&save_path).await;
return Err(YamafError::FileTooBig(filename));
}
@@ -233,16 +294,22 @@ async fn upload(mut payload: Multipart) -> Result<impl IntoResponse, YamafError>
.map_err(|_| YamafError::InternalError("Internal i/o error".into()))?;
}
responses.push(format!(
r#"<a href="{proto}://{host}/{file}">{proto}://{host}/{file}</a> (size ~ {size:.2}k)"#,
let url = format!(
"{proto}://{host}/{file}",
proto = CONFIG.external_protocol,
host = CONFIG.external_host,
file = filename,
size = written as f64 / 1024 as f64
));
}
);
None | Some(_) => {}
if wants_html {
responses.push(format!(
r#"<a href="{url}">{url}</a> (size ~ {size:.2}k)"#,
url = url,
size = written as f64 / 1024.0,
));
} else {
responses.push(url);
}
}
}
@@ -250,20 +317,24 @@ async fn upload(mut payload: Multipart) -> Result<impl IntoResponse, YamafError>
return Err(YamafError::BadRequest("No files uploaded".into()));
}
if wants_html {
Ok(Html(format!(
"Here are your file(s):<br>{}",
responses.join("<br>")
))
.into_response())
} else {
Ok(responses.join("\n").into_response())
}
}
async fn serve_file(Path(filename): Path<String>) -> Result<impl IntoResponse, YamafError> {
let path = PathBuf::from(&CONFIG.root_dir).join(&filename);
let metadata = tokio::fs::metadata(&path)
let metadata = fs::metadata(&path)
.await
.map_err(|_| YamafError::FileNotFound)?;
let file = File::open(&path)
let file = fs::File::open(&path)
.await
.map_err(|_| YamafError::FileNotFound)?;
let mime = mime_guess::from_path(&path).first_or_octet_stream();
@@ -289,3 +360,37 @@ async fn serve_file(Path(filename): Path<String>) -> Result<impl IntoResponse, Y
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
* 60.0;
if meta.is_file() && age.as_secs_f64() > retention {
fs::remove_file(&path).await?;
println!("Deleted {:?}", path);
}
}
Ok(())
}