innernet/server/src/error.rs

70 lines
1.9 KiB
Rust

use std::convert::TryFrom;
use hyper::{http, Body, Response, StatusCode};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ServerError {
#[error("unauthorized access")]
Unauthorized,
#[error("object not found")]
NotFound,
#[error("invalid query")]
InvalidQuery,
#[error("endpoint gone")]
Gone,
#[error("internal database error")]
Database(#[from] rusqlite::Error),
#[error("internal WireGuard error")]
WireGuard,
#[error("internal I/O error")]
Io(#[from] std::io::Error),
#[error("JSON parsing/serialization error")]
Json(#[from] serde_json::Error),
#[error("Generic HTTP error")]
Http(#[from] http::Error),
#[error("Generic Hyper error")]
Hyper(#[from] hyper::Error),
}
impl<'a> From<&'a ServerError> for StatusCode {
fn from(error: &ServerError) -> StatusCode {
use ServerError::*;
match error {
Unauthorized => StatusCode::UNAUTHORIZED,
NotFound => StatusCode::NOT_FOUND,
Gone => StatusCode::GONE,
InvalidQuery | Json(_) => StatusCode::BAD_REQUEST,
// Special-case the constraint violation situation.
Database(rusqlite::Error::SqliteFailure(libsqlite3_sys::Error { code, .. }, ..))
if *code == libsqlite3_sys::ErrorCode::ConstraintViolation =>
{
StatusCode::BAD_REQUEST
},
Database(rusqlite::Error::QueryReturnedNoRows) => StatusCode::NOT_FOUND,
WireGuard | Io(_) | Database(_) | Http(_) | Hyper(_) => {
StatusCode::INTERNAL_SERVER_ERROR
},
}
}
}
impl TryFrom<ServerError> for Response<Body> {
type Error = http::Error;
fn try_from(e: ServerError) -> Result<Self, Self::Error> {
Response::builder()
.status(StatusCode::from(&e))
.body(Body::empty())
}
}