Added timeouts and a struct for empty response
This commit is contained in:
parent
9e3b9527d3
commit
5f79a9f0d2
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -321,9 +321,9 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.1.12"
|
version = "1.1.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68064e60dbf1f17005c2fde4d07c16d8baa506fd7ffed8ccab702d93617975c7"
|
checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
@ -1051,9 +1051,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.155"
|
version = "0.2.156"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
checksum = "a5f43f184355eefb8d17fc948dbecf6c13be3c141f20d834ae842193a448c72a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
|
@ -48,6 +48,7 @@ tower = { version = "0.4" }
|
|||||||
tower-http = { version = "0.5", features = [
|
tower-http = { version = "0.5", features = [
|
||||||
"compression-full",
|
"compression-full",
|
||||||
"sensitive-headers",
|
"sensitive-headers",
|
||||||
|
"timeout",
|
||||||
"trace",
|
"trace",
|
||||||
"util",
|
"util",
|
||||||
] }
|
] }
|
||||||
|
@ -9,7 +9,7 @@ pub async fn delete(
|
|||||||
Query(params): Query<Params>,
|
Query(params): Query<Params>,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
claims: Claims,
|
claims: Claims,
|
||||||
) -> GeneralResult<StatusCode> {
|
) -> GeneralResult<EmptyResponse> {
|
||||||
db::file::get_permissions(params.file_id, claims.user_id, &state.pool)
|
db::file::get_permissions(params.file_id, claims.user_id, &state.pool)
|
||||||
.await
|
.await
|
||||||
.can_write_guard()?;
|
.can_write_guard()?;
|
||||||
@ -24,5 +24,5 @@ pub async fn delete(
|
|||||||
.await
|
.await
|
||||||
.handle_internal("Error deleting the file")?;
|
.handle_internal("Error deleting the file")?;
|
||||||
|
|
||||||
Ok(StatusCode::NO_CONTENT)
|
Ok(EmptyResponse)
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ pub async fn modify(
|
|||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
claims: Claims,
|
claims: Claims,
|
||||||
mut multipart: Multipart,
|
mut multipart: Multipart,
|
||||||
) -> GeneralResult<StatusCode> {
|
) -> GeneralResult<EmptyResponse> {
|
||||||
db::file::get_permissions(params.file_id, claims.user_id, &state.pool)
|
db::file::get_permissions(params.file_id, claims.user_id, &state.pool)
|
||||||
.await
|
.await
|
||||||
.can_write_guard()?;
|
.can_write_guard()?;
|
||||||
@ -52,5 +52,5 @@ pub async fn modify(
|
|||||||
.await
|
.await
|
||||||
.handle_internal("Error updating the file")?;
|
.handle_internal("Error updating the file")?;
|
||||||
|
|
||||||
Ok(StatusCode::NO_CONTENT)
|
Ok(EmptyResponse)
|
||||||
}
|
}
|
||||||
|
@ -36,9 +36,19 @@ async fn create_file(
|
|||||||
pool: &Pool,
|
pool: &Pool,
|
||||||
) -> anyhow::Result<Uuid> {
|
) -> anyhow::Result<Uuid> {
|
||||||
let (file_id, file) = storage.create().await?;
|
let (file_id, file) = storage.create().await?;
|
||||||
|
let result = async {
|
||||||
let (hash, size) = crate::FileStorage::write_to_file(file, field).await?;
|
let (hash, size) = crate::FileStorage::write_to_file(file, field).await?;
|
||||||
db::file::insert(file_id, parent_folder, file_name, size, hash, pool).await?;
|
db::file::insert(file_id, parent_folder, file_name, size, hash, pool).await?;
|
||||||
Ok(file_id)
|
anyhow::Result::Ok(())
|
||||||
|
}
|
||||||
|
.await;
|
||||||
|
match result {
|
||||||
|
Ok(()) => Ok(file_id),
|
||||||
|
Err(err) => {
|
||||||
|
let _ = storage.delete(file_id).await;
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn parse_field(
|
async fn parse_field(
|
||||||
|
@ -9,7 +9,7 @@ pub async fn delete(
|
|||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
claims: Claims,
|
claims: Claims,
|
||||||
Query(params): Query<Params>,
|
Query(params): Query<Params>,
|
||||||
) -> GeneralResult<()> {
|
) -> GeneralResult<EmptyResponse> {
|
||||||
let root = db::folder::get_root(claims.user_id, &state.pool)
|
let root = db::folder::get_root(claims.user_id, &state.pool)
|
||||||
.await
|
.await
|
||||||
.handle_internal("Error getting the root folder")?;
|
.handle_internal("Error getting the root folder")?;
|
||||||
@ -31,5 +31,7 @@ pub async fn delete(
|
|||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.handle_internal("Error deleting the fodler")
|
.handle_internal("Error deleting the fodler")?;
|
||||||
|
|
||||||
|
Ok(EmptyResponse)
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ pub async fn delete(
|
|||||||
State(pool): State<Pool>,
|
State(pool): State<Pool>,
|
||||||
claims: Claims,
|
claims: Claims,
|
||||||
Query(params): Query<Params>,
|
Query(params): Query<Params>,
|
||||||
) -> GeneralResult<StatusCode> {
|
) -> GeneralResult<EmptyResponse> {
|
||||||
if params.user_id != claims.user_id {
|
if params.user_id != claims.user_id {
|
||||||
db::folder::get_permissions(params.folder_id, claims.user_id, &pool)
|
db::folder::get_permissions(params.folder_id, claims.user_id, &pool)
|
||||||
.await
|
.await
|
||||||
@ -21,5 +21,5 @@ pub async fn delete(
|
|||||||
.await
|
.await
|
||||||
.handle_internal("Error deleting the permissions")?;
|
.handle_internal("Error deleting the permissions")?;
|
||||||
|
|
||||||
Ok(StatusCode::NO_CONTENT)
|
Ok(EmptyResponse)
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ pub async fn set(
|
|||||||
claims: Claims,
|
claims: Claims,
|
||||||
State(pool): State<Pool>,
|
State(pool): State<Pool>,
|
||||||
Json(params): Json<Params>,
|
Json(params): Json<Params>,
|
||||||
) -> GeneralResult<StatusCode> {
|
) -> GeneralResult<EmptyResponse> {
|
||||||
let root = db::folder::get_root(claims.user_id, &pool)
|
let root = db::folder::get_root(claims.user_id, &pool)
|
||||||
.await
|
.await
|
||||||
.handle_internal("Error getting the root folder")?;
|
.handle_internal("Error getting the root folder")?;
|
||||||
@ -53,5 +53,5 @@ pub async fn set(
|
|||||||
.await
|
.await
|
||||||
.handle_internal("Error writing to the database")?;
|
.handle_internal("Error writing to the database")?;
|
||||||
|
|
||||||
Ok(StatusCode::NO_CONTENT)
|
Ok(EmptyResponse)
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub async fn delete(
|
pub async fn delete(
|
||||||
State(AppState { pool, ref storage }): State<AppState>,
|
State(AppState { pool, ref storage }): State<AppState>,
|
||||||
claims: Claims,
|
claims: Claims,
|
||||||
) -> GeneralResult<()> {
|
) -> GeneralResult<EmptyResponse> {
|
||||||
|
tokio::time::sleep(Duration::from_secs(100)).await;
|
||||||
db::users::delete_user(claims.user_id, &pool)
|
db::users::delete_user(claims.user_id, &pool)
|
||||||
.try_for_each_concurrent(5, |file_id| async move {
|
.try_for_each_concurrent(5, |file_id| async move {
|
||||||
let _ = storage.delete(file_id).await;
|
let _ = storage.delete(file_id).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.handle_internal("Error deleting the user")
|
.handle_internal("Error deleting the user")?;
|
||||||
|
|
||||||
|
Ok(EmptyResponse)
|
||||||
}
|
}
|
||||||
|
33
src/main.rs
33
src/main.rs
@ -4,10 +4,8 @@ mod endpoints;
|
|||||||
mod errors;
|
mod errors;
|
||||||
mod file_storage;
|
mod file_storage;
|
||||||
mod prelude;
|
mod prelude;
|
||||||
|
mod util;
|
||||||
|
|
||||||
use std::{env, net::Ipv4Addr};
|
|
||||||
|
|
||||||
use axum::Router;
|
|
||||||
use file_storage::FileStorage;
|
use file_storage::FileStorage;
|
||||||
|
|
||||||
type Pool = sqlx::postgres::PgPool;
|
type Pool = sqlx::postgres::PgPool;
|
||||||
@ -63,6 +61,8 @@ fn init_tracing() {
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
use std::{env, net::Ipv4Addr};
|
||||||
|
|
||||||
if env::var("RUST_BACKTRACE").is_err() {
|
if env::var("RUST_BACKTRACE").is_err() {
|
||||||
env::set_var("RUST_BACKTRACE", "1");
|
env::set_var("RUST_BACKTRACE", "1");
|
||||||
}
|
}
|
||||||
@ -124,7 +124,7 @@ async fn shutdown_signal() {
|
|||||||
ctrl_c.await;
|
ctrl_c.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app(state: AppState) -> Router {
|
fn app(state: AppState) -> axum::Router {
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::DefaultBodyLimit,
|
extract::DefaultBodyLimit,
|
||||||
handler::Handler as _,
|
handler::Handler as _,
|
||||||
@ -137,6 +137,7 @@ fn app(state: AppState) -> Router {
|
|||||||
users,
|
users,
|
||||||
};
|
};
|
||||||
use tower_http::{
|
use tower_http::{
|
||||||
|
timeout::TimeoutLayer,
|
||||||
trace::{MakeSpan, TraceLayer},
|
trace::{MakeSpan, TraceLayer},
|
||||||
ServiceBuilderExt as _,
|
ServiceBuilderExt as _,
|
||||||
};
|
};
|
||||||
@ -160,19 +161,22 @@ fn app(state: AppState) -> Router {
|
|||||||
const TEN_GIBIBYTES: usize = 10 * 1024 * 1024 * 1024;
|
const TEN_GIBIBYTES: usize = 10 * 1024 * 1024 * 1024;
|
||||||
let body_limit = DefaultBodyLimit::max(TEN_GIBIBYTES);
|
let body_limit = DefaultBodyLimit::max(TEN_GIBIBYTES);
|
||||||
|
|
||||||
let middleware = tower::ServiceBuilder::new()
|
let timeout = TimeoutLayer::new(std::time::Duration::from_secs(10));
|
||||||
|
|
||||||
|
let common_middleware = tower::ServiceBuilder::new()
|
||||||
.sensitive_headers([header::AUTHORIZATION, header::COOKIE])
|
.sensitive_headers([header::AUTHORIZATION, header::COOKIE])
|
||||||
.layer(TraceLayer::new_for_http().make_span_with(SpanMaker))
|
.layer(TraceLayer::new_for_http().make_span_with(SpanMaker))
|
||||||
.compression();
|
.compression();
|
||||||
|
|
||||||
Router::new()
|
let file_router = axum::Router::new().route(
|
||||||
.route(
|
"/",
|
||||||
"/files",
|
|
||||||
get(file::download::download)
|
get(file::download::download)
|
||||||
.post(file::upload::upload.layer(body_limit.clone()))
|
.post(file::upload::upload.layer(body_limit.clone()))
|
||||||
.delete(file::delete::delete)
|
.delete(file::delete::delete.layer(timeout))
|
||||||
.patch(file::modify::modify.layer(body_limit)),
|
.patch(file::modify::modify.layer(body_limit.clone())),
|
||||||
)
|
);
|
||||||
|
|
||||||
|
let general_router = axum::Router::new()
|
||||||
.route(
|
.route(
|
||||||
"/folders",
|
"/folders",
|
||||||
get(folder::list::list)
|
get(folder::list::list)
|
||||||
@ -200,6 +204,11 @@ fn app(state: AppState) -> Router {
|
|||||||
.route("/users/search", get(users::search::search))
|
.route("/users/search", get(users::search::search))
|
||||||
.route("/users/register", post(users::register::register))
|
.route("/users/register", post(users::register::register))
|
||||||
.route("/users/authorize", post(users::login::login))
|
.route("/users/authorize", post(users::login::login))
|
||||||
.layer(middleware)
|
.layer(timeout);
|
||||||
|
|
||||||
|
axum::Router::new()
|
||||||
|
.nest("/files", file_router)
|
||||||
|
.nest("/", general_router)
|
||||||
|
.layer(common_middleware)
|
||||||
.with_state(state)
|
.with_state(state)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ pub(crate) use crate::{
|
|||||||
auth::Claims,
|
auth::Claims,
|
||||||
db::{self, permissions::PermissionExt as _},
|
db::{self, permissions::PermissionExt as _},
|
||||||
errors::{ErrorHandlingExt as _, GeneralError, GeneralResult, ItemNotFoundExt as _},
|
errors::{ErrorHandlingExt as _, GeneralError, GeneralResult, ItemNotFoundExt as _},
|
||||||
|
util::EmptyResponse,
|
||||||
AppState, Pool,
|
AppState, Pool,
|
||||||
};
|
};
|
||||||
pub use axum::{
|
pub use axum::{
|
||||||
|
11
src/util.rs
Normal file
11
src/util.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use axum::response::IntoResponse;
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub struct EmptyResponse;
|
||||||
|
|
||||||
|
impl IntoResponse for EmptyResponse {
|
||||||
|
fn into_response(self) -> axum::response::Response {
|
||||||
|
StatusCode::NO_CONTENT.into_response()
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user