mirror of https://github.com/rwf2/Rocket.git
parent
007c4b093f
commit
2f98299272
|
@ -1,3 +1,5 @@
|
|||
use std::error::Error;
|
||||
|
||||
use crate::templates::{DEFAULT_TEMPLATE_DIR, Context, Engines};
|
||||
|
||||
use rocket::Rocket;
|
||||
|
@ -5,6 +7,8 @@ use rocket::fairing::{Fairing, Info, Kind};
|
|||
|
||||
pub(crate) use self::context::ContextManager;
|
||||
|
||||
type Callback = Box<dyn Fn(&mut Engines) -> Result<(), Box<dyn Error>>+ Send + Sync + 'static>;
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
mod context {
|
||||
use std::ops::Deref;
|
||||
|
@ -37,7 +41,7 @@ mod context {
|
|||
|
||||
use notify::{raw_watcher, RawEvent, RecommendedWatcher, RecursiveMode, Watcher};
|
||||
|
||||
use crate::templates::{Context, Engines};
|
||||
use super::{Callback, Context};
|
||||
|
||||
/// Wraps a Context. With `cfg(debug_assertions)` active, this structure
|
||||
/// additionally provides a method to reload the context at runtime.
|
||||
|
@ -88,7 +92,7 @@ mod context {
|
|||
/// have been changes since the last reload, all templates are
|
||||
/// reinitialized from disk and the user's customization callback is run
|
||||
/// again.
|
||||
pub fn reload_if_needed<F: Fn(&mut Engines)>(&self, custom_callback: F) {
|
||||
pub fn reload_if_needed(&self, callback: &Callback) {
|
||||
self.watcher.as_ref().map(|w| {
|
||||
let rx_lock = w.lock().expect("receive queue lock");
|
||||
let mut changed = false;
|
||||
|
@ -100,11 +104,17 @@ mod context {
|
|||
info_!("Change detected: reloading templates.");
|
||||
let mut ctxt = self.context_mut();
|
||||
if let Some(mut new_ctxt) = Context::initialize(ctxt.root.clone()) {
|
||||
custom_callback(&mut new_ctxt.engines);
|
||||
*ctxt = new_ctxt;
|
||||
match callback(&mut new_ctxt.engines) {
|
||||
Ok(()) => *ctxt = new_ctxt,
|
||||
Err(e) => {
|
||||
warn_!("The template customization callback returned an error:");
|
||||
warn_!("{}", e);
|
||||
warn_!("The existing templates will remain active.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn_!("An error occurred while reloading templates.");
|
||||
warn_!("The previous templates will remain active.");
|
||||
warn_!("The existing templates will remain active.");
|
||||
};
|
||||
}
|
||||
});
|
||||
|
@ -120,7 +130,7 @@ pub struct TemplateFairing {
|
|||
/// The user-provided customization callback, allowing the use of
|
||||
/// functionality specific to individual template engines. In debug mode,
|
||||
/// this callback might be run multiple times as templates are reloaded.
|
||||
pub custom_callback: Box<dyn Fn(&mut Engines) + Send + Sync + 'static>,
|
||||
pub callback: Callback,
|
||||
}
|
||||
|
||||
#[rocket::async_trait]
|
||||
|
@ -161,11 +171,19 @@ impl Fairing for TemplateFairing {
|
|||
use crate::templates::Engines;
|
||||
|
||||
info!("{}{}", Paint::emoji("📐 "), Paint::magenta("Templating:"));
|
||||
info_!("directory: {}", Paint::white(root));
|
||||
info_!("engines: {:?}", Paint::white(Engines::ENABLED_EXTENSIONS));
|
||||
|
||||
(self.custom_callback)(&mut ctxt.engines);
|
||||
Ok(rocket.manage(ContextManager::new(ctxt)))
|
||||
match (self.callback)(&mut ctxt.engines) {
|
||||
Ok(()) => {
|
||||
info_!("directory: {}", Paint::white(root));
|
||||
info_!("engines: {:?}", Paint::white(Engines::ENABLED_EXTENSIONS));
|
||||
Ok(rocket.manage(ContextManager::new(ctxt)))
|
||||
}
|
||||
Err(e) => {
|
||||
error_!("The template customization callback returned an error:");
|
||||
error_!("{}", e);
|
||||
Err(rocket)
|
||||
}
|
||||
}
|
||||
}
|
||||
None => Err(rocket),
|
||||
}
|
||||
|
@ -176,6 +194,6 @@ impl Fairing for TemplateFairing {
|
|||
let cm = req.managed_state::<ContextManager>()
|
||||
.expect("Template ContextManager registered in on_attach");
|
||||
|
||||
cm.reload_if_needed(&*self.custom_callback);
|
||||
cm.reload_if_needed(&self.callback);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,11 +93,11 @@
|
|||
//! ## Template Fairing
|
||||
//!
|
||||
//! Template discovery is actualized by the template fairing, which itself is
|
||||
//! created via [`Template::fairing()`] or [`Template::custom()`], the latter of
|
||||
//! which allows for customizations to the templating engine. In order for _any_
|
||||
//! templates to be rendered, the template fairing _must_ be
|
||||
//! [attached](rocket::Rocket::attach()) to the running Rocket instance. Failure
|
||||
//! to do so will result in a run-time error.
|
||||
//! created via [`Template::fairing()`], [`Template::custom()`], or
|
||||
//! [`Template::try_custom()`], the latter two allowing customizations to
|
||||
//! enabled templating engines. In order for _any_ templates to be rendered, the
|
||||
//! template fairing _must_ be [attached](rocket::Rocket::attach()) to the
|
||||
//! running Rocket instance. Failure to do so will result in a run-time error.
|
||||
//!
|
||||
//! Templates are rendered with the `render` method. The method takes in the
|
||||
//! name of a template and a context to render the template with. The context
|
||||
|
@ -110,10 +110,6 @@
|
|||
//! template reloading is disabled to improve performance and cannot be enabled.
|
||||
//!
|
||||
//! [`Serialize`]: serde::Serialize
|
||||
//! [`Template`]: crate::templates::Template
|
||||
//! [`Template::fairing()`]: crate::templates::Template::fairing()
|
||||
//! [`Template::custom()`]: crate::templates::Template::custom()
|
||||
//! [`Template::render()`]: crate::templates::Template::render()
|
||||
|
||||
#[cfg(feature = "tera_templates")] pub extern crate tera;
|
||||
#[cfg(feature = "tera_templates")] mod tera_templates;
|
||||
|
@ -139,6 +135,7 @@ use serde_json::{Value, to_value};
|
|||
|
||||
use std::borrow::Cow;
|
||||
use std::path::PathBuf;
|
||||
use std::error::Error;
|
||||
|
||||
use rocket::Rocket;
|
||||
use rocket::request::Request;
|
||||
|
@ -254,9 +251,12 @@ impl Template {
|
|||
/// Returns a fairing that initializes and maintains templating state.
|
||||
///
|
||||
/// Unlike [`Template::fairing()`], this method allows you to configure
|
||||
/// templating engines via the parameter `f`. Note that only the enabled
|
||||
/// templating engines via the function `f`. Note that only the enabled
|
||||
/// templating engines will be accessible from the `Engines` type.
|
||||
///
|
||||
/// This method does not allow the function `f` to fail. If `f` is fallible,
|
||||
/// use [`Template::try_custom()`] instead.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -275,10 +275,42 @@ impl Template {
|
|||
/// # ;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn custom<F>(f: F) -> impl Fairing
|
||||
where F: Fn(&mut Engines) + Send + Sync + 'static
|
||||
pub fn custom<F: Send + Sync + 'static>(f: F) -> impl Fairing
|
||||
where F: Fn(&mut Engines)
|
||||
{
|
||||
TemplateFairing { custom_callback: Box::new(f) }
|
||||
Self::try_custom(move |engines| { f(engines); Ok(()) })
|
||||
}
|
||||
|
||||
/// Returns a fairing that initializes and maintains templating state.
|
||||
///
|
||||
/// This variant of [`Template::custom()`] allows a fallible `f`. If `f`
|
||||
/// returns an error during initialization, it will cancel the launch. If
|
||||
/// `f` returns an error during template reloading (in debug mode), then the
|
||||
/// newly-reloaded templates are discarded.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// extern crate rocket;
|
||||
/// extern crate rocket_contrib;
|
||||
///
|
||||
/// use rocket_contrib::templates::Template;
|
||||
///
|
||||
/// fn main() {
|
||||
/// rocket::ignite()
|
||||
/// // ...
|
||||
/// .attach(Template::try_custom(|engines| {
|
||||
/// // engines.handlebars.register_helper ...
|
||||
/// Ok(())
|
||||
/// }))
|
||||
/// // ...
|
||||
/// # ;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn try_custom<F: Send + Sync + 'static>(f: F) -> impl Fairing
|
||||
where F: Fn(&mut Engines) -> Result<(), Box<dyn Error>>
|
||||
{
|
||||
TemplateFairing { callback: Box::new(f) }
|
||||
}
|
||||
|
||||
/// Render the template named `name` with the context `context`. The
|
||||
|
|
|
@ -32,6 +32,23 @@ mod templates_tests {
|
|||
.mount("/", routes![template_check, is_reloading])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_callback_error() {
|
||||
use rocket::{local::blocking::Client, error::ErrorKind::FailedFairings};
|
||||
|
||||
let rocket = rocket::ignite().attach(Template::try_custom(|_| {
|
||||
Err("error reloading templates!".into())
|
||||
}));
|
||||
|
||||
match Client::untracked(rocket) {
|
||||
Err(e) => match e.kind() {
|
||||
FailedFairings(failures) => assert_eq!(failures[0], "Templates"),
|
||||
_ => panic!("Wrong kind of launch error"),
|
||||
}
|
||||
_ => panic!("Wrong kind of error"),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "tera_templates")]
|
||||
mod tera_tests {
|
||||
use super::*;
|
||||
|
|
Loading…
Reference in New Issue