mirror of https://github.com/rwf2/Rocket.git
Remove 'Error' panic-on-drop behavior.
Instead, the `#[launch]` attribute traces the error and panics, replicating the old behavior in the common case.
This commit is contained in:
parent
8a1c91b7d5
commit
d767694861
|
@ -1,5 +1,6 @@
|
||||||
use rocket::{Rocket, Build, Orbit};
|
use rocket::{Rocket, Build, Orbit};
|
||||||
use rocket::fairing::{self, Fairing, Info, Kind};
|
use rocket::fairing::{self, Fairing, Info, Kind};
|
||||||
|
use rocket::figment::{Source, value::magic::RelativePathBuf};
|
||||||
|
|
||||||
use crate::context::{Callback, Context, ContextManager};
|
use crate::context::{Callback, Context, ContextManager};
|
||||||
use crate::template::DEFAULT_TEMPLATE_DIR;
|
use crate::template::DEFAULT_TEMPLATE_DIR;
|
||||||
|
@ -31,8 +32,6 @@ impl Fairing for TemplateFairing {
|
||||||
/// template engines. In debug mode, the `ContextManager::new` method
|
/// template engines. In debug mode, the `ContextManager::new` method
|
||||||
/// initializes a directory watcher for auto-reloading of templates.
|
/// initializes a directory watcher for auto-reloading of templates.
|
||||||
async fn on_ignite(&self, rocket: Rocket<Build>) -> fairing::Result {
|
async fn on_ignite(&self, rocket: Rocket<Build>) -> fairing::Result {
|
||||||
use rocket::figment::value::magic::RelativePathBuf;
|
|
||||||
|
|
||||||
let configured_dir = rocket.figment()
|
let configured_dir = rocket.figment()
|
||||||
.extract_inner::<RelativePathBuf>("template_dir")
|
.extract_inner::<RelativePathBuf>("template_dir")
|
||||||
.map(|path| path.relative());
|
.map(|path| path.relative());
|
||||||
|
@ -55,14 +54,13 @@ impl Fairing for TemplateFairing {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_liftoff(&self, rocket: &Rocket<Orbit>) {
|
async fn on_liftoff(&self, rocket: &Rocket<Orbit>) {
|
||||||
use rocket::{figment::Source, yansi::Paint};
|
|
||||||
|
|
||||||
let cm = rocket.state::<ContextManager>()
|
let cm = rocket.state::<ContextManager>()
|
||||||
.expect("Template ContextManager registered in on_ignite");
|
.expect("Template ContextManager registered in on_ignite");
|
||||||
|
|
||||||
info!("{}{}:", "📐 ".emoji(), "Templating".magenta());
|
info_span!("templating" [icon = "📐"] => {
|
||||||
info_!("directory: {}", Source::from(&*cm.context().root).primary());
|
info!(directory = %Source::from(&*cm.context().root));
|
||||||
info_!("engines: {:?}", Engines::ENABLED_EXTENSIONS.primary());
|
info!(engines = ?Engines::ENABLED_EXTENSIONS);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
@ -72,5 +70,4 @@ impl Fairing for TemplateFairing {
|
||||||
|
|
||||||
cm.reload_if_needed(&self.callback);
|
cm.reload_if_needed(&self.callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use proc_macro2::{TokenStream, Span};
|
||||||
|
|
||||||
use super::EntryAttr;
|
use super::EntryAttr;
|
||||||
use crate::attribute::suppress::Lint;
|
use crate::attribute::suppress::Lint;
|
||||||
use crate::exports::mixed;
|
use crate::exports::{mixed, _error, _ExitCode};
|
||||||
|
|
||||||
/// `#[rocket::launch]`: generates a `main` function that calls the attributed
|
/// `#[rocket::launch]`: generates a `main` function that calls the attributed
|
||||||
/// function to generate a `Rocket` instance. Then calls `.launch()` on the
|
/// function to generate a `Rocket` instance. Then calls `.launch()` on the
|
||||||
|
@ -106,14 +106,14 @@ impl EntryAttr for Launch {
|
||||||
|
|
||||||
let (vis, mut sig) = (&f.vis, f.sig.clone());
|
let (vis, mut sig) = (&f.vis, f.sig.clone());
|
||||||
sig.ident = syn::Ident::new("main", sig.ident.span());
|
sig.ident = syn::Ident::new("main", sig.ident.span());
|
||||||
sig.output = syn::ReturnType::Default;
|
sig.output = syn::parse_quote!(-> #_ExitCode);
|
||||||
sig.asyncness = None;
|
sig.asyncness = None;
|
||||||
|
|
||||||
Ok(quote_spanned!(block.span() =>
|
Ok(quote_spanned!(block.span() =>
|
||||||
#[allow(dead_code)] #f
|
#[allow(dead_code)] #f
|
||||||
|
|
||||||
#vis #sig {
|
#vis #sig {
|
||||||
let _ = ::rocket::async_main(#launch);
|
#_error::Error::report(::rocket::async_main(#launch))
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ define_exported_paths! {
|
||||||
_request => ::rocket::request,
|
_request => ::rocket::request,
|
||||||
_response => ::rocket::response,
|
_response => ::rocket::response,
|
||||||
_route => ::rocket::route,
|
_route => ::rocket::route,
|
||||||
|
_error => ::rocket::error,
|
||||||
_catcher => ::rocket::catcher,
|
_catcher => ::rocket::catcher,
|
||||||
_sentinel => ::rocket::sentinel,
|
_sentinel => ::rocket::sentinel,
|
||||||
_form => ::rocket::form::prelude,
|
_form => ::rocket::form::prelude,
|
||||||
|
@ -84,6 +85,7 @@ define_exported_paths! {
|
||||||
_Box => ::std::boxed::Box,
|
_Box => ::std::boxed::Box,
|
||||||
_Vec => ::std::vec::Vec,
|
_Vec => ::std::vec::Vec,
|
||||||
_Cow => ::std::borrow::Cow,
|
_Cow => ::std::borrow::Cow,
|
||||||
|
_ExitCode => ::std::process::ExitCode,
|
||||||
BorrowMut => ::std::borrow::BorrowMut,
|
BorrowMut => ::std::borrow::BorrowMut,
|
||||||
Outcome => ::rocket::outcome::Outcome,
|
Outcome => ::rocket::outcome::Outcome,
|
||||||
FromForm => ::rocket::form::FromForm,
|
FromForm => ::rocket::form::FromForm,
|
||||||
|
|
|
@ -433,7 +433,7 @@ pub fn bail_with_config_error<T>(error: figment::Error) -> T {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
// FIXME: Remove this funtion.
|
// FIXME: Remove this function.
|
||||||
pub fn pretty_print_error(error: figment::Error) {
|
pub fn pretty_print_error(error: figment::Error) {
|
||||||
error.trace_error()
|
error.trace_error()
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,24 +340,22 @@ fn test_precedence() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "secrets")]
|
#[cfg(feature = "secrets")]
|
||||||
#[should_panic]
|
|
||||||
fn test_err_on_non_debug_and_no_secret_key() {
|
fn test_err_on_non_debug_and_no_secret_key() {
|
||||||
figment::Jail::expect_with(|jail| {
|
figment::Jail::expect_with(|jail| {
|
||||||
jail.set_env("ROCKET_PROFILE", "release");
|
jail.set_env("ROCKET_PROFILE", "release");
|
||||||
let rocket = crate::custom(Config::figment());
|
let rocket = crate::custom(Config::figment());
|
||||||
let _result = crate::local::blocking::Client::untracked(rocket);
|
crate::local::blocking::Client::untracked(rocket).expect_err("release secret key");
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "secrets")]
|
#[cfg(feature = "secrets")]
|
||||||
#[should_panic]
|
|
||||||
fn test_err_on_non_debug2_and_no_secret_key() {
|
fn test_err_on_non_debug2_and_no_secret_key() {
|
||||||
figment::Jail::expect_with(|jail| {
|
figment::Jail::expect_with(|jail| {
|
||||||
jail.set_env("ROCKET_PROFILE", "boop");
|
jail.set_env("ROCKET_PROFILE", "boop");
|
||||||
let rocket = crate::custom(Config::figment());
|
let rocket = crate::custom(Config::figment());
|
||||||
let _result = crate::local::blocking::Client::tracked(rocket);
|
crate::local::blocking::Client::tracked(rocket).expect_err("boop secret key");
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +1,20 @@
|
||||||
//! Types representing various errors that can occur in a Rocket application.
|
//! Types representing various errors that can occur in a Rocket application.
|
||||||
|
|
||||||
use std::{io, fmt};
|
use std::{io, fmt, process};
|
||||||
use std::sync::{Arc, atomic::{Ordering, AtomicBool}};
|
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use yansi::Paint;
|
|
||||||
use figment::Profile;
|
use figment::Profile;
|
||||||
|
|
||||||
use crate::listener::Endpoint;
|
use crate::listener::Endpoint;
|
||||||
use crate::{Ignite, Orbit, Rocket};
|
use crate::trace::traceable::Traceable;
|
||||||
|
use crate::{Ignite, Orbit, Phase, Rocket};
|
||||||
|
|
||||||
/// An error that occurs during launch.
|
/// An error that occurs during launch.
|
||||||
///
|
///
|
||||||
/// An `Error` is returned by [`launch()`](Rocket::launch()) when launching an
|
/// An `Error` is returned by [`launch()`](Rocket::launch()) when launching an
|
||||||
/// application fails or, more rarely, when the runtime fails after launching.
|
/// application fails or, more rarely, when the runtime fails after launching.
|
||||||
///
|
///
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// A value of this type panics if it is dropped without first being inspected.
|
|
||||||
/// An _inspection_ occurs when any method is called. For instance, if
|
|
||||||
/// `println!("Error: {}", e)` is called, where `e: Error`, the `Display::fmt`
|
|
||||||
/// method being called by `println!` results in `e` being marked as inspected;
|
|
||||||
/// a subsequent `drop` of the value will _not_ result in a panic. The following
|
|
||||||
/// snippet illustrates this:
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # let _ = async {
|
|
||||||
/// if let Err(error) = rocket::build().launch().await {
|
|
||||||
/// // This println "inspects" the error.
|
|
||||||
/// println!("Launch failed! Error: {}", error);
|
|
||||||
///
|
|
||||||
/// // This call to drop (explicit here for demonstration) will do nothing.
|
|
||||||
/// drop(error);
|
|
||||||
/// }
|
|
||||||
/// # };
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// When a value of this type panics, the corresponding error message is pretty
|
|
||||||
/// printed to the console. The following illustrates this:
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # let _ = async {
|
|
||||||
/// let error = rocket::build().launch().await;
|
|
||||||
///
|
|
||||||
/// // This call to drop (explicit here for demonstration) will result in
|
|
||||||
/// // `error` being pretty-printed to the console along with a `panic!`.
|
|
||||||
/// drop(error);
|
|
||||||
/// # };
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Usage
|
/// # Usage
|
||||||
///
|
///
|
||||||
/// An `Error` value should usually be allowed to `drop` without inspection.
|
/// An `Error` value should usually be allowed to `drop` without inspection.
|
||||||
|
@ -61,8 +27,7 @@ use crate::{Ignite, Orbit, Rocket};
|
||||||
///
|
///
|
||||||
/// 2. You want to display your own error messages.
|
/// 2. You want to display your own error messages.
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
handled: AtomicBool,
|
pub(crate) kind: ErrorKind
|
||||||
kind: ErrorKind
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The kind error that occurred.
|
/// The kind error that occurred.
|
||||||
|
@ -74,6 +39,7 @@ pub struct Error {
|
||||||
/// `FailedFairing` variants, respectively.
|
/// `FailedFairing` variants, respectively.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
|
// FIXME: Don't expose this. Expose access methods from `Error` instead.
|
||||||
pub enum ErrorKind {
|
pub enum ErrorKind {
|
||||||
/// Binding to the network interface at `.0` failed with error `.1`.
|
/// Binding to the network interface at `.0` failed with error `.1`.
|
||||||
Bind(Option<Endpoint>, Box<dyn StdError + Send>),
|
Bind(Option<Endpoint>, Box<dyn StdError + Send>),
|
||||||
|
@ -93,7 +59,7 @@ pub enum ErrorKind {
|
||||||
/// Liftoff failed. Contains the Rocket instance that failed to shutdown.
|
/// Liftoff failed. Contains the Rocket instance that failed to shutdown.
|
||||||
Liftoff(
|
Liftoff(
|
||||||
Result<Box<Rocket<Ignite>>, Arc<Rocket<Orbit>>>,
|
Result<Box<Rocket<Ignite>>, Arc<Rocket<Orbit>>>,
|
||||||
Box<dyn StdError + Send + 'static>
|
tokio::task::JoinError,
|
||||||
),
|
),
|
||||||
/// Shutdown failed. Contains the Rocket instance that failed to shutdown.
|
/// Shutdown failed. Contains the Rocket instance that failed to shutdown.
|
||||||
Shutdown(Arc<Rocket<Orbit>>),
|
Shutdown(Arc<Rocket<Orbit>>),
|
||||||
|
@ -103,6 +69,28 @@ pub enum ErrorKind {
|
||||||
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct Empty;
|
pub struct Empty;
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn new(kind: ErrorKind) -> Error {
|
||||||
|
Error { kind }
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Don't expose this. Expose finer access methods instead.
|
||||||
|
pub fn kind(&self) -> &ErrorKind {
|
||||||
|
&self.kind
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn report<P: Phase>(result: Result<Rocket<P>, Error>) -> process::ExitCode {
|
||||||
|
match result {
|
||||||
|
Ok(_) => process::ExitCode::SUCCESS,
|
||||||
|
Err(e) => {
|
||||||
|
error_span!("aborting launch due to error" => e.trace_error());
|
||||||
|
process::ExitCode::SUCCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<ErrorKind> for Error {
|
impl From<ErrorKind> for Error {
|
||||||
fn from(kind: ErrorKind) -> Self {
|
fn from(kind: ErrorKind) -> Self {
|
||||||
Error::new(kind)
|
Error::new(kind)
|
||||||
|
@ -121,139 +109,21 @@ impl From<io::Error> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl StdError for Error {
|
||||||
#[inline(always)]
|
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||||
pub(crate) fn new(kind: ErrorKind) -> Error {
|
match &self.kind {
|
||||||
Error { handled: AtomicBool::new(false), kind }
|
ErrorKind::Bind(_, e) => Some(&**e),
|
||||||
}
|
ErrorKind::Io(e) => Some(e),
|
||||||
|
ErrorKind::Collisions(_) => None,
|
||||||
#[inline(always)]
|
ErrorKind::FailedFairings(_) => None,
|
||||||
fn was_handled(&self) -> bool {
|
ErrorKind::InsecureSecretKey(_) => None,
|
||||||
self.handled.load(Ordering::Acquire)
|
ErrorKind::Config(e) => Some(e),
|
||||||
}
|
ErrorKind::SentinelAborts(_) => None,
|
||||||
|
ErrorKind::Liftoff(_, e) => Some(e),
|
||||||
#[inline(always)]
|
ErrorKind::Shutdown(_) => None,
|
||||||
fn mark_handled(&self) {
|
|
||||||
self.handled.store(true, Ordering::Release)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve the `kind` of the launch error.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// use rocket::error::ErrorKind;
|
|
||||||
///
|
|
||||||
/// # let _ = async {
|
|
||||||
/// if let Err(error) = rocket::build().launch().await {
|
|
||||||
/// match error.kind() {
|
|
||||||
/// ErrorKind::Io(e) => println!("found an i/o launch error: {}", e),
|
|
||||||
/// e => println!("something else happened: {}", e)
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// # };
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn kind(&self) -> &ErrorKind {
|
|
||||||
self.mark_handled();
|
|
||||||
&self.kind
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prints the error with color (if enabled) and detail. Returns a string
|
|
||||||
/// that indicates the abort condition such as "aborting due to i/o error".
|
|
||||||
///
|
|
||||||
/// This function is called on `Drop` to display the error message. By
|
|
||||||
/// contrast, the `Display` implementation prints a succinct version of the
|
|
||||||
/// error, without detail.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # let _ = async {
|
|
||||||
/// if let Err(error) = rocket::build().launch().await {
|
|
||||||
/// let abort = error.pretty_print();
|
|
||||||
/// panic!("{}", abort);
|
|
||||||
/// }
|
|
||||||
/// # };
|
|
||||||
/// ```
|
|
||||||
// FIXME: Remove `Error` panicking behavior. Make display/debug better.
|
|
||||||
pub fn pretty_print(&self) -> &'static str {
|
|
||||||
self.mark_handled();
|
|
||||||
match self.kind() {
|
|
||||||
ErrorKind::Bind(ref a, ref e) => {
|
|
||||||
if let Some(e) = e.downcast_ref::<Self>() {
|
|
||||||
e.pretty_print()
|
|
||||||
} else {
|
|
||||||
match a {
|
|
||||||
Some(a) => error!("Binding to {} failed.", a.primary().underline()),
|
|
||||||
None => error!("Binding to network interface failed."),
|
|
||||||
}
|
|
||||||
|
|
||||||
info_!("{}", e);
|
|
||||||
"aborting due to bind error"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ErrorKind::Io(ref e) => {
|
|
||||||
error!("Rocket failed to launch due to an I/O error.");
|
|
||||||
info_!("{}", e);
|
|
||||||
"aborting due to i/o error"
|
|
||||||
}
|
|
||||||
ErrorKind::Collisions(ref collisions) => {
|
|
||||||
fn log_collisions<T: fmt::Display>(kind: &str, collisions: &[(T, T)]) {
|
|
||||||
if collisions.is_empty() { return }
|
|
||||||
|
|
||||||
error!("Rocket failed to launch due to the following {} collisions:", kind);
|
|
||||||
for (a, b) in collisions {
|
|
||||||
info_!("{} {} {}", a, "collides with".red().italic(), b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log_collisions("route", &collisions.routes);
|
|
||||||
log_collisions("catcher", &collisions.catchers);
|
|
||||||
|
|
||||||
info_!("Note: Route collisions can usually be resolved by ranking routes.");
|
|
||||||
"aborting due to detected routing collisions"
|
|
||||||
}
|
|
||||||
ErrorKind::FailedFairings(ref failures) => {
|
|
||||||
error!("Rocket failed to launch due to failing fairings:");
|
|
||||||
for fairing in failures {
|
|
||||||
info_!("{}", fairing.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
"aborting due to fairing failure(s)"
|
|
||||||
}
|
|
||||||
ErrorKind::InsecureSecretKey(profile) => {
|
|
||||||
error!("secrets enabled in non-debug without `secret_key`");
|
|
||||||
info_!("selected profile: {}", profile.primary().bold());
|
|
||||||
info_!("disable `secrets` feature or configure a `secret_key`");
|
|
||||||
"aborting due to insecure configuration"
|
|
||||||
}
|
|
||||||
ErrorKind::Config(error) => {
|
|
||||||
crate::config::pretty_print_error(error.clone());
|
|
||||||
"aborting due to invalid configuration"
|
|
||||||
}
|
|
||||||
ErrorKind::SentinelAborts(ref errors) => {
|
|
||||||
error!("Rocket failed to launch due to aborting sentinels:");
|
|
||||||
for sentry in errors {
|
|
||||||
let name = sentry.type_name.primary().bold();
|
|
||||||
let (file, line, col) = sentry.location;
|
|
||||||
info_!("{} ({}:{}:{})", name, file, line, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
"aborting due to sentinel-triggered abort(s)"
|
|
||||||
}
|
|
||||||
ErrorKind::Liftoff(_, error) => {
|
|
||||||
error!("Rocket liftoff failed due to panicking liftoff fairing(s).");
|
|
||||||
error_!("{error}");
|
|
||||||
"aborting due to failed liftoff"
|
|
||||||
}
|
|
||||||
ErrorKind::Shutdown(_) => {
|
|
||||||
error!("Rocket failed to shutdown gracefully.");
|
|
||||||
"aborting due to failed shutdown"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl std::error::Error for Error { }
|
|
||||||
|
|
||||||
impl fmt::Display for ErrorKind {
|
impl fmt::Display for ErrorKind {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -275,27 +145,14 @@ impl fmt::Display for ErrorKind {
|
||||||
impl fmt::Debug for Error {
|
impl fmt::Debug for Error {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
self.mark_handled();
|
self.kind.fmt(f)
|
||||||
self.kind().fmt(f)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
self.mark_handled();
|
write!(f, "{}", self.kind)
|
||||||
write!(f, "{}", self.kind())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Error {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
// Don't panic if the message has been seen. Don't double-panic.
|
|
||||||
if self.was_handled() || std::thread::panicking() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
panic!("{}", self.pretty_print());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ use std::borrow::Cow;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
|
|
||||||
use yansi::Paint;
|
|
||||||
use state::{TypeMap, InitCell};
|
use state::{TypeMap, InitCell};
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
use ref_swap::OptionRefSwap;
|
use ref_swap::OptionRefSwap;
|
||||||
|
@ -1203,20 +1202,3 @@ impl fmt::Debug for Request<'_> {
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Remov me to identify dependent `TRACE` statements.
|
|
||||||
impl fmt::Display for Request<'_> {
|
|
||||||
/// Pretty prints a Request. Primarily used by Rocket's logging.
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{} {}", self.method().green(), self.uri.blue())?;
|
|
||||||
|
|
||||||
// Print the requests media type when the route specifies a format.
|
|
||||||
if let Some(mime) = self.format() {
|
|
||||||
if !mime.is_any() {
|
|
||||||
write!(f, " {}/{}", mime.top().yellow().linger(), mime.sub().resetting())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -687,7 +687,7 @@ impl Rocket<Ignite> {
|
||||||
rocket.shutdown.spawn_listener(&rocket.config.shutdown);
|
rocket.shutdown.spawn_listener(&rocket.config.shutdown);
|
||||||
if let Err(e) = tokio::spawn(Rocket::liftoff(rocket.clone())).await {
|
if let Err(e) = tokio::spawn(Rocket::liftoff(rocket.clone())).await {
|
||||||
let rocket = rocket.try_wait_shutdown().await.map(Box::new);
|
let rocket = rocket.try_wait_shutdown().await.map(Box::new);
|
||||||
return Err(ErrorKind::Liftoff(rocket, Box::new(e)).into());
|
return Err(ErrorKind::Liftoff(rocket, e).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(rocket)
|
Ok(rocket)
|
||||||
|
|
|
@ -125,8 +125,8 @@ impl Rocket<Ignite> {
|
||||||
let http12 = tokio::task::spawn(rocket.clone().serve12(listener));
|
let http12 = tokio::task::spawn(rocket.clone().serve12(listener));
|
||||||
let http3 = tokio::task::spawn(rocket.clone().serve3(h3listener));
|
let http3 = tokio::task::spawn(rocket.clone().serve3(h3listener));
|
||||||
let (r1, r2) = tokio::join!(http12, http3);
|
let (r1, r2) = tokio::join!(http12, http3);
|
||||||
r1.map_err(|e| ErrorKind::Liftoff(Err(rocket.clone()), Box::new(e)))??;
|
r1.map_err(|e| ErrorKind::Liftoff(Err(rocket.clone()), e))??;
|
||||||
r2.map_err(|e| ErrorKind::Liftoff(Err(rocket.clone()), Box::new(e)))??;
|
r2.map_err(|e| ErrorKind::Liftoff(Err(rocket.clone()), e))??;
|
||||||
return Ok(rocket);
|
return Ok(rocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,7 @@ macro_rules! declare_macro {
|
||||||
([$d:tt] $name:ident $level:ident) => (
|
([$d:tt] $name:ident $level:ident) => (
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! $name {
|
macro_rules! $name {
|
||||||
($d ($t:tt)*) => ({
|
($d ($t:tt)*) => ($crate::tracing::$level!($d ($t)*));
|
||||||
#[allow(unused_imports)]
|
|
||||||
use $crate::trace::macros::PaintExt as _;
|
|
||||||
$crate::tracing::$level!($d ($t)*);
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -45,14 +41,31 @@ macro_rules! declare_span_macro {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! $name {
|
macro_rules! $name {
|
||||||
($n:literal $d ([ $d ($f:tt)* ])? => $in_scope:expr) => ({
|
($n:literal $d ([ $d ($f:tt)* ])? => $in_scope:expr) => ({
|
||||||
$crate::tracing::span!(tracing::Level::$level, $n $d (, $d ($f)* )?)
|
$crate::tracing::span!($crate::tracing::Level::$level, $n $d (, $d ($f)* )?)
|
||||||
.in_scope(|| $in_scope);
|
.in_scope(|| $in_scope);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_span_macro!(info_span INFO, trace_span TRACE, debug_span DEBUG);
|
declare_span_macro!(error_span ERROR, info_span INFO, trace_span TRACE, debug_span DEBUG);
|
||||||
|
|
||||||
|
macro_rules! span {
|
||||||
|
($level:expr, $($args:tt)*) => {{
|
||||||
|
match $level {
|
||||||
|
$crate::tracing::Level::ERROR =>
|
||||||
|
$crate::tracing::span!($crate::tracing::Level::ERROR, $($args)*),
|
||||||
|
$crate::tracing::Level::WARN =>
|
||||||
|
$crate::tracing::span!($crate::tracing::Level::WARN, $($args)*),
|
||||||
|
$crate::tracing::Level::INFO =>
|
||||||
|
$crate::tracing::span!($crate::tracing::Level::INFO, $($args)*),
|
||||||
|
$crate::tracing::Level::DEBUG =>
|
||||||
|
$crate::tracing::span!($crate::tracing::Level::DEBUG, $($args)*),
|
||||||
|
$crate::tracing::Level::TRACE =>
|
||||||
|
$crate::tracing::span!($crate::tracing::Level::TRACE, $($args)*),
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! event {
|
macro_rules! event {
|
||||||
($level:expr, $($args:tt)*) => {{
|
($level:expr, $($args:tt)*) => {{
|
||||||
|
|
|
@ -5,6 +5,8 @@ pub mod subscriber;
|
||||||
pub mod level;
|
pub mod level;
|
||||||
pub mod traceable;
|
pub mod traceable;
|
||||||
|
|
||||||
|
pub use traceable::Traceable;
|
||||||
|
|
||||||
pub fn init<'a, T: Into<Option<&'a crate::Config>>>(_config: T) {
|
pub fn init<'a, T: Into<Option<&'a crate::Config>>>(_config: T) {
|
||||||
#[cfg(all(feature = "trace", debug_assertions))]
|
#[cfg(all(feature = "trace", debug_assertions))]
|
||||||
subscriber::RocketFmt::<subscriber::Pretty>::init(_config.into());
|
subscriber::RocketFmt::<subscriber::Pretty>::init(_config.into());
|
||||||
|
|
|
@ -89,7 +89,53 @@ impl<S: Subscriber + for<'a> LookupSpan<'a>> Layer<S> for RocketFmt<Pretty> {
|
||||||
println!("{prefix}{}{} {}", self.emoji("🚀 "),
|
println!("{prefix}{}{} {}", self.emoji("🚀 "),
|
||||||
"Rocket has launched from".paint(style).primary().bold(),
|
"Rocket has launched from".paint(style).primary().bold(),
|
||||||
&data["endpoint"].paint(style).primary().bold().underline());
|
&data["endpoint"].paint(style).primary().bold().underline());
|
||||||
|
},
|
||||||
|
"route" => println!("{}", Formatter(|f| {
|
||||||
|
write!(f, "{}{}{}: ", self.indent(), self.marker(), "route".paint(style))?;
|
||||||
|
|
||||||
|
let (base, mut relative) = (&data["uri.base"], &data["uri.unmounted"]);
|
||||||
|
if base.ends_with('/') && relative.starts_with('/') {
|
||||||
|
relative = &relative[1..];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write!(f, "{:>3} {} {}{}",
|
||||||
|
&data["rank"].paint(style.bright().dim()),
|
||||||
|
&data["method"].paint(style.bold()),
|
||||||
|
base.paint(style.primary().underline()),
|
||||||
|
relative.paint(style.primary()),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if let Some(name) = data.get("name") {
|
||||||
|
write!(f, " ({})", name.paint(style.bold().bright()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})),
|
||||||
|
"catcher" => println!("{}", Formatter(|f| {
|
||||||
|
write!(f, "{}{}{}: ", self.indent(), self.marker(), "catcher".paint(style))?;
|
||||||
|
|
||||||
|
match data.get("code") {
|
||||||
|
Some(code) => write!(f, "{} ", code.paint(style.bold()))?,
|
||||||
|
None => write!(f, "{} ", "default".paint(style.bold()))?,
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, "{}", &data["uri.base"].paint(style.primary()))?;
|
||||||
|
if let Some(name) = data.get("name") {
|
||||||
|
write!(f, " ({})", name.paint(style.bold().bright()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})),
|
||||||
|
"header" => println!("{}{}{}: {}: {}",
|
||||||
|
self.indent(), self.marker(), "header".paint(style),
|
||||||
|
&data["name"].paint(style.bold()),
|
||||||
|
&data["value"].paint(style.primary()),
|
||||||
|
),
|
||||||
|
"fairing" => println!("{}{}{}: {} {}",
|
||||||
|
self.indent(), self.marker(), "fairing".paint(style),
|
||||||
|
&data["name"].paint(style.bold()),
|
||||||
|
&data["kind"].paint(style.primary().dim()),
|
||||||
|
),
|
||||||
_ => self.print_pretty(meta, event),
|
_ => self.print_pretty(meta, event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,14 +157,22 @@ impl<S: Subscriber + for<'a> LookupSpan<'a>> Layer<S> for RocketFmt<Pretty> {
|
||||||
|
|
||||||
let meta = span.metadata();
|
let meta = span.metadata();
|
||||||
let style = self.style(meta);
|
let style = self.style(meta);
|
||||||
let prefix = self.prefix(meta);
|
|
||||||
let emoji = self.emoji(icon);
|
let emoji = self.emoji(icon);
|
||||||
let name = name.paint(style).bold();
|
let name = name.paint(style).bold();
|
||||||
|
|
||||||
if !attrs.fields().is_empty() {
|
let fields = self.compact_fields(meta, attrs);
|
||||||
println!("{prefix}{emoji}{name} ({})", self.compact_fields(meta, attrs))
|
let prefix = self.prefix(meta);
|
||||||
|
let fieldless_prefix = Formatter(|f| write!(f, "{prefix}{emoji}{name} "));
|
||||||
|
let field_prefix = Formatter(|f| write!(f, "{prefix}{emoji}{name} ({fields}) "));
|
||||||
|
|
||||||
|
if self.has_message(meta) && self.has_data_fields(meta) {
|
||||||
|
print!("{}", self.message(&field_prefix, &fieldless_prefix, meta, attrs));
|
||||||
|
} else if self.has_message(meta) {
|
||||||
|
print!("{}", self.message(&fieldless_prefix, &fieldless_prefix, meta, attrs));
|
||||||
|
} else if self.has_data_fields(meta) {
|
||||||
|
println!("{field_prefix}");
|
||||||
} else {
|
} else {
|
||||||
println!("{prefix}{emoji}{name}");
|
println!("{fieldless_prefix}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
use crate::fairing::Fairing;
|
use std::error::Error as StdError;
|
||||||
use crate::{route, Catcher, Config, Response, Route};
|
|
||||||
|
use crate::sentinel::Sentry;
|
||||||
use crate::util::Formatter;
|
use crate::util::Formatter;
|
||||||
|
use crate::{route, Catcher, Config, Error, Request, Response, Route};
|
||||||
|
use crate::error::ErrorKind;
|
||||||
|
|
||||||
use figment::Figment;
|
use figment::Figment;
|
||||||
use rocket::http::Header;
|
use rocket::http::Header;
|
||||||
|
@ -131,8 +134,8 @@ impl Traceable for Route {
|
||||||
fn trace(&self, level: Level) {
|
fn trace(&self, level: Level) {
|
||||||
event! { level, "route",
|
event! { level, "route",
|
||||||
name = self.name.as_ref().map(|n| &**n),
|
name = self.name.as_ref().map(|n| &**n),
|
||||||
method = %self.method,
|
|
||||||
rank = self.rank,
|
rank = self.rank,
|
||||||
|
method = %self.method,
|
||||||
uri = %self.uri,
|
uri = %self.uri,
|
||||||
uri.base = %self.uri.base(),
|
uri.base = %self.uri.base(),
|
||||||
uri.unmounted = %self.uri.unmounted(),
|
uri.unmounted = %self.uri.unmounted(),
|
||||||
|
@ -154,7 +157,7 @@ impl Traceable for Catcher {
|
||||||
fn trace(&self, level: Level) {
|
fn trace(&self, level: Level) {
|
||||||
event! { level, "catcher",
|
event! { level, "catcher",
|
||||||
name = self.name.as_ref().map(|n| &**n),
|
name = self.name.as_ref().map(|n| &**n),
|
||||||
status = %Formatter(|f| match self.code {
|
code = %Formatter(|f| match self.code {
|
||||||
Some(code) => write!(f, "{}", code),
|
Some(code) => write!(f, "{}", code),
|
||||||
None => write!(f, "default"),
|
None => write!(f, "default"),
|
||||||
}),
|
}),
|
||||||
|
@ -164,9 +167,15 @@ impl Traceable for Catcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Traceable for &dyn Fairing {
|
impl Traceable for &dyn crate::fairing::Fairing {
|
||||||
fn trace(&self, level: Level) {
|
fn trace(&self, level: Level) {
|
||||||
event!(level, "fairing", name = self.info().name, kind = %self.info().kind)
|
self.info().trace(level)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Traceable for crate::fairing::Info {
|
||||||
|
fn trace(&self, level: Level) {
|
||||||
|
event!(level, "fairing", name = self.name, kind = %self.kind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,17 +185,17 @@ impl Traceable for figment::error::Kind {
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Message(message) => error!(message),
|
Message(message) => error!(message),
|
||||||
InvalidType(actual, expected) => error!(name: "invalid type", %actual, expected),
|
InvalidType(actual, expected) => error!(%actual, expected, "invalid type"),
|
||||||
InvalidValue(actual, expected) => error!(name: "invalid value", %actual, expected),
|
InvalidValue(actual, expected) => error!(%actual, expected, "invalid value"),
|
||||||
InvalidLength(actual, expected) => error!(name: "invalid length", %actual, expected),
|
InvalidLength(actual, expected) => error!(%actual, expected, "invalid length"),
|
||||||
UnknownVariant(actual, v) => error!(name: "unknown variant", actual, expected = %V(v)),
|
UnknownVariant(actual, v) => error!(actual, expected = %V(v), "unknown variant"),
|
||||||
UnknownField(actual, v) => error!(name: "unknown field", actual, expected = %V(v)),
|
UnknownField(actual, v) => error!(actual, expected = %V(v), "unknown field"),
|
||||||
UnsupportedKey(actual, v) => error!(name: "unsupported key", %actual, expected = &**v),
|
UnsupportedKey(actual, v) => error!(%actual, expected = &**v, "unsupported key"),
|
||||||
MissingField(value) => error!(name: "missing field", value = &**value),
|
MissingField(value) => error!(value = &**value, "missing field"),
|
||||||
DuplicateField(value) => error!(name: "duplicate field", value),
|
DuplicateField(value) => error!(value, "duplicate field"),
|
||||||
ISizeOutOfRange(value) => error!(name: "out of range signed integer", value),
|
ISizeOutOfRange(value) => error!(value, "out of range signed integer"),
|
||||||
USizeOutOfRange(value) => error!(name: "out of range unsigned integer", value),
|
USizeOutOfRange(value) => error!(value, "out of range unsigned integer"),
|
||||||
Unsupported(value) => error!(name: "unsupported type", %value),
|
Unsupported(value) => error!(%value, "unsupported type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,3 +246,94 @@ impl Traceable for Response<'_> {
|
||||||
event!(level, "response", status = self.status().code);
|
event!(level, "response", status = self.status().code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Traceable for Error {
|
||||||
|
fn trace(&self, level: Level) {
|
||||||
|
self.kind.trace(level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Traceable for Sentry {
|
||||||
|
fn trace(&self, level: Level) {
|
||||||
|
let (file, line, column) = self.location;
|
||||||
|
event!(level, "sentry", type_name = self.type_name, file, line, column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Traceable for Request<'_> {
|
||||||
|
fn trace(&self, level: Level) {
|
||||||
|
event!(level, "request", method = %self.method(), uri = %self.uri())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Traceable for ErrorKind {
|
||||||
|
fn trace(&self, level: Level) {
|
||||||
|
use ErrorKind::*;
|
||||||
|
|
||||||
|
fn try_downcast<'a, T>(error: &'a (dyn StdError + 'static)) -> Option<&'a T>
|
||||||
|
where T: StdError + 'static
|
||||||
|
{
|
||||||
|
error.downcast_ref().or_else(|| error.source()?.downcast_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Bind(endpoint, error) => {
|
||||||
|
if let Some(e) = try_downcast::<crate::Error>(&**error) {
|
||||||
|
e.trace(level);
|
||||||
|
} else if let Some(e) = try_downcast::<figment::Error>(&**error) {
|
||||||
|
e.trace(level);
|
||||||
|
} else {
|
||||||
|
event!(level, "error::bind",
|
||||||
|
?error,
|
||||||
|
endpoint = endpoint.as_ref().map(display),
|
||||||
|
"binding to network interface failed"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Io(reason) => event!(level, "error::io", %reason, "i/o error"),
|
||||||
|
Config(error) => error.trace(level),
|
||||||
|
Collisions(collisions) => {
|
||||||
|
let routes = collisions.routes.len();
|
||||||
|
let catchers = collisions.catchers.len();
|
||||||
|
|
||||||
|
span!(level, "collision",
|
||||||
|
route.pairs = routes,
|
||||||
|
catcher.pairs = catchers,
|
||||||
|
"colliding items detected"
|
||||||
|
).in_scope(|| {
|
||||||
|
let routes = &collisions.routes;
|
||||||
|
for (a, b) in routes {
|
||||||
|
span!(level, "colliding route pair").in_scope(|| {
|
||||||
|
a.trace(level);
|
||||||
|
b.trace(level);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let catchers = &collisions.catchers;
|
||||||
|
for (a, b) in catchers {
|
||||||
|
span!(level, "colliding catcher pair").in_scope(|| {
|
||||||
|
a.trace(level);
|
||||||
|
b.trace(level);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
span!(Level::INFO, "collisions can usually be resolved by ranking items");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
FailedFairings(fairings) => {
|
||||||
|
let span = span!(level, "fairings", count = fairings.len(), "ignition failure");
|
||||||
|
span.in_scope(|| fairings.iter().trace_all(level));
|
||||||
|
},
|
||||||
|
SentinelAborts(sentries) => {
|
||||||
|
let span = span!(level, "sentries", "sentry abort");
|
||||||
|
span.in_scope(|| sentries.iter().trace_all(level));
|
||||||
|
}
|
||||||
|
InsecureSecretKey(profile) => event!(level, "insecure_key", %profile,
|
||||||
|
"secrets enabled in a non-debug profile without a stable `secret_key`\n\
|
||||||
|
disable the `secrets` feature or configure a `secret_key`"
|
||||||
|
),
|
||||||
|
Liftoff(_, reason) => event!(level, "panic", %reason, "liftoff fairing failed"),
|
||||||
|
Shutdown(_) => event!(level, "shutdown", "shutdown failed"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -38,10 +38,7 @@ fn test_adhoc_normalizer_works_as_expected () {
|
||||||
.mount("/base", routes![foo, bar, not_bar, baz, doggy, rest])
|
.mount("/base", routes![foo, bar, not_bar, baz, doggy, rest])
|
||||||
.attach(AdHoc::uri_normalizer());
|
.attach(AdHoc::uri_normalizer());
|
||||||
|
|
||||||
let client = match Client::debug(rocket) {
|
let client = Client::debug(rocket).unwrap();
|
||||||
Ok(client) => client,
|
|
||||||
Err(e) => { e.pretty_print(); panic!("failed to build client"); }
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_response!(client: "/foo" => "foo");
|
assert_response!(client: "/foo" => "foo");
|
||||||
assert_response!(client: "/foo/" => "foo");
|
assert_response!(client: "/foo/" => "foo");
|
||||||
|
|
|
@ -6,6 +6,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use rocket::{Rocket, Request, State, Data, Build};
|
use rocket::{Rocket, Request, State, Data, Build};
|
||||||
use rocket::fairing::{self, AdHoc, Fairing, Info, Kind};
|
use rocket::fairing::{self, AdHoc, Fairing, Info, Kind};
|
||||||
|
use rocket::trace::Traceable;
|
||||||
use rocket::http::Method;
|
use rocket::http::Method;
|
||||||
|
|
||||||
struct Token(i64);
|
struct Token(i64);
|
||||||
|
@ -63,7 +64,7 @@ fn rocket() -> _ {
|
||||||
.mount("/", routes![hello, token])
|
.mount("/", routes![hello, token])
|
||||||
.attach(Counter::default())
|
.attach(Counter::default())
|
||||||
.attach(AdHoc::try_on_ignite("Token State", |rocket| async {
|
.attach(AdHoc::try_on_ignite("Token State", |rocket| async {
|
||||||
info!("Adding token managed state...");
|
info!("adding token managed state");
|
||||||
match rocket.figment().extract_inner("token") {
|
match rocket.figment().extract_inner("token") {
|
||||||
Ok(value) => Ok(rocket.manage(Token(value))),
|
Ok(value) => Ok(rocket.manage(Token(value))),
|
||||||
Err(_) => Err(rocket)
|
Err(_) => Err(rocket)
|
||||||
|
@ -74,17 +75,20 @@ fn rocket() -> _ {
|
||||||
})))
|
})))
|
||||||
.attach(AdHoc::on_request("PUT Rewriter", |req, _| {
|
.attach(AdHoc::on_request("PUT Rewriter", |req, _| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
println!(" => Incoming request: {}", req);
|
|
||||||
if req.uri().path() == "/" {
|
if req.uri().path() == "/" {
|
||||||
println!(" => Changing method to `PUT`.");
|
info_span!("PUT rewriter" => {
|
||||||
|
req.trace_info();
|
||||||
|
info!("changing method to `PUT`");
|
||||||
req.set_method(Method::Put);
|
req.set_method(Method::Put);
|
||||||
|
req.trace_info();
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
.attach(AdHoc::on_response("Response Rewriter", |req, res| {
|
.attach(AdHoc::on_response("Response Rewriter", |req, res| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
if req.uri().path() == "/" {
|
if req.uri().path() == "/" {
|
||||||
println!(" => Rewriting response body.");
|
info!("rewriting response body");
|
||||||
res.set_sized_body(None, Cursor::new("Hello, fairings!"));
|
res.set_sized_body(None, Cursor::new("Hello, fairings!"));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use rocket::fairing::AdHoc;
|
||||||
|
|
||||||
#[macro_use] extern crate rocket;
|
#[macro_use] extern crate rocket;
|
||||||
|
|
||||||
#[cfg(test)] mod tests;
|
#[cfg(test)] mod tests;
|
||||||
|
@ -38,6 +40,9 @@ fn wave(name: &str, age: u8) -> String {
|
||||||
format!("👋 Hello, {} year old named {}!", age, name)
|
format!("👋 Hello, {} year old named {}!", age, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/<a>/<b>")]
|
||||||
|
fn f(a: usize, b: usize) { }
|
||||||
|
|
||||||
// Note: without the `..` in `opt..`, we'd need to pass `opt.emoji`, `opt.name`.
|
// Note: without the `..` in `opt..`, we'd need to pass `opt.emoji`, `opt.name`.
|
||||||
//
|
//
|
||||||
// Try visiting:
|
// Try visiting:
|
||||||
|
|
|
@ -9,6 +9,7 @@ use rocket::fairing::AdHoc;
|
||||||
use rocket::listener::{Bind, DefaultListener};
|
use rocket::listener::{Bind, DefaultListener};
|
||||||
use rocket::serde::{Deserialize, DeserializeOwned, Serialize};
|
use rocket::serde::{Deserialize, DeserializeOwned, Serialize};
|
||||||
use rocket::{Build, Ignite, Rocket};
|
use rocket::{Build, Ignite, Rocket};
|
||||||
|
use rocket::trace::Traceable;
|
||||||
|
|
||||||
use ipc_channel::ipc::{IpcOneShotServer, IpcReceiver, IpcSender};
|
use ipc_channel::ipc::{IpcOneShotServer, IpcReceiver, IpcSender};
|
||||||
|
|
||||||
|
@ -135,7 +136,7 @@ impl Token {
|
||||||
let sender = IpcSender::<Message>::connect(server).unwrap();
|
let sender = IpcSender::<Message>::connect(server).unwrap();
|
||||||
let _ = sender.send(Message::Failure);
|
let _ = sender.send(Message::Failure);
|
||||||
let _ = sender.send(Message::Failure);
|
let _ = sender.send(Message::Failure);
|
||||||
e.pretty_print();
|
e.trace_error();
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue