whole bunch of stuff ig
parent
e1c499ee72
commit
88b875b809
|
@ -1 +1,2 @@
|
||||||
/target
|
/target
|
||||||
|
.DS_Store
|
||||||
|
|
|
@ -111,6 +111,21 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-io",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.28"
|
version = "0.3.28"
|
||||||
|
@ -118,6 +133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
|
checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -126,6 +142,34 @@ version = "0.3.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
|
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-executor"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-io"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-macro"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.13",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.28"
|
version = "0.3.28"
|
||||||
|
@ -144,10 +188,27 @@ version = "0.3.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
|
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"futures-macro",
|
||||||
|
"futures-sink",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
|
"memchr",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
|
"slab",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -387,11 +448,15 @@ name = "nyazoom"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
|
"futures",
|
||||||
|
"rand",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
"tower",
|
"tower",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
"urlencoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -467,6 +532,12 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.56"
|
version = "1.0.56"
|
||||||
|
@ -485,6 +556,36 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
|
@ -842,6 +943,12 @@ version = "1.0.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "urlencoding"
|
||||||
|
version = "2.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -7,8 +7,12 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = { version = "0.6.12", features = ["multipart", "http2"] }
|
axum = { version = "0.6.12", features = ["multipart", "http2"] }
|
||||||
|
futures = "0.3.28"
|
||||||
|
rand = { version = "0.8.5", features = ["small_rng"] }
|
||||||
tokio = { version = "1.27.0", features = ["full"] }
|
tokio = { version = "1.27.0", features = ["full"] }
|
||||||
|
tokio-util = { version = "0.7.7", features = ["io"] }
|
||||||
tower = { version = "0.4.13", features = ["util"] }
|
tower = { version = "0.4.13", features = ["util"] }
|
||||||
tower-http = { version = "0.4.0", features = ["fs", "trace", "limit"] }
|
tower-http = { version = "0.4.0", features = ["fs", "trace", "limit"] }
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
||||||
|
urlencoding = "2.1.2"
|
||||||
|
|
141
src/main.rs
141
src/main.rs
|
@ -1,56 +1,161 @@
|
||||||
|
use std::io;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use axum::body::Bytes;
|
||||||
|
use axum::http::StatusCode;
|
||||||
|
use axum::routing::post;
|
||||||
|
use axum::BoxError;
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{DefaultBodyLimit, Multipart},
|
extract::{DefaultBodyLimit, Multipart},
|
||||||
response::{IntoResponse, Redirect},
|
response::Redirect,
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use axum::routing::post;
|
use futures::{Stream, TryStreamExt};
|
||||||
|
use rand::distributions::{Alphanumeric, DistString};
|
||||||
|
use rand::rngs::SmallRng;
|
||||||
|
use rand::SeedableRng;
|
||||||
|
use tokio::fs::File;
|
||||||
|
use tokio::io::BufWriter;
|
||||||
|
use tokio_util::io::StreamReader;
|
||||||
use tower_http::{limit::RequestBodyLimitLayer, services::ServeDir, trace::TraceLayer};
|
use tower_http::{limit::RequestBodyLimitLayer, services::ServeDir, trace::TraceLayer};
|
||||||
|
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() -> io::Result<()> {
|
||||||
tracing_subscriber::registry()
|
tracing_subscriber::registry()
|
||||||
.with(
|
.with(
|
||||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||||
.unwrap_or_else(|_| "nyazoo=debug,tower_http=debug".into()),
|
.unwrap_or_else(|_| "nyazoom=debug,tower_http=debug".into()),
|
||||||
)
|
)
|
||||||
.with(tracing_subscriber::fmt::layer())
|
.with(tracing_subscriber::fmt::layer())
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
|
// uses create_dir_all to create both .cache and .temp inside it in one go
|
||||||
|
make_dir(".cache/.temp").await?;
|
||||||
|
|
||||||
|
// Router Setup
|
||||||
let with_big_body = Router::new()
|
let with_big_body = Router::new()
|
||||||
.route("/upload", post(upload))
|
.route("/upload", post(upload))
|
||||||
.layer(DefaultBodyLimit::disable())
|
.layer(DefaultBodyLimit::disable())
|
||||||
.layer(RequestBodyLimitLayer::new(
|
.layer(RequestBodyLimitLayer::new(
|
||||||
250 * 1024 * 1024, // 250Mb
|
10 * 1024 * 1024 * 1024, // 10GiB
|
||||||
));
|
));
|
||||||
|
|
||||||
let base = Router::new().nest_service("/", ServeDir::new("dist"));
|
let base = Router::new()
|
||||||
|
.nest_service("/", ServeDir::new("dist"))
|
||||||
|
.nest_service("/download", ServeDir::new(".cache"));
|
||||||
|
|
||||||
let app = Router::new().merge(with_big_body).merge(base);
|
let app = Router::new()
|
||||||
|
.merge(with_big_body)
|
||||||
|
.merge(base)
|
||||||
|
.layer(TraceLayer::new_for_http());
|
||||||
|
|
||||||
|
// Server creation
|
||||||
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
|
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
|
||||||
tracing::debug!("listening on {}", addr);
|
tracing::debug!("listening on {}", addr);
|
||||||
axum::Server::bind(&addr)
|
axum::Server::bind(&addr)
|
||||||
.serve(app.layer(TraceLayer::new_for_http()).into_make_service())
|
.serve(app.into_make_service())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn upload(mut body: Multipart) -> impl IntoResponse {
|
async fn upload(mut body: Multipart) -> Result<Redirect, (StatusCode, String)> {
|
||||||
|
let cache_folder = Path::new(".cache/.temp").join(get_random_name(10));
|
||||||
|
|
||||||
|
make_dir(&cache_folder)
|
||||||
|
.await
|
||||||
|
.map_err(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()))?;
|
||||||
|
|
||||||
while let Some(field) = body.next_field().await.unwrap() {
|
while let Some(field) = body.next_field().await.unwrap() {
|
||||||
let name = field.name().unwrap().to_string();
|
let file_name = if let Some(file_name) = field.file_name() {
|
||||||
let content_type = field.content_type().unwrap().to_string();
|
file_name.to_owned()
|
||||||
let file_name = field.file_name().unwrap().to_string();
|
} else {
|
||||||
let data = field.bytes().await.unwrap();
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
tracing::debug!(
|
|
||||||
"\n\nLength of {name} ({file_name}: {content_type}) is {} bytes\n",
|
if !path_is_valid(&file_name) {
|
||||||
data.len()
|
return Err((StatusCode::BAD_REQUEST, "Invalid Filename >:(".to_owned()))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Redirect::to("/")
|
let path = cache_folder.join(file_name);
|
||||||
|
|
||||||
|
tracing::debug!("\n\nstuff written to {path:?}\n");
|
||||||
|
stream_to_file(&path, field).await?
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::debug!("{cache_folder:?}");
|
||||||
|
|
||||||
|
Ok(Redirect::to("/"))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn stream_to_file<S, E, P>(path: P, stream: S) -> Result<(), (StatusCode, String)>
|
||||||
|
where
|
||||||
|
P: AsRef<Path>,
|
||||||
|
S: Stream<Item = Result<Bytes, E>>,
|
||||||
|
E: Into<BoxError>,
|
||||||
|
{
|
||||||
|
async {
|
||||||
|
// Convert the stream into an `AsyncRead`.
|
||||||
|
let body_with_io_error = stream.map_err(|err| io::Error::new(io::ErrorKind::Other, err));
|
||||||
|
let body_reader = StreamReader::new(body_with_io_error);
|
||||||
|
futures::pin_mut!(body_reader);
|
||||||
|
|
||||||
|
// Create the file. `File` implements `AsyncWrite`.
|
||||||
|
let mut file = BufWriter::new(File::create(&path).await?);
|
||||||
|
|
||||||
|
// Copy the body into the file.
|
||||||
|
tokio::io::copy(&mut body_reader, &mut file).await?;
|
||||||
|
|
||||||
|
io::Result::Ok(())
|
||||||
|
}
|
||||||
|
.await
|
||||||
|
.map_err(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn remove_dir<T>(folder: T) -> io::Result<()>
|
||||||
|
where
|
||||||
|
T: AsRef<Path>,
|
||||||
|
{
|
||||||
|
tokio::fs::remove_dir_all(&folder).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn path_is_valid(path: &str) -> bool {
|
||||||
|
let mut components = Path::new(path).components().peekable();
|
||||||
|
|
||||||
|
if let Some(first) = components.peek() {
|
||||||
|
tracing::debug!("{:?}", &first);
|
||||||
|
if !matches!(first, std::path::Component::Normal(_)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
components.count() == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
async fn make_dir<T>(name: T) -> io::Result<()>
|
||||||
|
where
|
||||||
|
T: AsRef<Path>,
|
||||||
|
{
|
||||||
|
tokio::fs::create_dir_all(name)
|
||||||
|
.await
|
||||||
|
.or_else(|err| match err.kind() {
|
||||||
|
io::ErrorKind::AlreadyExists => Ok(()),
|
||||||
|
_ => Err(err),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_random_name(len: usize) -> String {
|
||||||
|
let mut rng = SmallRng::from_entropy();
|
||||||
|
|
||||||
|
Alphanumeric.sample_string(&mut rng, len)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue