file download

This commit is contained in:
2026-04-14 16:11:04 +02:00
parent 52a14a71d6
commit cb9414bc43
6 changed files with 125 additions and 44 deletions

50
Cargo.lock generated
View File

@ -152,9 +152,9 @@ dependencies = [
[[package]] [[package]]
name = "axum" name = "axum"
version = "0.8.8" version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90"
dependencies = [ dependencies = [
"axum-core", "axum-core",
"axum-macros", "axum-macros",
@ -181,7 +181,7 @@ dependencies = [
"sha1", "sha1",
"sync_wrapper", "sync_wrapper",
"tokio", "tokio",
"tokio-tungstenite", "tokio-tungstenite 0.29.0",
"tower", "tower",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
@ -232,9 +232,9 @@ dependencies = [
[[package]] [[package]]
name = "axum-macros" name = "axum-macros"
version = "0.5.0" version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1191,7 +1191,7 @@ dependencies = [
"thiserror 2.0.18", "thiserror 2.0.18",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
"tokio-tungstenite", "tokio-tungstenite 0.28.0",
"tokio-util", "tokio-util",
"tower", "tower",
"tower-http", "tower-http",
@ -1497,7 +1497,7 @@ dependencies = [
"subsecond", "subsecond",
"thiserror 2.0.18", "thiserror 2.0.18",
"tokio", "tokio",
"tokio-tungstenite", "tokio-tungstenite 0.28.0",
"tokio-util", "tokio-util",
"tower", "tower",
"tower-http", "tower-http",
@ -2540,15 +2540,19 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
name = "httpserver" name = "httpserver"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"axum-core",
"chrono", "chrono",
"diesel", "diesel",
"dioxus", "dioxus",
"dioxus-asset-resolver",
"dioxus-html", "dioxus-html",
"dioxus-primitives", "dioxus-primitives",
"futures", "futures",
"random-string", "random-string",
"reqwest 0.13.2", "reqwest 0.13.2",
"serde", "serde",
"tokio",
"tokio-util",
"tracing", "tracing",
"wasm-bindgen", "wasm-bindgen",
"web-sys", "web-sys",
@ -5226,9 +5230,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.51.0" version = "1.51.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bd1c4c0fc4a7ab90fc15ef6daaa3ec3b893f004f915f2392557ed23237820cd" checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c"
dependencies = [ dependencies = [
"bytes", "bytes",
"libc", "libc",
@ -5284,6 +5288,18 @@ dependencies = [
"tungstenite 0.28.0", "tungstenite 0.28.0",
] ]
[[package]]
name = "tokio-tungstenite"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c"
dependencies = [
"futures-util",
"log",
"tokio",
"tungstenite 0.29.0",
]
[[package]] [[package]]
name = "tokio-util" name = "tokio-util"
version = "0.7.18" version = "0.7.18"
@ -5561,6 +5577,22 @@ dependencies = [
"utf-8", "utf-8",
] ]
[[package]]
name = "tungstenite"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8"
dependencies = [
"bytes",
"data-encoding",
"http",
"httparse",
"log",
"rand 0.9.2",
"sha1",
"thiserror 2.0.18",
]
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.19.0" version = "1.19.0"

View File

@ -7,15 +7,19 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
axum-core = { version = "0.5.6", optional = true }
chrono = { version = "0.4.44", features = ["serde"] } chrono = { version = "0.4.44", features = ["serde"] }
diesel = { version = "2.3.7", features = ["postgres", "r2d2"], optional = true } diesel = { version = "2.3.7", features = ["postgres", "r2d2"], optional = true }
dioxus = { version = "0.7.1", features = ["router", "fullstack"] } dioxus = { version = "0.7.1", features = ["router", "fullstack"] }
dioxus-asset-resolver = "0.7.4"
dioxus-html = "0.7.3" dioxus-html = "0.7.3"
dioxus-primitives = { git = "https://github.com/DioxusLabs/components", version = "0.0.1", default-features = false } dioxus-primitives = { git = "https://github.com/DioxusLabs/components", version = "0.0.1", default-features = false }
futures = "0.3.32" futures = "0.3.32"
random-string = "1.1.0" random-string = "1.1.0"
reqwest = { version = "0.13.2", features = ["stream"] } reqwest = { version = "0.13.2", features = ["stream"] }
serde = "1.0.228" serde = "1.0.228"
tokio = { version = "1.51.1", optional = true }
tokio-util = { version = "0.7.18", optional = true }
tracing = "0.1.44" tracing = "0.1.44"
wasm-bindgen = "0.2.114" wasm-bindgen = "0.2.114"
web-sys = { version = "0.3.91", features = [ "Navigator", "Clipboard" ] } web-sys = { version = "0.3.91", features = [ "Navigator", "Clipboard" ] }
@ -29,7 +33,7 @@ desktop = ["dioxus/desktop"]
# The feature that are only required for the mobile = ["dioxus/mobile"] build target should be optional and only enabled in the mobile = ["dioxus/mobile"] feature # The feature that are only required for the mobile = ["dioxus/mobile"] build target should be optional and only enabled in the mobile = ["dioxus/mobile"] feature
mobile = ["dioxus/mobile"] mobile = ["dioxus/mobile"]
# The feature that are only required for the server = ["dioxus/server"] build target should be optional and only enabled in the server = ["dioxus/server"] feature # The feature that are only required for the server = ["dioxus/server"] build target should be optional and only enabled in the server = ["dioxus/server"] feature
server = ["dioxus/server", "dep:diesel"] server = ["dioxus/server", "dep:diesel", "dep:tokio", "dep:tokio-util", "dep:axum-core"]
[profile.release] [profile.release]
opt-level = "z" opt-level = "z"

View File

@ -7,7 +7,6 @@
'Noto Color Emoji'; 'Noto Color Emoji';
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
monospace; monospace;
--color-blue-100: oklch(93.2% 0.032 255.585);
--color-blue-800: oklch(42.4% 0.199 265.638); --color-blue-800: oklch(42.4% 0.199 265.638);
--color-zinc-900: oklch(21% 0.006 285.885); --color-zinc-900: oklch(21% 0.006 285.885);
--color-white: #fff; --color-white: #fff;
@ -171,6 +170,9 @@
.static { .static {
position: static; position: static;
} }
.contents {
display: contents;
}
.flex { .flex {
display: flex; display: flex;
} }
@ -192,25 +194,12 @@
.w-screen { .w-screen {
width: 100vw; width: 100vw;
} }
.border-collapse {
border-collapse: collapse;
}
.transform { .transform {
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,); transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
} }
.resize {
resize: both;
}
.flex-col { .flex-col {
flex-direction: column; flex-direction: column;
} }
.flex-row {
flex-direction: row;
}
.border {
border-style: var(--tw-border-style);
border-width: 1px;
}
.bg-zinc-900 { .bg-zinc-900 {
background-color: var(--color-zinc-900); background-color: var(--color-zinc-900);
} }
@ -231,9 +220,6 @@
--tw-font-weight: var(--font-weight-bold); --tw-font-weight: var(--font-weight-bold);
font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold);
} }
.text-blue-100 {
color: var(--color-blue-100);
}
.text-blue-800 { .text-blue-800 {
color: var(--color-blue-800); color: var(--color-blue-800);
} }
@ -243,10 +229,6 @@
.underline { .underline {
text-decoration-line: underline; text-decoration-line: underline;
} }
.outline {
outline-style: var(--tw-outline-style);
outline-width: 1px;
}
} }
@property --tw-rotate-x { @property --tw-rotate-x {
syntax: "*"; syntax: "*";
@ -268,20 +250,10 @@
syntax: "*"; syntax: "*";
inherits: false; inherits: false;
} }
@property --tw-border-style {
syntax: "*";
inherits: false;
initial-value: solid;
}
@property --tw-font-weight { @property --tw-font-weight {
syntax: "*"; syntax: "*";
inherits: false; inherits: false;
} }
@property --tw-outline-style {
syntax: "*";
inherits: false;
initial-value: solid;
}
@layer properties { @layer properties {
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) { @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
*, ::before, ::after, ::backdrop { *, ::before, ::after, ::backdrop {
@ -290,9 +262,7 @@
--tw-rotate-z: initial; --tw-rotate-z: initial;
--tw-skew-x: initial; --tw-skew-x: initial;
--tw-skew-y: initial; --tw-skew-y: initial;
--tw-border-style: solid;
--tw-font-weight: initial; --tw-font-weight: initial;
--tw-outline-style: solid;
} }
} }
} }

View File

@ -0,0 +1,72 @@
use std::fs::create_dir;
use dioxus::prelude::*;
use dioxus::fullstack::FileStream;
#[cfg(feature = "server")]
use httpserver::models::GetFile;
#[cfg(feature = "server")]
use diesel::prelude::*;
#[cfg(feature = "server")]
use httpserver::DB;
#[cfg(feature = "server")]
use httpserver::schema;
#[cfg(feature = "server")]
use crate::config::ServerConfig;
use std::path::Path;
#[cfg(feature = "server")]
async fn create_filestream(filename: String, file: &Path) -> Result<FileStream, std::io::Error> {
let metadata = file.metadata()?;
let contents = tokio::fs::File::open(&file).await?;
let mime = dioxus_asset_resolver::native::get_mime_from_ext(
file.extension().and_then(|s| s.to_str()),
);
let size = metadata.len();
let reader_stream = tokio_util::io::ReaderStream::new(contents);
let body = axum_core::body::Body::from_stream(reader_stream).into_data_stream();
Ok(FileStream::from_raw(filename, Some(size), mime.to_string(), body))
}
#[get("/upload/{id}/dl")]
async fn download_file(id: String) -> Result<FileStream, HttpError> {
use schema::file;
let s_config = ServerConfig::load();
let result = DB.with(|pool| schema::file::table.select((file::filename))
.filter(file::stored_filename.eq(id.clone()))
.filter(file::deleted.eq(false))
.load::<(String)>(&mut pool.get().unwrap()));
if let Err(_) = result {
return HttpError::internal_server_error("Database request failed");
}
let db_file = result.unwrap();
if db_file.len() == 0 {
return HttpError::internal_server_error("The requested file does not exist");
}
let file_path = s_config.upload_folder + &id;
let path = Path::new(&file_path);
// create a filestream from raw to set the filename to the uploaded filename
let fstream = create_filestream(db_file[0].clone(), path.into()).await;
match fstream {
Ok(stream) => {
Ok(stream)
},
Err(err) => {
tracing::info!("Failed to open a file err : {err}");
HttpError::internal_server_error(format!("Failed to open the file"))
}
}
}

View File

@ -29,7 +29,7 @@ struct FetchedInfo {
} }
#[post("/api/upload/info")] #[get("/api/upload/info?filename")]
async fn get_file_info(filename: String) -> Result<FetchedInfo, HttpError> { async fn get_file_info(filename: String) -> Result<FetchedInfo, HttpError> {
use schema::file; use schema::file;
let result = DB.with(|pool| schema::file::table.select((file::filename, file::file_size, file::created_at)) let result = DB.with(|pool| schema::file::table.select((file::filename, file::file_size, file::created_at))

View File

@ -3,3 +3,6 @@ pub use create::UploadFile;
mod info; mod info;
pub use info::FileInfo; pub use info::FileInfo;
mod get;