Properly use blake3 mmap

This commit is contained in:
G2-Games 2024-10-24 23:00:23 -05:00
parent 4809be56a9
commit 2fac064c38
5 changed files with 62 additions and 31 deletions

46
Cargo.lock generated
View file

@ -170,6 +170,8 @@ dependencies = [
"cc", "cc",
"cfg-if", "cfg-if",
"constant_time_eq", "constant_time_eq",
"memmap2",
"rayon-core",
"serde", "serde",
] ]
@ -266,6 +268,31 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "crossbeam-deque"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.20.10" version = "0.20.10"
@ -790,6 +817,15 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "memmap2"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "mime" name = "mime"
version = "0.3.17" version = "0.3.17"
@ -1055,6 +1091,16 @@ dependencies = [
"getrandom", "getrandom",
] ]
[[package]]
name = "rayon-core"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.5.7" version = "0.5.7"

View file

@ -5,7 +5,7 @@ edition = "2021"
[dependencies] [dependencies]
bincode = { version = "2.0.0-rc.3", features = ["serde"] } bincode = { version = "2.0.0-rc.3", features = ["serde"] }
blake3 = { version = "1.5.4", features = ["serde"] } blake3 = { version = "1.5.4", features = ["mmap", "rayon", "serde"] }
chrono = { version = "0.4.38", features = ["serde"] } chrono = { version = "0.4.38", features = ["serde"] }
log = "0.4" log = "0.4"
maud = { version = "0.26", features = ["rocket"] } maud = { version = "0.26", features = ["rocket"] }

View file

@ -57,9 +57,6 @@ pub struct MochiFile {
/// The original name of the file /// The original name of the file
name: String, name: String,
/// Size of the file in bytes
size: usize,
/// The location on disk (for deletion and management) /// The location on disk (for deletion and management)
filename: PathBuf, filename: PathBuf,
@ -80,7 +77,6 @@ impl MochiFile {
/// Create a new file that expires in `expiry`. /// Create a new file that expires in `expiry`.
pub fn new_with_expiry( pub fn new_with_expiry(
name: &str, name: &str,
size: usize,
hash: Hash, hash: Hash,
filename: PathBuf, filename: PathBuf,
expire_duration: TimeDelta expire_duration: TimeDelta
@ -90,7 +86,6 @@ impl MochiFile {
Self { Self {
name: name.to_string(), name: name.to_string(),
size,
filename, filename,
hash, hash,
upload_datetime: current, upload_datetime: current,

View file

@ -8,7 +8,7 @@ use chrono::{DateTime, TimeDelta, Utc};
use database::{clean_loop, Database, MochiFile}; use database::{clean_loop, Database, MochiFile};
use log::info; use log::info;
use rocket::{ use rocket::{
data::{Limits, ToByteUnit}, form::Form, fs::{FileServer, Options, TempFile}, get, http::{ContentType, RawStr}, post, response::{content::{RawCss, RawJavaScript}, status::NotFound, Redirect}, routes, serde::{json::Json, Serialize}, tokio::{self, fs::File, io::AsyncReadExt}, Config, FromForm, State data::{Limits, ToByteUnit}, form::Form, fs::{FileServer, Options, TempFile}, get, http::{ContentType, RawStr}, post, response::{content::{RawCss, RawJavaScript}, status::NotFound, Redirect}, routes, serde::{json::Json, Serialize}, tokio, Config, FromForm, State
}; };
use settings::Settings; use settings::Settings;
use strings::{parse_time_string, to_pretty_time}; use strings::{parse_time_string, to_pretty_time};
@ -155,14 +155,13 @@ async fn handle_upload(
let filename = get_id( let filename = get_id(
raw_name, raw_name,
hash.0 hash
); );
out_path.push(filename.clone()); out_path.push(filename.clone());
let constructed_file = MochiFile::new_with_expiry( let constructed_file = MochiFile::new_with_expiry(
raw_name, raw_name,
hash.1, hash,
hash.0,
out_path.clone(), out_path.clone(),
expire_time expire_time
); );
@ -175,8 +174,8 @@ async fn handle_upload(
status: true, status: true,
response: "File already exists", response: "File already exists",
name: constructed_file.name().clone(), name: constructed_file.name().clone(),
url: "files/".to_string() + &filename, url: filename,
hash: hash.0.to_hex()[0..10].to_string(), hash: hash.to_hex()[0..10].to_string(),
expires: Some(constructed_file.get_expiry()), expires: Some(constructed_file.get_expiry()),
..Default::default() ..Default::default()
})) }))
@ -191,8 +190,8 @@ async fn handle_upload(
Ok(Json(ClientResponse { Ok(Json(ClientResponse {
status: true, status: true,
name: constructed_file.name().clone(), name: constructed_file.name().clone(),
url: "files/".to_string() + &filename, url: filename,
hash: hash.0.to_hex()[0..10].to_string(), hash: hash.to_hex()[0..10].to_string(),
expires: Some(constructed_file.get_expiry()), expires: Some(constructed_file.get_expiry()),
..Default::default() ..Default::default()
})) }))
@ -207,11 +206,11 @@ struct ClientResponse {
pub response: &'static str, pub response: &'static str,
#[serde(skip_serializing_if = "String::is_empty")] #[serde(skip_serializing_if = "str::is_empty")]
pub name: String, pub name: String,
#[serde(skip_serializing_if = "String::is_empty")] #[serde(skip_serializing_if = "str::is_empty")]
pub url: String, pub url: String,
#[serde(skip_serializing_if = "String::is_empty")] #[serde(skip_serializing_if = "str::is_empty")]
pub hash: String, pub hash: String,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub expires: Option<DateTime<Utc>>, pub expires: Option<DateTime<Utc>>,
@ -223,20 +222,11 @@ fn get_id(name: &str, hash: Hash) -> String {
} }
/// Get the Blake3 hash of a file, without reading it all into memory, and also get the size /// Get the Blake3 hash of a file, without reading it all into memory, and also get the size
async fn hash_file<P: AsRef<Path>>(input: &P) -> Result<(Hash, usize), std::io::Error> { async fn hash_file<P: AsRef<Path>>(input: &P) -> Result<Hash, std::io::Error> {
let mut file = File::open(input).await?;
let mut buf = vec![0; 5000000];
let mut hasher = blake3::Hasher::new(); let mut hasher = blake3::Hasher::new();
hasher.update_mmap_rayon(input)?;
let mut total = 0; Ok(hasher.finalize())
let mut bytes_read = None;
while bytes_read != Some(0) {
bytes_read = Some(file.read(&mut buf).await?);
total += bytes_read.unwrap();
hasher.update(&buf[..bytes_read.unwrap()]);
}
Ok((hasher.finalize(), total))
} }
/// An endpoint to obtain information about the server's capabilities /// An endpoint to obtain information about the server's capabilities

View file

@ -57,7 +57,7 @@ function makeFinished(progressBar, progressText, linkRow, linkAddress, hash) {
progressText.textContent = ""; progressText.textContent = "";
const link = progressText.appendChild(document.createElement("a")); const link = progressText.appendChild(document.createElement("a"));
link.textContent = hash; link.textContent = hash;
link.href = linkAddress; link.href = "/files/" + linkAddress;
link.target = "_blank"; link.target = "_blank";
let button = linkRow.appendChild(document.createElement("button")); let button = linkRow.appendChild(document.createElement("button"));
@ -68,7 +68,7 @@ function makeFinished(progressBar, progressText, linkRow, linkAddress, hash) {
clearTimeout(buttonTimeout) clearTimeout(buttonTimeout)
} }
navigator.clipboard.writeText( navigator.clipboard.writeText(
encodeURI(window.location.protocol + "//" + window.location.host + "/" + linkAddress) encodeURI(window.location.protocol + "//" + window.location.host + "/files/" + linkAddress)
) )
button.textContent = "✅"; button.textContent = "✅";
buttonTimeout = setTimeout(function() { buttonTimeout = setTimeout(function() {