Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typed catchers #2814

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
6 changes: 3 additions & 3 deletions contrib/db_pools/codegen/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ pub fn derive_database(input: TokenStream) -> TokenStream {

#[rocket::async_trait]
impl<'r> rocket::request::FromRequest<'r> for &'r #decorated_type {
type Error = ();
type Error = rocket::http::Status;

async fn from_request(
req: &'r rocket::request::Request<'_>
) -> rocket::request::Outcome<Self, Self::Error> {
match #db_ty::fetch(req.rocket()) {
Some(db) => rocket::outcome::Outcome::Success(db),
None => rocket::outcome::Outcome::Error((
rocket::http::Status::InternalServerError, ()))
None => rocket::outcome::Outcome::Error(
rocket::http::Status::InternalServerError)
}
}
}
Expand Down
29 changes: 25 additions & 4 deletions contrib/db_pools/lib/src/database.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};

use rocket::catcher::{Static, TypedError};
use rocket::{error, Build, Ignite, Phase, Rocket, Sentinel, Orbit};
use rocket::fairing::{self, Fairing, Info, Kind};
use rocket::request::{FromRequest, Outcome, Request};
Expand Down Expand Up @@ -278,17 +279,37 @@ impl<D: Database> Fairing for Initializer<D> {
}
}

/// Possible errors when aquiring a database connection
#[derive(Debug, PartialEq, Eq)]
pub enum DbError<E> {
ServiceUnavailable(E),
InternalError,
}

impl<E: 'static> Static for DbError<E> {}

impl<'r, E: Send + Sync + 'static> TypedError<'r> for DbError<E> {
fn status(&self) -> Status {
match self {
Self::ServiceUnavailable(_) => Status::ServiceUnavailable,
Self::InternalError => Status::InternalServerError,
}
}
}

#[rocket::async_trait]
impl<'r, D: Database> FromRequest<'r> for Connection<D> {
type Error = Option<<D::Pool as Pool>::Error>;
impl<'r, D: Database> FromRequest<'r> for Connection<D>
where <D::Pool as Pool>::Error: Send + Sync + 'static
{
type Error = DbError<<D::Pool as Pool>::Error>;

async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
match D::fetch(req.rocket()) {
Some(db) => match db.get().await {
Ok(conn) => Outcome::Success(Connection(conn)),
Err(e) => Outcome::Error((Status::ServiceUnavailable, Some(e))),
Err(e) => Outcome::Error(DbError::ServiceUnavailable(e)),
},
None => Outcome::Error((Status::InternalServerError, None)),
None => Outcome::Error(DbError::InternalError),
}
}
}
Expand Down
20 changes: 11 additions & 9 deletions contrib/dyn_templates/src/metadata.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::fmt;
use std::borrow::Cow;

use rocket::{Request, Rocket, Ignite, Sentinel};
use rocket::http::{Status, ContentType};
use rocket::outcome::Outcome;
use rocket::{Ignite, Request, Rocket, Sentinel, StateMissing};
use rocket::http::ContentType;
use rocket::request::{self, FromRequest};
use rocket::serde::Serialize;

Expand Down Expand Up @@ -152,18 +153,19 @@ impl Sentinel for Metadata<'_> {
/// (`500`) is returned.
#[rocket::async_trait]
impl<'r> FromRequest<'r> for Metadata<'r> {
type Error = ();
type Error = StateMissing;

async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, ()> {
request.rocket().state::<ContextManager>()
.map(|cm| request::Outcome::Success(Metadata(cm)))
.unwrap_or_else(|| {
async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
match request.rocket().state::<ContextManager>() {
Some(cm) => Outcome::Success(Metadata(cm)),
None => {
error!(
"uninitialized template context: missing `Template::fairing()`.\n\
To use templates, you must attach `Template::fairing()`."
);

request::Outcome::Error((Status::InternalServerError, ()))
})
request::Outcome::Error(StateMissing("Template::fairing()"))
}
}
}
}
2 changes: 1 addition & 1 deletion contrib/dyn_templates/src/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ impl Template {
/// extension and a fixed-size body containing the rendered template. If
/// rendering fails, an `Err` of `Status::InternalServerError` is returned.
impl<'r> Responder<'r, 'static> for Template {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'r, 'static> {
let ctxt = req.rocket()
.state::<ContextManager>()
.ok_or_else(|| {
Expand Down
4 changes: 2 additions & 2 deletions contrib/sync_db_pools/codegen/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@ pub fn database_attr(attr: TokenStream, input: TokenStream) -> Result<TokenStrea

#[#rocket::async_trait]
impl<'r> #rocket::request::FromRequest<'r> for #guard_type {
type Error = ();
type Error = ::rocket_sync_db_pools::ConnectionMissing;

async fn from_request(
__r: &'r #rocket::request::Request<'_>
) -> #rocket::request::Outcome<Self, ()> {
) -> #rocket::request::Outcome<Self, Self::Error> {
<#conn>::from_request(__r).await.map(Self)
}
}
Expand Down
22 changes: 17 additions & 5 deletions contrib/sync_db_pools/lib/src/connection.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::any::type_name;
use std::sync::Arc;
use std::marker::PhantomData;

use rocket::catcher::{Static, TypedError};
use rocket::{Phase, Rocket, Ignite, Sentinel};
use rocket::fairing::{AdHoc, Fairing};
use rocket::request::{Request, Outcome, FromRequest};
Expand Down Expand Up @@ -221,19 +223,29 @@ impl<K, C: Poolable> Drop for ConnectionPool<K, C> {
}
}

/// Error for a managed state element not being present.
#[derive(Debug, PartialEq, Eq)]
pub struct ConnectionMissing(pub &'static str);

impl Static for ConnectionMissing {}

impl<'r> TypedError<'r> for ConnectionMissing {
fn status(&self) -> Status { Status::InternalServerError }
}

#[rocket::async_trait]
impl<'r, K: 'static, C: Poolable> FromRequest<'r> for Connection<K, C> {
type Error = ();
type Error = ConnectionMissing;

#[inline]
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, ()> {
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
match request.rocket().state::<ConnectionPool<K, C>>() {
Some(c) => c.get().await.or_error((Status::ServiceUnavailable, ())),
Some(c) => c.get().await.or_error(ConnectionMissing(type_name::<K>())),
None => {
let conn = std::any::type_name::<K>();
let conn = type_name::<K>();
error!("`{conn}::fairing()` is not attached\n\
the fairing must be attached to use `{conn} in routes.");
Outcome::Error((Status::InternalServerError, ()))
Outcome::Error(ConnectionMissing(type_name::<K>()))
}
}
}
Expand Down
Loading
Loading