mirror of
https://github.com/localsend/localsend.git
synced 2026-06-23 04:10:07 +00:00
refactor: use thiserror
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
use hyper::body::Incoming;
|
||||
use hyper::StatusCode;
|
||||
use http_body_util::BodyExt;
|
||||
use serde::de::DeserializeOwned;
|
||||
use crate::http::server::error::AppError;
|
||||
use http_body_util::BodyExt;
|
||||
use hyper::body::Incoming;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
pub(crate) trait CollectToJson {
|
||||
async fn collect_to_json<T: DeserializeOwned>(self) -> Result<T, AppError>;
|
||||
@@ -13,7 +12,7 @@ impl CollectToJson for Incoming {
|
||||
let bytes = self.collect().await?.to_bytes();
|
||||
serde_json::from_slice::<T>(&bytes).map_err(|err| {
|
||||
tracing::warn!("Failed to parse JSON body: {err:#}");
|
||||
AppError::status(StatusCode::BAD_REQUEST, Some("Invalid JSON body".to_string()))
|
||||
AppError::BadRequest("Invalid JSON body".to_string())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use hyper::body::Incoming;
|
||||
use hyper::StatusCode;
|
||||
use crate::http::dto::{RegisterDto, RegisterResponseDto};
|
||||
use crate::http::server::{AppState, JsonResponse, RequestClientInfo};
|
||||
use crate::http::server::collect_to_json::CollectToJson;
|
||||
use crate::http::server::error::AppError;
|
||||
use crate::http::server::response::JsonResponse;
|
||||
use crate::http::server::{AppState, RequestClientInfo};
|
||||
use hyper::body::Incoming;
|
||||
use hyper::StatusCode;
|
||||
|
||||
pub(crate) async fn register(
|
||||
body: Incoming,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use crate::http::dto::{NonceRequest, NonceResponse, RegisterDto, RegisterResponseDto};
|
||||
use crate::http::server::collect_to_json::CollectToJson;
|
||||
use crate::http::server::error::AppError;
|
||||
use crate::http::server::response::JsonResponse;
|
||||
use crate::http::server::{AppState, RequestClientInfo};
|
||||
use crate::{crypto, util};
|
||||
use hyper::body::Incoming;
|
||||
use hyper::StatusCode;
|
||||
use crate::http::dto::{NonceRequest, NonceResponse, RegisterDto, RegisterResponseDto};
|
||||
use crate::http::server::{AppState, RequestClientInfo, JsonResponse};
|
||||
use crate::http::server::error::AppError;
|
||||
use crate::{crypto, util};
|
||||
use crate::http::server::collect_to_json::CollectToJson;
|
||||
|
||||
pub(crate) async fn nonce_exchange(
|
||||
body: Incoming,
|
||||
@@ -15,18 +16,12 @@ pub(crate) async fn nonce_exchange(
|
||||
|
||||
let nonce = util::base64::decode(&payload.nonce).map_err(|_| {
|
||||
tracing::warn!("Failed to decode nonce from base64");
|
||||
AppError::status(
|
||||
StatusCode::BAD_REQUEST,
|
||||
Some("Invalid nonce format".to_string()),
|
||||
)
|
||||
AppError::BadRequest("Invalid nonce format".to_string())
|
||||
})?;
|
||||
|
||||
if !crypto::nonce::validate_nonce(&nonce) {
|
||||
tracing::warn!("Invalid nonce received");
|
||||
return Err(AppError::status(
|
||||
StatusCode::BAD_REQUEST,
|
||||
Some("Invalid nonce".to_string()),
|
||||
));
|
||||
return Err(AppError::BadRequest("Invalid nonce".to_string()));
|
||||
}
|
||||
|
||||
// Save the nonce
|
||||
|
||||
@@ -1,31 +1,42 @@
|
||||
use hyper::StatusCode;
|
||||
use crate::http::dto::ErrorResponse;
|
||||
use crate::http::server::response::JsonResponse;
|
||||
use bytes::Bytes;
|
||||
use http_body_util::Full;
|
||||
use hyper::{Response, StatusCode};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AppError {
|
||||
pub status: StatusCode,
|
||||
pub message: Option<String>,
|
||||
pub error: Option<anyhow::Error>,
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum AppError {
|
||||
#[error("Hyper error: {0}")]
|
||||
Hyper(#[from] hyper::Error),
|
||||
|
||||
#[error("Status Error: {0}")]
|
||||
Status(StatusCode),
|
||||
|
||||
#[error("Invalid request: {0}")]
|
||||
BadRequest(String),
|
||||
}
|
||||
|
||||
impl AppError {
|
||||
pub fn status(status: StatusCode, message: Option<String>) -> Self {
|
||||
Self {
|
||||
status,
|
||||
message,
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(crate) fn to_response(self) -> Response<Full<Bytes>> {
|
||||
let json = match self {
|
||||
AppError::Hyper(_) => JsonResponse {
|
||||
status: StatusCode::INTERNAL_SERVER_ERROR,
|
||||
body: ErrorResponse {
|
||||
message: "Internal server error".to_string(),
|
||||
},
|
||||
},
|
||||
AppError::Status(code) => JsonResponse {
|
||||
status: code,
|
||||
body: ErrorResponse {
|
||||
message: format!("Status code: {code}"),
|
||||
},
|
||||
},
|
||||
AppError::BadRequest(message) => JsonResponse {
|
||||
status: StatusCode::BAD_REQUEST,
|
||||
body: ErrorResponse { message },
|
||||
},
|
||||
};
|
||||
|
||||
impl<E> From<E> for AppError
|
||||
where
|
||||
E: Into<anyhow::Error>,
|
||||
{
|
||||
fn from(err: E) -> Self {
|
||||
Self {
|
||||
status: StatusCode::INTERNAL_SERVER_ERROR,
|
||||
message: None,
|
||||
error: Some(err.into()),
|
||||
}
|
||||
json.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ mod client_cert_verifier;
|
||||
mod collect_to_json;
|
||||
mod controller;
|
||||
mod error;
|
||||
mod response;
|
||||
|
||||
use crate::crypto::cert::public_key_from_cert_der;
|
||||
use crate::http::dto::ErrorResponse;
|
||||
use crate::http::server::client_cert_verifier::CustomClientCertVerifier;
|
||||
use crate::http::server::controller::web::WebPageState;
|
||||
use crate::http::server::error::AppError;
|
||||
@@ -12,13 +12,12 @@ use crate::http::state::ClientInfo;
|
||||
use bytes::Bytes;
|
||||
use http_body_util::Full;
|
||||
use hyper::body::Incoming;
|
||||
use hyper::{http, Method, Request, Response, StatusCode};
|
||||
use hyper::{Method, Request, Response, StatusCode};
|
||||
use hyper_util::rt::{TokioExecutor, TokioIo};
|
||||
use hyper_util::server::conn::auto::Builder;
|
||||
use lru::LruCache;
|
||||
use rustls::pki_types::pem::PemObject;
|
||||
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
|
||||
use serde::Serialize;
|
||||
use std::fmt::Debug;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
use std::num::NonZeroUsize;
|
||||
@@ -238,57 +237,26 @@ async fn handle_request(
|
||||
.await
|
||||
.unwrap_or_else(|err| {
|
||||
tracing::error!("Error handling request: {err:?}");
|
||||
JsonResponse {
|
||||
status: err.status,
|
||||
body: ErrorResponse {
|
||||
message: err
|
||||
.message
|
||||
.unwrap_or_else(|| "Internal Server Error".to_string()),
|
||||
},
|
||||
}
|
||||
.into_response()
|
||||
err.to_response()
|
||||
}))
|
||||
}
|
||||
|
||||
struct JsonResponse<T: Serialize> {
|
||||
status: StatusCode,
|
||||
body: T,
|
||||
}
|
||||
|
||||
impl<T: Serialize> JsonResponse<T> {
|
||||
fn into_response(self) -> Response<Full<Bytes>> {
|
||||
let mut response = Response::new(Full::default());
|
||||
*response.status_mut() = self.status;
|
||||
|
||||
response.headers_mut().insert(
|
||||
http::header::CONTENT_TYPE,
|
||||
http::HeaderValue::from_static("application/json"),
|
||||
);
|
||||
|
||||
*response.body_mut() = Full::from(Bytes::from(
|
||||
serde_json::to_string(&self.body).unwrap_or_else(|_| "{}".to_string()),
|
||||
));
|
||||
|
||||
response
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_request_inner(
|
||||
mut req: Request<Incoming>,
|
||||
legacy_enabled: bool,
|
||||
) -> Result<Response<Full<Bytes>>, AppError> {
|
||||
let Some(state) = req.extensions_mut().remove::<AppState>() else {
|
||||
return Err(AppError::status(StatusCode::INTERNAL_SERVER_ERROR, None));
|
||||
return Err(AppError::Status(StatusCode::INTERNAL_SERVER_ERROR));
|
||||
};
|
||||
|
||||
let Some(client_info) = req.extensions_mut().remove::<RequestClientInfo>() else {
|
||||
return Err(AppError::status(StatusCode::INTERNAL_SERVER_ERROR, None));
|
||||
return Err(AppError::Status(StatusCode::INTERNAL_SERVER_ERROR));
|
||||
};
|
||||
|
||||
match (req.method(), req.uri().path()) {
|
||||
(&Method::POST, "/api/localsend/v2/register") => {
|
||||
if !legacy_enabled {
|
||||
return Err(AppError::status(StatusCode::NOT_FOUND, None));
|
||||
return Err(AppError::Status(StatusCode::NOT_FOUND));
|
||||
}
|
||||
|
||||
Ok(
|
||||
@@ -299,7 +267,7 @@ async fn handle_request_inner(
|
||||
}
|
||||
(&Method::POST, "/api/localsend/v2/prepare-upload") => {
|
||||
if !legacy_enabled {
|
||||
return Err(AppError::status(StatusCode::NOT_FOUND, None));
|
||||
return Err(AppError::Status(StatusCode::NOT_FOUND));
|
||||
}
|
||||
|
||||
Ok(
|
||||
@@ -310,7 +278,7 @@ async fn handle_request_inner(
|
||||
}
|
||||
(&Method::POST, "/api/localsend/v2/upload") => {
|
||||
if !legacy_enabled {
|
||||
return Err(AppError::status(StatusCode::NOT_FOUND, None));
|
||||
return Err(AppError::Status(StatusCode::NOT_FOUND));
|
||||
}
|
||||
|
||||
Ok(
|
||||
@@ -321,7 +289,7 @@ async fn handle_request_inner(
|
||||
}
|
||||
(&Method::POST, "/api/localsend/v2/cancel") => {
|
||||
if !legacy_enabled {
|
||||
return Err(AppError::status(StatusCode::NOT_FOUND, None));
|
||||
return Err(AppError::Status(StatusCode::NOT_FOUND));
|
||||
}
|
||||
|
||||
Ok(
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
use bytes::Bytes;
|
||||
use http_body_util::Full;
|
||||
use hyper::{http, Response, StatusCode};
|
||||
use serde::Serialize;
|
||||
|
||||
pub(crate) struct JsonResponse<T: Serialize> {
|
||||
pub(crate) status: StatusCode,
|
||||
pub(crate) body: T,
|
||||
}
|
||||
|
||||
impl<T: Serialize> JsonResponse<T> {
|
||||
pub(crate) fn into_response(self) -> Response<Full<Bytes>> {
|
||||
let mut response = Response::new(Full::default());
|
||||
*response.status_mut() = self.status;
|
||||
|
||||
response.headers_mut().insert(
|
||||
http::header::CONTENT_TYPE,
|
||||
http::HeaderValue::from_static("application/json"),
|
||||
);
|
||||
|
||||
*response.body_mut() = Full::from(Bytes::from(
|
||||
serde_json::to_string(&self.body).unwrap_or_else(|_| "{}".to_string()),
|
||||
));
|
||||
|
||||
response
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user