1 Commits

Author SHA1 Message Date
892787f3be add: LICENSE
Signed-off-by: prashantrahul141 <prashantrahul141@protonmail.com>
2025-11-11 22:55:01 +05:30
8 changed files with 131 additions and 487 deletions

230
Cargo.lock generated
View File

@@ -2,32 +2,17 @@
# 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "axum"
version = "0.8.7"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425"
checksum = "8a18ed336352031311f4e0b4dd2ff392d4fbb370777c9d18d7fc9d7359f73871"
dependencies = [
"axum-core",
"bytes",
@@ -82,27 +67,11 @@ version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "bumpalo"
version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "bytes"
version = "1.11.0"
version = "1.10.1"
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",
]
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cfg-if"
@@ -110,25 +79,6 @@ 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"
@@ -138,12 +88,6 @@ 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"
@@ -271,9 +215,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
version = "1.8.1"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e"
dependencies = [
"atomic-waker",
"bytes",
@@ -292,9 +236,9 @@ dependencies = [
[[package]]
name = "hyper-util"
version = "0.1.18"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56"
checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8"
dependencies = [
"bytes",
"futures-core",
@@ -306,46 +250,12 @@ 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"
@@ -423,15 +333,6 @@ 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"
@@ -550,12 +451,6 @@ 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"
@@ -633,12 +528,6 @@ 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"
@@ -678,9 +567,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
name = "syn"
version = "2.0.110"
version = "2.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f"
dependencies = [
"proc-macro2",
"quote",
@@ -815,110 +704,12 @@ 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"
@@ -1013,7 +804,6 @@ name = "yamaf"
version = "0.1.0"
dependencies = [
"axum",
"chrono",
"futures-util",
"mime_guess",
"rand",

View File

@@ -7,12 +7,8 @@ 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 = []

23
LICENSE
View File

@@ -1,14 +1,15 @@
Marvel Rivals License Revision 2
(c) Amneesh Singh, 2025
Marvel Rivals License Revision 1
(c) Author, year
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.
Permission is hereby granted, free of charge, for anyone to use, distribute, or
sell the compiled binaries, source code, and documentation (the "Software")
without attribution.
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.
Permission to modify the Software is only granted to those that have a higher
competitive matchmaking rank than the copyright holder in Marvel Rivals
(NetEase, 2024).
The Software is provided in the hope that some will find it useful, but the
Software comes under NO WARRANTY, EXPRESS OR IMPLIED, and the authors of the
Software are NOT LIABLE IN THE EVENT OF LOSSES, DAMAGES OR MISUSE relating to
the Software.

View File

@@ -18,19 +18,7 @@
| 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 | - |
| 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
| MAX_FILESIZE_MB | Determines the max filesize possible, used to return failure and calculate bodysize | 100M |
[fn:1] https://git.weirdnatto.in/natto1784/simple-filehost/

View File

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

View File

@@ -1,15 +0,0 @@
{
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,45 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<title>{{TITLE}}</title>
</head>
<body>
<h1>{{TITLE}}</h1>
<p>
Use curl to upload:
<br>
<code>
curl -F file=@"[file]" {{USER_URL}}
</code>
<br>
<br>
If key is enabled then a field "key" will be required.
<br>
Make sure the key is the first field in the multipart before any files.
<br>
<code>
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>
<!-- 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 -->
<head>
<title>{{TITLE}}</title>
</head>
<body>
<h1>{{TITLE}}</h1>
<p>
Use curl to upload:
<br>
<code>
curl -F file=@"[file]" {{USER_URL}}
</code>
<br>
<br>
If key is enabled then a field "key" will be required.
<br>
Make sure the key is the first field in the multipart before any files.
<br>
<code>
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>
</html>

View File

@@ -6,10 +6,11 @@ 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;
use tokio::fs::File;
use tokio_util::io::ReaderStream;
struct Config {
@@ -22,14 +23,12 @@ 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(|_| "Yet Another Mid Ahh Filehost".to_string());
let title = env::var("TITLE").unwrap_or_else(|_| "Simpler 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")
@@ -55,18 +54,6 @@ 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,
@@ -77,8 +64,6 @@ static CONFIG: LazyLock<Config> = LazyLock::new(|| {
external_protocol,
max_filesize,
max_bodysize,
min_filedays,
max_filedays,
}
});
@@ -101,35 +86,6 @@ 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();
}
@@ -152,19 +108,6 @@ 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
});
@@ -210,7 +153,10 @@ fn clean_filename(filename: &str) -> String {
let mut prev_dash = false;
for c in filename.to_lowercase().chars() {
if c.is_ascii_alphanumeric() || c == '.' {
if c.is_ascii_alphanumeric() {
slug.push(c);
prev_dash = false;
} else if c == '.' {
slug.push(c);
prev_dash = false;
} else if !prev_dash {
@@ -222,94 +168,81 @@ fn clean_filename(filename: &str) -> String {
slug.trim_matches('-').to_string()
}
async fn upload(
headers: HeaderMap,
mut payload: Multipart,
) -> Result<impl IntoResponse, YamafError> {
async fn upload(mut payload: Multipart) -> Result<impl IntoResponse, YamafError> {
let mut responses = Vec::new();
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
.map_err(|e| YamafError::BadRequest(format!("Error reading key: {e}")))?;
let s = String::from_utf8(bytes.to_vec())
.map_err(|_| YamafError::InternalError("Invalid key format".into()))?;
if s != *key {
return Err(YamafError::BadRequest("Wrong key".into()));
}
} else {
return Err(YamafError::BadRequest("Missing key".into()));
}
} else {
return Err(YamafError::BadRequest("Missing key".into()));
}
}
let mut found_key = false;
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| {
format!("{}-{}", random(4), clean_filename(filename))
});
match field.name() {
Some("key") => {
if let Ok(ref key) = CONFIG.key {
let bytes = field
.bytes()
.await
.map_err(|e| YamafError::BadRequest(format!("Error reading key: {e}")))?;
let save_path = std::path::Path::new(&CONFIG.root_dir).join(&filename);
let s = String::from_utf8(bytes.to_vec())
.map_err(|_| YamafError::InternalError("Invalid key format".into()))?;
let mut file = fs::File::create(&save_path)
.await
.map_err(|_| YamafError::InternalError("Internal i/o error".into()))?;
if s != *key {
return Err(YamafError::BadRequest("Wrong key".into()));
}
let mut written: usize = 0;
found_key = true;
}
}
while let Some(chunk) = field
.chunk()
.await
.map_err(|err| YamafError::InternalError(err.to_string()))?
{
use tokio::io::AsyncWriteExt;
written = written
.checked_add(chunk.len())
.ok_or_else(|| YamafError::BadRequest("File too large".into()))?;
if written > CONFIG.max_filesize {
_ = fs::remove_file(&save_path).await;
return Err(YamafError::FileTooBig(filename));
Some("file") => {
if CONFIG.key.is_ok() && found_key == false {
return Err(YamafError::BadRequest("Missing key".into()));
}
file.write_all(&chunk)
let filename = field
.file_name()
.map_or(format!("{}-upload", random(10)), |filename| {
format!("{}-{}", random(4), clean_filename(filename))
});
let save_path = std::path::Path::new(&CONFIG.root_dir).join(&filename);
let mut file = File::create(&save_path)
.await
.map_err(|_| YamafError::InternalError("Internal i/o error".into()))?;
}
let url = format!(
"{proto}://{host}/{file}",
proto = CONFIG.external_protocol,
host = CONFIG.external_host,
file = filename,
);
let mut written: usize = 0;
while let Some(chunk) = field
.chunk()
.await
.map_err(|err| YamafError::InternalError(err.to_string()))?
{
use tokio::io::AsyncWriteExt;
written = written
.checked_add(chunk.len())
.ok_or_else(|| YamafError::BadRequest("File too large".into()))?;
if written > CONFIG.max_filesize {
_ = tokio::fs::remove_file(&save_path).await;
return Err(YamafError::FileTooBig(filename));
}
file.write_all(&chunk)
.await
.map_err(|_| YamafError::InternalError("Internal i/o error".into()))?;
}
if wants_html {
responses.push(format!(
r#"<a href="{url}">{url}</a> (size ~ {size:.2}k)"#,
url = url,
size = written as f64 / 1024.0,
r#"<a href="{proto}://{host}/{file}">{proto}://{host}/{file}</a> (size ~ {size:.2}k)"#,
proto = CONFIG.external_protocol,
host = CONFIG.external_host,
file = filename,
size = written as f64 / 1024 as f64
));
} else {
responses.push(url);
}
None | Some(_) => {}
}
}
@@ -317,24 +250,20 @@ async fn upload(
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())
}
Ok(Html(format!(
"Here are your file(s):<br>{}",
responses.join("<br>")
))
.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 = fs::metadata(&path)
let metadata = tokio::fs::metadata(&path)
.await
.map_err(|_| YamafError::FileNotFound)?;
let file = fs::File::open(&path)
let file = File::open(&path)
.await
.map_err(|_| YamafError::FileNotFound)?;
let mime = mime_guess::from_path(&path).first_or_octet_stream();
@@ -360,37 +289,3 @@ 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(())
}