Remove 'rocket::inspect()', 'Cargo'.

This commit reverts most of dea940c7 and d89c7024. The "fix" is to run
attach fairings on a new thread. If a runtime is already running, it is
used. Otherwise, the future is executed in a single-threaded executor.
This commit is contained in:
Sergio Benitez 2020-10-22 03:27:04 -07:00
parent 491b229582
commit ec9b5816a8
33 changed files with 293 additions and 521 deletions

View File

@ -72,10 +72,12 @@ pub fn database_attr(attr: TokenStream, input: TokenStream) -> Result<TokenStrea
let request = quote!(::rocket::request);
let request_guard_type = quote_spanned! { span =>
/// The request guard type.
#vis struct #guard_type(#databases::Connection<Self, #conn_type>);
};
let pool = quote_spanned!(span => #databases::ConnectionPool<Self, #conn_type>);
let conn = quote_spanned!(span => #databases::Connection<Self, #conn_type>);
Ok(quote! {
#request_guard_type
@ -83,26 +85,26 @@ pub fn database_attr(attr: TokenStream, input: TokenStream) -> Result<TokenStrea
/// Returns a fairing that initializes the associated database
/// connection pool.
pub fn fairing() -> impl ::rocket::fairing::Fairing {
<#databases::ConnectionPool<Self, #conn_type>>::fairing(#fairing_name, #name)
<#pool>::fairing(#fairing_name, #name)
}
/// Retrieves a connection of type `Self` from the `rocket`
/// instance. Returns `Some` as long as `Self::fairing()` has been
/// attached.
pub async fn get_one(cargo: &::rocket::Cargo) -> Option<Self> {
<#databases::ConnectionPool<Self, #conn_type>>::get_one(cargo).await.map(Self)
pub async fn get_one(__rocket: &::rocket::Rocket) -> Option<Self> {
<#pool>::get_one(&__rocket).await.map(Self)
}
/// Runs the provided closure on a thread from a threadpool. The
/// closure will be passed an `&mut r2d2::PooledConnection`.
/// `.await`ing the return value of this function yields the value
/// returned by the closure.
pub async fn run<F, R>(&self, f: F) -> R
pub async fn run<F, R>(&self, __f: F) -> R
where
F: FnOnce(&mut #conn_type) -> R + Send + 'static,
R: Send + 'static,
{
self.0.run(f).await
self.0.run(__f).await
}
}
@ -110,8 +112,8 @@ pub fn database_attr(attr: TokenStream, input: TokenStream) -> Result<TokenStrea
impl<'a, 'r> #request::FromRequest<'a, 'r> for #guard_type {
type Error = ();
async fn from_request(req: &'a #request::Request<'r>) -> #request::Outcome<Self, ()> {
<#databases::Connection<Self, #conn_type>>::from_request(req).await.map(Self)
async fn from_request(__r: &'a #request::Request<'r>) -> #request::Outcome<Self, ()> {
<#conn>::from_request(__r).await.map(Self)
}
}
}.into())

View File

@ -198,7 +198,7 @@
//! Returns a fairing that initializes the associated database connection
//! pool.
//!
//! * `async fn get_one(&Cargo) -> Option<Self>`
//! * `async fn get_one(&Rocket) -> Option<Self>`
//!
//! Retrieves a connection wrapper from the configured pool. Returns `Some`
//! as long as `Self::fairing()` has been attached.
@ -405,7 +405,7 @@ use self::r2d2::ManageConnection;
/// timeout = 5
/// ```
///
/// ...`Config::from("my_database", cargo)` would return the following struct:
/// ...`Config::from("my_database", rocket)` would return the following struct:
///
/// ```rust
/// # use rocket_contrib::databases::Config;
@ -455,32 +455,29 @@ impl Config {
///
/// use rocket_contrib::databases::Config;
///
/// fn pool(cargo: &rocket::Cargo) {
/// let config = Config::from("my_db", cargo).unwrap();
/// fn pool(rocket: &rocket::Rocket) {
/// let config = Config::from("my_db", rocket).unwrap();
/// assert_eq!(config.url, "db/db.sqlite");
/// assert_eq!(config.pool_size, 25);
///
/// let config = Config::from("my_other_db", cargo).unwrap();
/// let config = Config::from("my_other_db", rocket).unwrap();
/// assert_eq!(config.url, "mysql://root:root@localhost/database");
/// assert_eq!(config.pool_size, cargo.config().workers as u32);
/// assert_eq!(config.pool_size, rocket.config().workers as u32);
///
/// let config = Config::from("unknown_db", cargo);
/// let config = Config::from("unknown_db", rocket);
/// assert!(config.is_err())
/// }
/// #
/// # rocket::async_test(async {
/// # let config = Figment::from(rocket::Config::default()).merge(toml);
/// # let mut rocket = rocket::custom(config);
/// # let cargo = rocket.inspect().await;
/// # pool(cargo);
/// # });
/// # let rocket = rocket::custom(config);
/// # pool(&rocket);
/// # }
/// ```
pub fn from(db_name: &str, cargo: &rocket::Cargo) -> Result<Config, figment::Error> {
pub fn from(db_name: &str, rocket: &rocket::Rocket) -> Result<Config, figment::Error> {
let db_key = format!("databases.{}", db_name);
let key = |name: &str| format!("{}.{}", db_key, name);
Figment::from(cargo.figment())
.merge(Serialized::default(&key("pool_size"), cargo.config().workers))
Figment::from(rocket.figment())
.merge(Serialized::default(&key("pool_size"), rocket.config().workers))
.merge(Serialized::default(&key("timeout"), 5))
.extract_inner::<Self>(&db_key)
}
@ -578,8 +575,8 @@ impl<T> From<r2d2::Error> for Error<T> {
/// type Manager = foo::ConnectionManager;
/// type Error = foo::Error;
///
/// fn pool(db_name: &str, cargo: &rocket::Cargo) -> PoolResult<Self> {
/// let config = Config::from(db_name, cargo)?;
/// fn pool(db_name: &str, rocket: &rocket::Rocket) -> PoolResult<Self> {
/// let config = Config::from(db_name, rocket)?;
/// let manager = foo::ConnectionManager::new(&config.url).map_err(Error::Custom)?;
/// Ok(r2d2::Pool::builder().max_size(config.pool_size).build(manager)?)
/// }
@ -607,7 +604,7 @@ pub trait Poolable: Send + Sized + 'static {
/// Creates an `r2d2` connection pool for `Manager::Connection`, returning
/// the pool on success.
fn pool(db_name: &str, cargo: &rocket::Cargo) -> PoolResult<Self>;
fn pool(db_name: &str, rocket: &rocket::Rocket) -> PoolResult<Self>;
}
/// A type alias for the return type of [`Poolable::pool()`].
@ -619,8 +616,8 @@ impl Poolable for diesel::SqliteConnection {
type Manager = diesel::r2d2::ConnectionManager<diesel::SqliteConnection>;
type Error = std::convert::Infallible;
fn pool(db_name: &str, cargo: &rocket::Cargo) -> PoolResult<Self> {
let config = Config::from(db_name, cargo)?;
fn pool(db_name: &str, rocket: &rocket::Rocket) -> PoolResult<Self> {
let config = Config::from(db_name, rocket)?;
let manager = diesel::r2d2::ConnectionManager::new(&config.url);
Ok(r2d2::Pool::builder().max_size(config.pool_size).build(manager)?)
}
@ -631,8 +628,8 @@ impl Poolable for diesel::PgConnection {
type Manager = diesel::r2d2::ConnectionManager<diesel::PgConnection>;
type Error = std::convert::Infallible;
fn pool(db_name: &str, cargo: &rocket::Cargo) -> PoolResult<Self> {
let config = Config::from(db_name, cargo)?;
fn pool(db_name: &str, rocket: &rocket::Rocket) -> PoolResult<Self> {
let config = Config::from(db_name, rocket)?;
let manager = diesel::r2d2::ConnectionManager::new(&config.url);
Ok(r2d2::Pool::builder().max_size(config.pool_size).build(manager)?)
}
@ -643,8 +640,8 @@ impl Poolable for diesel::MysqlConnection {
type Manager = diesel::r2d2::ConnectionManager<diesel::MysqlConnection>;
type Error = std::convert::Infallible;
fn pool(db_name: &str, cargo: &rocket::Cargo) -> PoolResult<Self> {
let config = Config::from(db_name, cargo)?;
fn pool(db_name: &str, rocket: &rocket::Rocket) -> PoolResult<Self> {
let config = Config::from(db_name, rocket)?;
let manager = diesel::r2d2::ConnectionManager::new(&config.url);
Ok(r2d2::Pool::builder().max_size(config.pool_size).build(manager)?)
}
@ -656,8 +653,8 @@ impl Poolable for postgres::Client {
type Manager = r2d2_postgres::PostgresConnectionManager<postgres::tls::NoTls>;
type Error = postgres::Error;
fn pool(db_name: &str, cargo: &rocket::Cargo) -> PoolResult<Self> {
let config = Config::from(db_name, cargo)?;
fn pool(db_name: &str, rocket: &rocket::Rocket) -> PoolResult<Self> {
let config = Config::from(db_name, rocket)?;
let url = config.url.parse().map_err(Error::Custom)?;
let manager = r2d2_postgres::PostgresConnectionManager::new(url, postgres::tls::NoTls);
Ok(r2d2::Pool::builder().max_size(config.pool_size).build(manager)?)
@ -669,8 +666,8 @@ impl Poolable for mysql::Conn {
type Manager = r2d2_mysql::MysqlConnectionManager;
type Error = std::convert::Infallible;
fn pool(db_name: &str, cargo: &rocket::Cargo) -> PoolResult<Self> {
let config = Config::from(db_name, cargo)?;
fn pool(db_name: &str, rocket: &rocket::Rocket) -> PoolResult<Self> {
let config = Config::from(db_name, rocket)?;
let opts = mysql::OptsBuilder::from_opts(&config.url);
let manager = r2d2_mysql::MysqlConnectionManager::new(opts);
Ok(r2d2::Pool::builder().max_size(config.pool_size).build(manager)?)
@ -682,8 +679,8 @@ impl Poolable for rusqlite::Connection {
type Manager = r2d2_sqlite::SqliteConnectionManager;
type Error = std::convert::Infallible;
fn pool(db_name: &str, cargo: &rocket::Cargo) -> PoolResult<Self> {
let config = Config::from(db_name, cargo)?;
fn pool(db_name: &str, rocket: &rocket::Rocket) -> PoolResult<Self> {
let config = Config::from(db_name, rocket)?;
let manager = r2d2_sqlite::SqliteConnectionManager::file(&*config.url);
Ok(r2d2::Pool::builder().max_size(config.pool_size).build(manager)?)
}
@ -695,8 +692,8 @@ impl Poolable for memcache::Client {
// Unused, but we might want it in the future without a breaking change.
type Error = memcache::MemcacheError;
fn pool(db_name: &str, cargo: &rocket::Cargo) -> PoolResult<Self> {
let config = Config::from(db_name, cargo)?;
fn pool(db_name: &str, rocket: &rocket::Rocket) -> PoolResult<Self> {
let config = Config::from(db_name, rocket)?;
let manager = r2d2_memcache::MemcacheConnectionManager::new(&*config.url);
Ok(r2d2::Pool::builder().max_size(config.pool_size).build(manager)?)
}
@ -759,15 +756,14 @@ macro_rules! dberr {
impl<K: 'static, C: Poolable> ConnectionPool<K, C> {
pub fn fairing(fairing_name: &'static str, db: &'static str) -> impl Fairing {
AdHoc::on_attach(fairing_name, move |mut rocket| async move {
let cargo = rocket.inspect().await;
let config = match Config::from(db, cargo) {
AdHoc::on_attach(fairing_name, move |rocket| async move {
let config = match Config::from(db, &rocket) {
Ok(config) => config,
Err(e) => dberr!("config", db, "{}", e, rocket),
};
let pool_size = config.pool_size;
match C::pool(db, cargo) {
match C::pool(db, &rocket) {
Ok(pool) => Ok(rocket.manage(ConnectionPool::<K, C> {
pool, config,
semaphore: Arc::new(Semaphore::new(pool_size as usize)),
@ -805,16 +801,16 @@ impl<K: 'static, C: Poolable> ConnectionPool<K, C> {
}
#[inline]
pub async fn get_one(cargo: &rocket::Cargo) -> Option<Connection<K, C>> {
match cargo.state::<Self>() {
pub async fn get_one(rocket: &rocket::Rocket) -> Option<Connection<K, C>> {
match rocket.state::<Self>() {
Some(pool) => pool.get().await.ok(),
None => None
}
}
#[inline]
pub async fn get_pool(cargo: &rocket::Cargo) -> Option<Self> {
cargo.state::<Self>().map(|pool| pool.clone())
pub async fn get_pool(rocket: &rocket::Rocket) -> Option<Self> {
rocket.state::<Self>().map(|pool| pool.clone())
}
}

View File

@ -3,7 +3,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
use rocket::http::uncased::UncasedStr;
use rocket::fairing::{Fairing, Info, Kind};
use rocket::{Cargo, Request, Response};
use rocket::{Rocket, Request, Response};
use crate::helmet::*;
@ -201,9 +201,9 @@ impl Fairing for SpaceHelmet {
self.apply(res);
}
fn on_launch(&self, cargo: &Cargo) {
if cargo.config().tls_enabled()
&& cargo.figment().profile() != rocket::Config::DEBUG_PROFILE
fn on_launch(&self, rocket: &Rocket) {
if rocket.config().tls_enabled()
&& rocket.figment().profile() != rocket::Config::DEBUG_PROFILE
&& !self.is_enabled::<Hsts>()
{
warn_!("Space Helmet: deploying with TLS without enabling HSTS.");

View File

@ -25,7 +25,7 @@
//! * [${database}_pool](databases) - Database Configuration and Pooling
//! * [helmet](helmet) - Fairing for Security and Privacy Headers
//!
//! The recommend way to include features from this crate via Cargo in your
//! The recommend way to include features from this crate via Rocket in your
//! project is by adding a `[dependencies.rocket_contrib]` section to your
//! `Cargo.toml` file, setting `default-features` to false, and specifying
//! features manually. For example, to use the JSON module, you would add:

View File

@ -187,7 +187,7 @@ impl std::ops::BitOr for Options {
/// ## Relative Paths
///
/// In the example above, `/static` is an absolute path. If your static files
/// are stored relative to your crate and your project is managed by Cargo, use
/// are stored relative to your crate and your project is managed by Rocket, use
/// the [`crate_relative!`] macro to obtain a path that is relative to your
/// crate's root. For example, to serve files in the `static` subdirectory of
/// your crate at `/`, you might write:

View File

@ -138,10 +138,10 @@ impl Fairing for TemplateFairing {
/// The user's callback, if any was supplied, is called to customize the
/// template engines. In debug mode, the `ContextManager::new` method
/// initializes a directory watcher for auto-reloading of templates.
async fn on_attach(&self, mut rocket: Rocket) -> Result<Rocket, Rocket> {
async fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> {
use rocket::figment::{Source, value::magic::RelativePathBuf};
let configured_dir = rocket.figment().await
let configured_dir = rocket.figment()
.extract_inner::<RelativePathBuf>("template_dir")
.map(|path| path.relative());
@ -173,7 +173,7 @@ impl Fairing for TemplateFairing {
#[cfg(debug_assertions)]
async fn on_request(&self, req: &mut rocket::Request<'_>, _data: &mut rocket::Data) {
let cm = req.guard::<rocket::State<'_, ContextManager>>().await
let cm = req.managed_state::<ContextManager>()
.expect("Template ContextManager registered in on_attach");
cm.reload_if_needed(&*self.custom_callback);

View File

@ -104,7 +104,7 @@
//! can be any type that implements [`Serialize`] from [`serde`] and would
//! serialize to an `Object` value.
//!
//! In debug mode (without the `--release` flag passed to `cargo`), templates
//! In debug mode (without the `--release` flag passed to `rocket`), templates
//! will be automatically reloaded from disk if any changes have been made to
//! the templates directory since the previous request. In release builds,
//! template reloading is disabled to improve performance and cannot be enabled.
@ -140,7 +140,7 @@ use serde_json::{Value, to_value};
use std::borrow::Cow;
use std::path::PathBuf;
use rocket::Cargo;
use rocket::Rocket;
use rocket::request::Request;
use rocket::fairing::Fairing;
use rocket::response::{self, Content, Responder};
@ -337,14 +337,14 @@ impl Template {
///
/// # context.insert("test", "test");
/// # #[allow(unused_variables)]
/// let template = Template::show(client.cargo(), "index", context);
/// let template = Template::show(client.rocket(), "index", context);
/// }
/// ```
#[inline]
pub fn show<S, C>(cargo: &Cargo, name: S, context: C) -> Option<String>
pub fn show<S, C>(rocket: &Rocket, name: S, context: C) -> Option<String>
where S: Into<Cow<'static, str>>, C: Serialize
{
let ctxt = cargo.state::<ContextManager>().map(ContextManager::context).or_else(|| {
let ctxt = rocket.state::<ContextManager>().map(ContextManager::context).or_else(|| {
warn!("Uninitialized template context: missing fairing.");
info!("To use templates, you must attach `Template::fairing()`.");
info!("See the `Template` documentation for more information.");

View File

@ -33,18 +33,21 @@ mod rusqlite_integration_test {
.merge(("databases", map!["test_db" => &options]))
.merge(("databases", map!["test_db_2" => &options]));
let mut rocket = rocket::custom(config)
let rocket = rocket::custom(config)
.attach(SqliteDb::fairing())
.attach(SqliteDb2::fairing());
let conn = SqliteDb::get_one(rocket.inspect().await).await
let conn = SqliteDb::get_one(&rocket).await
.expect("unable to get connection");
// Rusqlite's `transaction()` method takes `&mut self`; this tests that
// the &mut method can be called inside the closure passed to `run()`.
conn.run(|conn| {
let tx = conn.transaction().unwrap();
let _: i32 = tx.query_row("SELECT 1", &[] as &[&dyn ToSql], |row| row.get(0)).expect("get row");
let _: i32 = tx.query_row(
"SELECT 1", &[] as &[&dyn ToSql], |row| row.get(0)
).expect("get row");
tx.commit().expect("committed transaction");
}).await;
}

View File

@ -44,20 +44,19 @@ mod templates_tests {
const ESCAPED_EXPECTED: &'static str
= "\nh_start\ntitle: _test_\nh_end\n\n\n&lt;script &#x2F;&gt;\n\nfoot\n";
#[rocket::async_test]
async fn test_tera_templates() {
let mut rocket = rocket();
let cargo = rocket.inspect().await;
#[test]
fn test_tera_templates() {
let rocket = rocket();
let mut map = HashMap::new();
map.insert("title", "_test_");
map.insert("content", "<script />");
// Test with a txt file, which shouldn't escape.
let template = Template::show(cargo, "tera/txt_test", &map);
let template = Template::show(&rocket, "tera/txt_test", &map);
assert_eq!(template, Some(UNESCAPED_EXPECTED.into()));
// Now with an HTML file, which should.
let template = Template::show(cargo, "tera/html_test", &map);
let template = Template::show(&rocket, "tera/html_test", &map);
assert_eq!(template, Some(ESCAPED_EXPECTED.into()));
}
@ -89,16 +88,15 @@ mod templates_tests {
const EXPECTED: &'static str
= "Hello _test_!\n\n<main> &lt;script /&gt; hi </main>\nDone.\n\n";
#[rocket::async_test]
async fn test_handlebars_templates() {
let mut rocket = rocket();
let cargo = rocket.inspect().await;
#[test]
fn test_handlebars_templates() {
let rocket = rocket();
let mut map = HashMap::new();
map.insert("title", "_test_");
map.insert("content", "<script /> hi");
// Test with a txt file, which shouldn't escape.
let template = Template::show(cargo, "hbs/test", &map);
let template = Template::show(&rocket, "hbs/test", &map);
assert_eq!(template, Some(EXPECTED.into()));
}
@ -148,7 +146,7 @@ mod templates_tests {
}
// verify that the initial content is correct
let initial_rendered = Template::show(client.cargo(), RELOAD_TEMPLATE, ());
let initial_rendered = Template::show(client.rocket(), RELOAD_TEMPLATE, ());
assert_eq!(initial_rendered, Some(INITIAL_TEXT.into()));
// write a change to the file
@ -159,7 +157,7 @@ mod templates_tests {
client.get("/").dispatch();
// if the new content is correct, we are done
let new_rendered = Template::show(client.cargo(), RELOAD_TEMPLATE, ());
let new_rendered = Template::show(client.rocket(), RELOAD_TEMPLATE, ());
if new_rendered == Some(NEW_TEXT.into()) {
write_file(&reload_path, INITIAL_TEXT);
return;

View File

@ -92,7 +92,7 @@ fn bench_simple_routing(b: &mut Bencher) {
// Hold all of the requests we're going to make during the benchmark.
let mut requests = vec![];
for route in client.cargo().routes() {
for route in client.rocket().routes() {
let request = client.req(route.method, route.uri.path());
requests.push(request);
}

View File

@ -7,7 +7,7 @@
//! ## Extracting Configuration Parameters
//!
//! Rocket exposes the active [`Figment`] via [`Rocket::figment()`] and
//! [`Cargo::figment()`]. Any value that implements [`Deserialize`] can be
//! [`Rocket::figment()`]. Any value that implements [`Deserialize`] can be
//! extracted from the figment:
//!
//! ```rust
@ -27,7 +27,7 @@
//!
//! [`Figment`]: figment::Figment
//! [`Rocket::figment()`]: crate::Rocket::figment()
//! [`Cargo::figment()`]: crate::Cargo::figment()
//! [`Rocket::figment()`]: crate::Rocket::figment()
//! [`Deserialize`]: serde::Deserialize
//!
//! ## Custom Providers

View File

@ -130,7 +130,7 @@ impl Data {
/// In a fairing:
///
/// ```
/// use rocket::{Cargo, Rocket, Request, Data, Response};
/// use rocket::{Rocket, Request, Data, Response};
/// use rocket::fairing::{Fairing, Info, Kind};
/// # struct MyType;
///

View File

@ -2,7 +2,7 @@ use std::sync::Mutex;
use futures::future::{Future, BoxFuture};
use crate::{Cargo, Rocket, Request, Response, Data};
use crate::{Rocket, Request, Response, Data};
use crate::fairing::{Fairing, Kind, Info};
/// A ad-hoc fairing that can be created from a function or closure.
@ -67,7 +67,7 @@ enum AdHocKind {
-> BoxFuture<'static, Result<Rocket, Rocket>> + Send + 'static>>>),
/// An ad-hoc **launch** fairing. Called just before Rocket launches.
Launch(Mutex<Option<Box<dyn FnOnce(&Cargo) + Send + 'static>>>),
Launch(Mutex<Option<Box<dyn FnOnce(&Rocket) + Send + 'static>>>),
/// An ad-hoc **request** fairing. Called when a request is received.
Request(Box<dyn for<'a> Fn(&'a mut Request<'_>, &'a Data)
@ -124,9 +124,8 @@ impl AdHoc {
pub fn config<'de, T>() -> AdHoc
where T: serde::Deserialize<'de> + Send + Sync + 'static
{
AdHoc::on_attach(std::any::type_name::<T>(), |mut rocket| async {
let figment = rocket.figment().await;
let app_config = match figment.extract::<T>() {
AdHoc::on_attach(std::any::type_name::<T>(), |rocket| async {
let app_config = match rocket.figment().extract::<T>() {
Ok(config) => config,
Err(e) => {
crate::config::pretty_print_error(e);
@ -152,7 +151,7 @@ impl AdHoc {
/// });
/// ```
pub fn on_launch<F: Send + 'static>(name: &'static str, f: F) -> AdHoc
where F: FnOnce(&Cargo)
where F: FnOnce(&Rocket)
{
AdHoc { name, kind: AdHocKind::Launch(Mutex::new(Some(Box::new(f)))) }
}
@ -240,7 +239,7 @@ impl Fairing for AdHoc {
}
}
fn on_launch(&self, state: &Cargo) {
fn on_launch(&self, state: &Rocket) {
if let AdHocKind::Launch(ref mutex) = self.kind {
let mut opt = mutex.lock().expect("AdHoc::Launch lock");
let f = opt.take().expect("internal error: `on_launch` one-call invariant broken");

View File

@ -1,4 +1,4 @@
use crate::{Cargo, Rocket, Request, Response, Data};
use crate::{Rocket, Request, Response, Data};
use crate::fairing::{Fairing, Kind};
use crate::logger::PaintExt;
@ -52,9 +52,9 @@ impl Fairings {
}
#[inline(always)]
pub fn handle_launch(&self, cargo: &Cargo) {
pub fn handle_launch(&self, rocket: &Rocket) {
for &i in &self.launch {
self.all_fairings[i].on_launch(cargo);
self.all_fairings[i].on_launch(rocket);
}
}

View File

@ -47,7 +47,7 @@
//! of other `Fairings` are not jeopardized. For instance, unless it is made
//! abundantly clear, a fairing should not rewrite every request.
use crate::{Cargo, Rocket, Request, Response, Data};
use crate::{Rocket, Request, Response, Data};
mod fairings;
mod ad_hoc;
@ -196,7 +196,7 @@ pub use self::info_kind::{Info, Kind};
/// decorated with an attribute of `#[rocket::async_trait]`:
///
/// ```rust
/// use rocket::{Cargo, Rocket, Request, Data, Response};
/// use rocket::{Rocket, Request, Data, Response};
/// use rocket::fairing::{Fairing, Info, Kind};
///
/// # struct MyType;
@ -212,7 +212,7 @@ pub use self::info_kind::{Info, Kind};
/// # unimplemented!()
/// }
///
/// fn on_launch(&self, cargo: &Cargo) {
/// fn on_launch(&self, rocket: &Rocket) {
/// /* ... */
/// # unimplemented!()
/// }
@ -420,14 +420,14 @@ pub trait Fairing: Send + Sync + 'static {
///
/// This method is called just prior to launching the application if
/// `Kind::Launch` is in the `kind` field of the `Info` structure for this
/// fairing. The `Cargo` parameter corresponds to the application that
/// fairing. The `Rocket` parameter corresponds to the application that
/// will be launched.
///
/// ## Default Implementation
///
/// The default implementation of this method does nothing.
#[allow(unused_variables)]
fn on_launch(&self, cargo: &Cargo) {}
fn on_launch(&self, rocket: &Rocket) {}
/// The request callback.
///
@ -469,8 +469,8 @@ impl<T: Fairing> Fairing for std::sync::Arc<T> {
}
#[inline]
fn on_launch(&self, cargo: &Cargo) {
(self as &T).on_launch(cargo)
fn on_launch(&self, rocket: &Rocket) {
(self as &T).on_launch(rocket)
}
#[inline]

View File

@ -36,7 +36,7 @@
//!
//! ## Usage
//!
//! Depend on `rocket` in `Cargo.toml`:
//! Depend on `rocket` in `Rocket.toml`:
//!
//! ```toml
//! [dependencies]
@ -67,7 +67,7 @@
//! * **secrets:** Enables support for [private cookies].
//! * **tls:** Enables support for [TLS].
//!
//! The features can be enabled in `Cargo.toml`:
//! The features can be enabled in `Rocket.toml`:
//!
//! ```toml
//! [dependencies]
@ -146,7 +146,7 @@ mod ext;
#[doc(inline)] pub use crate::catcher::Catcher;
pub use crate::router::Route;
pub use crate::request::{Request, State};
pub use crate::rocket::{Cargo, Rocket};
pub use crate::rocket::Rocket;
pub use crate::shutdown::Shutdown;
/// Alias to [`Rocket::ignite()`] Creates a new instance of `Rocket`.

View File

@ -3,7 +3,7 @@ use std::borrow::Cow;
use parking_lot::RwLock;
use crate::local::asynchronous::{LocalRequest, LocalResponse};
use crate::rocket::{Rocket, Cargo};
use crate::rocket::Rocket;
use crate::http::{private::cookie, Method};
use crate::error::Error;
@ -48,7 +48,7 @@ use crate::error::Error;
/// # });
/// ```
pub struct Client {
cargo: Cargo,
rocket: Rocket,
cookies: RwLock<cookie::CookieJar>,
pub(in super) tracked: bool,
}
@ -59,9 +59,8 @@ impl Client {
tracked: bool
) -> Result<Client, Error> {
rocket.prelaunch_check().await?;
let cargo = rocket.into_cargo().await;
let cookies = RwLock::new(cookie::CookieJar::new());
Ok(Client { cargo, tracked, cookies })
Ok(Client { rocket, tracked, cookies })
}
// WARNING: This is unstable! Do not use this method outside of Rocket!
@ -79,8 +78,8 @@ impl Client {
}
#[inline(always)]
pub(crate) fn _cargo(&self) -> &Cargo {
&self.cargo
pub(crate) fn _rocket(&self) -> &Rocket {
&self.rocket
}
#[inline(always)]

View File

@ -3,7 +3,7 @@ use std::cell::RefCell;
use crate::error::Error;
use crate::local::{asynchronous, blocking::{LocalRequest, LocalResponse}};
use crate::rocket::{Rocket, Cargo};
use crate::rocket::Rocket;
use crate::http::Method;
/// A `blocking` client to construct and dispatch local requests.
@ -63,8 +63,8 @@ impl Client {
}
#[inline(always)]
fn _cargo(&self) -> &Cargo {
self.inner._cargo()
fn _rocket(&self) -> &Rocket {
self.inner._rocket()
}
#[inline(always)]

View File

@ -119,25 +119,7 @@ macro_rules! pub_client_impl {
/// ```
#[inline(always)]
pub fn rocket(&self) -> &Rocket {
&*self._cargo()
}
/// Returns a reference to the `Cargo` of the `Rocket` this client is
/// creating requests for.
///
/// # Example
///
/// ```rust
#[doc = $import]
///
/// # Client::_test(|client, _, _| {
/// let client: &Client = client;
/// let cargo = client.cargo();
/// # });
/// ```
#[inline(always)]
pub fn cargo(&self) -> &Cargo {
self._cargo()
&*self._rocket()
}
/// Returns a cookie jar containing all of the cookies this client is

View File

@ -1,6 +1,6 @@
use std::ops::Deref;
use crate::rocket::Cargo;
use crate::rocket::Rocket;
use crate::request::{self, FromRequest, Request};
use crate::outcome::Outcome;
use crate::http::Status;
@ -92,11 +92,9 @@ use crate::http::Status;
/// state.0.to_string()
/// }
///
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite().manage(MyManagedState(127));
/// let state = State::from(rocket.inspect().await).expect("managing `MyManagedState`");
/// let state = State::from(&rocket).expect("managed `MyManagedState`");
/// assert_eq!(handler(state), "127");
/// # });
/// ```
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct State<'r, T: Send + Sync + 'static>(&'r T);
@ -147,19 +145,16 @@ impl<'r, T: Send + Sync + 'static> State<'r, T> {
/// #[derive(Debug, PartialEq)]
/// struct Unmanaged(usize);
///
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite().manage(Managed(7));
/// let cargo = rocket.inspect().await;
/// let rocket = rocket::ignite().manage(Managed(7));
///
/// let state: Option<State<Managed>> = State::from(cargo);
/// let state: Option<State<Managed>> = State::from(&rocket);
/// assert_eq!(state.map(|s| s.inner()), Some(&Managed(7)));
///
/// let state: Option<State<Unmanaged>> = State::from(cargo);
/// let state: Option<State<Unmanaged>> = State::from(&rocket);
/// assert_eq!(state, None);
/// # });
/// ```
#[inline(always)]
pub fn from(rocket: &'r Cargo) -> Option<Self> {
pub fn from(rocket: &'r Rocket) -> Option<Self> {
rocket.state().map(State)
}
}

View File

@ -7,7 +7,6 @@ use futures::future::FutureExt;
use futures::stream::StreamExt;
use futures::future::{Future, BoxFuture};
use tokio::sync::{mpsc, oneshot};
use ref_cast::RefCast;
use yansi::Paint;
use state::Container;
@ -38,7 +37,6 @@ pub struct Rocket {
pub(crate) config: Config,
pub(crate) figment: Figment,
pub(crate) managed_state: Container,
manifest: Vec<PreLaunchOp>,
router: Router,
default_catcher: Option<Catcher>,
catchers: HashMap<u16, Catcher>,
@ -47,140 +45,9 @@ pub struct Rocket {
pub(crate) shutdown_handle: Shutdown,
}
/// An operation that occurs prior to launching a Rocket instance.
enum PreLaunchOp {
Mount(Origin<'static>, Vec<Route>),
Register(Vec<Catcher>),
Manage(&'static str, Box<dyn FnOnce(&mut Container) + Send + Sync + 'static>),
Attach(Box<dyn Fairing>),
}
/// A frozen view into the contents of an instance of `Rocket`.
///
/// Obtained via [`Rocket::inspect()`].
#[derive(RefCast)]
#[repr(transparent)]
pub struct Cargo(Rocket);
// A token returned to force the execution of one method before another.
pub(crate) struct Token;
impl Rocket {
#[inline]
fn _mount(&mut self, base: Origin<'static>, routes: Vec<Route>) {
// info!("[$]🛰 [/m]mounting [b]{}[/]:", log::emoji(), base);
// info!("[$]🛰 [/m]mounting [b]{}[/]:", log::emoji(), base);
// info!("{}[m]Mounting [b]{}[/]:[/]", log::emoji("🛰 "), base);
info!("{}{} {}{}",
Paint::emoji("🛰 "),
Paint::magenta("Mounting"),
Paint::blue(&base),
Paint::magenta(":"));
for route in routes {
let old_route = route.clone();
let route = route.map_base(|old| format!("{}{}", base, old))
.unwrap_or_else(|e| {
error_!("Route `{}` has a malformed URI.", old_route);
error_!("{}", e);
panic!("Invalid route URI.");
});
info_!("{}", route);
self.router.add(route);
}
}
#[inline]
fn _register(&mut self, catchers: Vec<Catcher>) {
info!("{}{}", Paint::emoji("👾 "), Paint::magenta("Catchers:"));
for catcher in catchers {
info_!("{}", catcher);
let existing = match catcher.code {
Some(code) => self.catchers.insert(code, catcher),
None => self.default_catcher.replace(catcher)
};
if let Some(existing) = existing {
warn_!("Replacing existing '{}' catcher.", existing);
}
}
}
#[inline]
async fn _attach(mut self, fairing: Box<dyn Fairing>) -> Self {
// Attach (and run attach-) fairings, which requires us to move `self`.
trace_!("Running attach fairing: {:?}", fairing.info());
let mut fairings = mem::replace(&mut self.fairings, Fairings::new());
self = fairings.attach(fairing, self).await;
// Note that `self.fairings` may now be non-empty! Move them to the end.
fairings.append(self.fairings);
self.fairings = fairings;
self
}
// Create a "dummy" instance of `Rocket` to use while mem-swapping `self`.
fn dummy() -> Rocket {
Rocket {
config: Config::debug_default(),
figment: Figment::from(Config::debug_default()),
manifest: vec![],
router: Router::new(),
default_catcher: None,
catchers: HashMap::new(),
managed_state: Container::new(),
fairings: Fairings::new(),
shutdown_handle: Shutdown(mpsc::channel(1).0),
shutdown_receiver: None,
}
}
// Instead of requiring the user to individually `await` each call to
// `attach()`, some operations are queued in `self.pending`. Functions that
// want to provide read access to any data from the Cargo, such as
// `inspect()`, need to apply those pending operations first.
//
// This function returns a future that executes those pending operations,
// requiring only a single `await` at the call site. After completion,
// `self.pending` will be empty and `self.manifest` will reflect all pending
// changes.
async fn actualize_manifest(&mut self) {
// Note: attach fairings may add more ops to the `manifest`! We
// process them as a stack to maintain proper ordering.
let mut manifest = mem::replace(&mut self.manifest, vec![]);
while !manifest.is_empty() {
trace_!("[MANIEST PROGRESS ({} left)]: {:?}", manifest.len(), manifest);
match manifest.remove(0) {
PreLaunchOp::Manage(_, callback) => callback(&mut self.managed_state),
PreLaunchOp::Mount(base, routes) => self._mount(base, routes),
PreLaunchOp::Register(catchers) => self._register(catchers),
PreLaunchOp::Attach(fairing) => {
let rocket = mem::replace(self, Rocket::dummy());
*self = rocket._attach(fairing).await;
self.manifest.append(&mut manifest);
manifest = mem::replace(&mut self.manifest, vec![]);
}
}
}
}
pub(crate) async fn into_cargo(mut self) -> Cargo {
self.actualize_manifest().await;
Cargo(self)
}
fn cargo(&self) -> &Cargo {
if !self.manifest.is_empty() {
panic!("internal error: immutable launch state with manifest");
}
Cargo::ref_cast(self)
}
}
// This function tries to hide all of the Hyper-ness from Rocket. It essentially
// converts Hyper types into Rocket types, then calls the `dispatch` function,
// which knows nothing about Hyper. Because responding depends on the
@ -506,7 +373,7 @@ impl Rocket {
// Run the launch fairings.
self.fairings.pretty_print_counts();
self.fairings.handle_launch(self.cargo());
self.fairings.handle_launch(&self);
// Determine the address and port we actually bound to.
self.config.port = listener.local_addr().map(|a| a.port()).unwrap_or(0);
@ -624,7 +491,6 @@ impl Rocket {
config, figment,
managed_state,
shutdown_handle: Shutdown(shutdown_sender),
manifest: vec![],
router: Router::new(),
default_catcher: None,
catchers: HashMap::new(),
@ -697,7 +563,25 @@ impl Rocket {
panic!("Invalid mount point.");
}
self.manifest.push(PreLaunchOp::Mount(base_uri, routes.into()));
info!("{}{} {}{}",
Paint::emoji("🛰 "),
Paint::magenta("Mounting"),
Paint::blue(&base_uri),
Paint::magenta(":"));
for route in routes.into() {
let old_route = route.clone();
let route = route.map_base(|old| format!("{}{}", base, old))
.unwrap_or_else(|e| {
error_!("Route `{}` has a malformed URI.", old_route);
error_!("{}", e);
panic!("Invalid route URI.");
});
info_!("{}", route);
self.router.add(route);
}
self
}
@ -726,7 +610,21 @@ impl Rocket {
/// ```
#[inline]
pub fn register(mut self, catchers: Vec<Catcher>) -> Self {
self.manifest.push(PreLaunchOp::Register(catchers));
info!("{}{}", Paint::emoji("👾 "), Paint::magenta("Catchers:"));
for catcher in catchers {
info_!("{}", catcher);
let existing = match catcher.code {
Some(code) => self.catchers.insert(code, catcher),
None => self.default_catcher.replace(catcher)
};
if let Some(existing) = existing {
warn_!("Replacing existing '{}' catcher.", existing);
}
}
self
}
@ -765,14 +663,12 @@ impl Rocket {
/// }
/// ```
#[inline]
pub fn manage<T: Send + Sync + 'static>(mut self, state: T) -> Self {
pub fn manage<T: Send + Sync + 'static>(self, state: T) -> Self {
let type_name = std::any::type_name::<T>();
self.manifest.push(PreLaunchOp::Manage(type_name, Box::new(move |managed| {
if !managed.set::<T>(state) {
if !self.managed_state.set(state) {
error!("State for type '{}' is already being managed!", type_name);
panic!("Aborting due to duplicately managed state.");
}
})));
self
}
@ -798,89 +694,125 @@ impl Rocket {
/// ```
#[inline]
pub fn attach<F: Fairing>(mut self, fairing: F) -> Self {
self.manifest.push(PreLaunchOp::Attach(Box::new(fairing)));
let future = async move {
let fairing = Box::new(fairing);
let mut fairings = mem::replace(&mut self.fairings, Fairings::new());
let rocket = fairings.attach(fairing, self).await;
(rocket, fairings)
};
let (rocket, mut fairings) = match tokio::runtime::Handle::try_current() {
Ok(handle) => {
// println!("Using existing runtime...");
std::thread::spawn(move || {
handle.block_on(future)
}).join().unwrap()
}
Err(_) => {
// println!("Using new runtime.");
std::thread::spawn(|| {
futures::executor::block_on(future)
}).join().unwrap()
}
};
self = rocket;
// Note that `self.fairings` may now be non-empty! Move them to the end.
fairings.append(self.fairings);
self.fairings = fairings;
self
}
/// Access the current state of this `Rocket` instance.
///
/// The `Cargo` type provides methods such as [`Cargo::routes()`]
/// and [`Cargo::state()`]. This method is called to get a `Cargo`
/// instance.
/// Returns an iterator over all of the routes mounted on this instance of
/// Rocket.
///
/// # Example
///
/// ```rust
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite();
/// let config = rocket.inspect().await.config();
/// # let _ = config;
/// # });
/// # #[macro_use] extern crate rocket;
/// use rocket::Rocket;
/// use rocket::fairing::AdHoc;
///
/// #[get("/hello")]
/// fn hello() -> &'static str {
/// "Hello, world!"
/// }
///
/// fn main() {
/// let mut rocket = rocket::ignite()
/// .mount("/", routes![hello])
/// .mount("/hi", routes![hello]);
///
/// for route in rocket.routes() {
/// match route.base() {
/// "/" => assert_eq!(route.uri.path(), "/hello"),
/// "/hi" => assert_eq!(route.uri.path(), "/hi/hello"),
/// _ => unreachable!("only /hello, /hi/hello are expected")
/// }
/// }
///
/// assert_eq!(rocket.routes().count(), 2);
/// }
/// ```
pub async fn inspect(&mut self) -> &Cargo {
self.actualize_manifest().await;
self.cargo()
#[inline(always)]
pub fn routes(&self) -> impl Iterator<Item = &Route> + '_ {
self.router.routes()
}
/// Returns `Some` of the managed state value for the type `T` if it is
/// being managed by `self`. Otherwise, returns `None`.
///
/// This function is equivalent to `.inspect().await.state()` and is
/// provided as a convenience.
///
/// # Example
///
/// ```rust
/// #[derive(PartialEq, Debug)]
/// struct MyState(&'static str);
///
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite().manage(MyState("hello!"));
/// assert_eq!(rocket.state::<MyState>().await, Some(&MyState("hello!")));
/// # });
/// let rocket = rocket::ignite().manage(MyState("hello!"));
/// assert_eq!(rocket.state::<MyState>(), Some(&MyState("hello!")));
/// ```
pub async fn state<T: Send + Sync + 'static>(&mut self) -> Option<&T> {
self.inspect().await.state()
#[inline(always)]
pub fn state<T: Send + Sync + 'static>(&self) -> Option<&T> {
self.managed_state.try_get()
}
/// Returns the figment.
///
/// This function is equivalent to `.inspect().await.figment()` and is
/// provided as a convenience.
/// Returns the figment for configured provider.
///
/// # Example
///
/// ```rust
/// use rocket::Rocket;
/// use rocket::fairing::AdHoc;
/// let rocket = rocket::ignite();
/// let figment = rocket.figment();
///
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite();
/// println!("Rocket config: {:?}", rocket.config().await);
/// # });
/// let port: u16 = figment.extract_inner("port").unwrap();
/// assert_eq!(port, rocket.config().port);
/// ```
pub async fn figment(&mut self) -> &Figment {
self.inspect().await.figment()
#[inline(always)]
pub fn figment(&self) -> &Figment {
&self.figment
}
/// Returns the config.
///
/// This function is equivalent to `.inspect().await.config()` and is
/// provided as a convenience.
/// Returns the active configuration.
///
/// # Example
///
/// ```rust
/// ```rust,no_run
/// # #[macro_use] extern crate rocket;
/// use rocket::Rocket;
/// use rocket::fairing::AdHoc;
///
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite();
/// println!("Rocket config: {:?}", rocket.config().await);
/// # });
/// #[launch]
/// fn rocket() -> rocket::Rocket {
/// rocket::ignite()
/// .attach(AdHoc::on_launch("Config Printer", |rocket| {
/// println!("Rocket launch config: {:?}", rocket.config());
/// }))
/// }
/// ```
pub async fn config(&mut self) -> &Config {
self.inspect().await.config()
#[inline(always)]
pub fn config(&self) -> &Config {
&self.config
}
/// Returns a handle which can be used to gracefully terminate this instance
@ -888,14 +820,12 @@ impl Rocket {
///
/// # Example
///
/// ```rust
/// ```rust,no_run
/// # use std::{thread, time::Duration};
/// #
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite();
/// let handle = rocket.inspect().await.shutdown();
/// let handle = rocket.shutdown();
///
/// # if false {
/// thread::spawn(move || {
/// thread::sleep(Duration::from_secs(10));
/// handle.shutdown();
@ -904,7 +834,6 @@ impl Rocket {
/// // Shuts down after 10 seconds
/// let shutdown_result = rocket.launch().await;
/// assert!(shutdown_result.is_ok());
/// # }
/// # });
/// ```
#[inline(always)]
@ -915,7 +844,6 @@ impl Rocket {
/// Perform "pre-launch" checks: verify that there are no routing colisions
/// and that there were no fairing failures.
pub(crate) async fn prelaunch_check(&mut self) -> Result<(), Error> {
self.actualize_manifest().await;
if let Err(e) = self.router.collisions() {
return Err(Error::new(ErrorKind::Collision(e)));
}
@ -1007,130 +935,3 @@ impl Rocket {
}
}
}
impl std::fmt::Debug for PreLaunchOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use PreLaunchOp::*;
match self {
Mount(origin, routes) => f.debug_tuple("PreLaunchOp::Mount")
.field(&origin)
.field(&routes)
.finish(),
Register(catchers) => f.debug_tuple("PreLaunchOp::Register")
.field(&catchers)
.finish(),
Manage(name, _) => f.debug_tuple("PreLaunchOp::Manage")
.field(&name)
.finish(),
Attach(fairing) => f.debug_tuple("PreLaunchOp::Attach")
.field(&fairing.info())
.finish()
}
}
}
impl std::ops::Deref for Cargo {
type Target = Rocket;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Cargo {
/// Returns an iterator over all of the routes mounted on this instance of
/// Rocket.
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::Rocket;
/// use rocket::fairing::AdHoc;
///
/// #[get("/hello")]
/// fn hello() -> &'static str {
/// "Hello, world!"
/// }
///
/// fn main() {
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite()
/// .mount("/", routes![hello])
/// .mount("/hi", routes![hello]);
///
/// for route in rocket.inspect().await.routes() {
/// match route.base() {
/// "/" => assert_eq!(route.uri.path(), "/hello"),
/// "/hi" => assert_eq!(route.uri.path(), "/hi/hello"),
/// _ => unreachable!("only /hello, /hi/hello are expected")
/// }
/// }
///
/// assert_eq!(rocket.inspect().await.routes().count(), 2);
/// # });
/// }
/// ```
#[inline(always)]
pub fn routes(&self) -> impl Iterator<Item = &Route> + '_ {
self.0.router.routes()
}
/// Returns `Some` of the managed state value for the type `T` if it is
/// being managed by `self`. Otherwise, returns `None`.
///
/// # Example
///
/// ```rust
/// #[derive(PartialEq, Debug)]
/// struct MyState(&'static str);
///
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite().manage(MyState("hello!"));
///
/// let cargo = rocket.inspect().await;
/// assert_eq!(cargo.state::<MyState>(), Some(&MyState("hello!")));
/// # });
/// ```
#[inline(always)]
pub fn state<T: Send + Sync + 'static>(&self) -> Option<&T> {
self.0.managed_state.try_get()
}
/// Returns the figment for configured provider.
///
/// # Example
///
/// ```rust,no_run
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite();
/// let figment = rocket.inspect().await.figment();
/// # });
/// ```
#[inline(always)]
pub fn figment(&self) -> &Figment {
&self.0.figment
}
/// Returns the active configuration.
///
/// # Example
///
/// ```rust,no_run
/// # #[macro_use] extern crate rocket;
/// use rocket::Rocket;
/// use rocket::fairing::AdHoc;
///
/// #[launch]
/// fn rocket() -> rocket::Rocket {
/// rocket::ignite()
/// .attach(AdHoc::on_launch("Config Printer", |cargo| {
/// println!("Rocket launch config: {:?}", cargo.config());
/// }))
/// }
/// ```
#[inline(always)]
pub fn config(&self) -> &Config {
&self.0.config
}
}

View File

@ -2,42 +2,43 @@ use rocket::fairing::AdHoc;
#[rocket::async_test]
async fn test_inspectable_attach_state() {
let mut rocket = rocket::ignite()
let rocket = rocket::ignite()
.attach(AdHoc::on_attach("Add State", |rocket| async {
Ok(rocket.manage("Hi!"))
}));
let state = rocket.inspect().await;
assert_eq!(state.state::<&'static str>(), Some(&"Hi!"));
let state = rocket.state::<&'static str>();
assert_eq!(state, Some(&"Hi!"));
}
#[rocket::async_test]
async fn test_inspectable_attach_state_in_future_attach() {
let mut rocket = rocket::ignite()
let rocket = rocket::ignite()
.attach(AdHoc::on_attach("Add State", |rocket| async {
Ok(rocket.manage("Hi!"))
}))
.attach(AdHoc::on_attach("Inspect State", |mut rocket| async {
let state = rocket.inspect().await;
assert_eq!(state.state::<&'static str>(), Some(&"Hi!"));
.attach(AdHoc::on_attach("Inspect State", |rocket| async {
let state = rocket.state::<&'static str>();
assert_eq!(state, Some(&"Hi!"));
Ok(rocket)
}));
let _ = rocket.inspect().await;
let state = rocket.state::<&'static str>();
assert_eq!(state, Some(&"Hi!"));
}
#[rocket::async_test]
async fn test_attach_state_is_well_ordered() {
let mut rocket = rocket::ignite()
.attach(AdHoc::on_attach("Inspect State Pre", |mut rocket| async {
let state = rocket.inspect().await;
assert_eq!(state.state::<&'static str>(), None);
let rocket = rocket::ignite()
.attach(AdHoc::on_attach("Inspect State Pre", |rocket| async {
let state = rocket.state::<&'static str>();
assert_eq!(state, None);
Ok(rocket)
}))
.attach(AdHoc::on_attach("Add State", |rocket| async {
Ok(rocket.manage("Hi!"))
}));
let state = rocket.inspect().await;
assert_eq!(state.state::<&'static str>(), Some(&"Hi!"));
let state = rocket.state::<&'static str>();
assert_eq!(state, Some(&"Hi!"));
}

View File

@ -1,7 +1,7 @@
struct A;
#[rocket::async_test]
#[test]
#[should_panic]
async fn twice_managed_state() {
let _ = rocket::ignite().manage(A).manage(A).inspect().await;
fn twice_managed_state() {
let _ = rocket::ignite().manage(A).manage(A);
}

View File

@ -1,8 +1,8 @@
use rocket::config::{Config, LogLevel};
async fn test_config(profile: &str) {
let mut rocket = rocket::custom(Config::figment().select(profile));
let config = rocket.config().await;
fn test_config(profile: &str) {
let rocket = rocket::custom(Config::figment().select(profile));
let config = rocket.config();
match &*profile {
"debug" => {
assert_eq!(config.address, std::net::Ipv4Addr::LOCALHOST);
@ -25,12 +25,12 @@ async fn test_config(profile: &str) {
}
}
#[rocket::async_test]
async fn test_debug_config() {
test_config("debug").await
#[test]
fn test_debug_config() {
test_config("debug")
}
#[rocket::async_test]
async fn test_release_config() {
test_config("release").await
#[test]
fn test_release_config() {
test_config("release")
}

View File

@ -40,11 +40,11 @@ fn test_index() {
// Render the template with an empty context.
let mut context: HashMap<&str, &str> = HashMap::new();
let template = Template::show(client.cargo(), "index", &context).unwrap();
let template = Template::show(client.rocket(), "index", &context).unwrap();
test_body(None, template);
// Render the template with a context that contains the message.
context.insert("message", "Hello from Rocket!");
let template = Template::show(client.cargo(), "index", &context).unwrap();
let template = Template::show(client.rocket(), "index", &context).unwrap();
test_body(Some(Cookie::new("message", "Hello from Rocket!")), template);
}

View File

@ -66,9 +66,9 @@ fn rocket() -> rocket::Rocket {
rocket::ignite()
.mount("/", routes![hello, token])
.attach(Counter::default())
.attach(AdHoc::on_attach("Token State", |mut rocket| async {
.attach(AdHoc::on_attach("Token State", |rocket| async {
println!("Adding token managed state...");
match rocket.figment().await.extract_inner("token") {
match rocket.figment().extract_inner("token") {
Ok(value) => Ok(rocket.manage(Token(value))),
Err(_) => Err(rocket)
}

View File

@ -31,7 +31,7 @@ fn test_root() {
dispatch!(*method, "/", |client, response| {
let mut map = std::collections::HashMap::new();
map.insert("path", "/");
let expected = Template::show(client.cargo(), "error/404", &map).unwrap();
let expected = Template::show(client.rocket(), "error/404", &map).unwrap();
assert_eq!(response.status(), Status::NotFound);
assert_eq!(response.into_string(), Some(expected));
@ -50,7 +50,7 @@ fn test_name() {
parent: "layout",
};
let expected = Template::show(client.cargo(), "index", &context).unwrap();
let expected = Template::show(client.rocket(), "index", &context).unwrap();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.into_string(), Some(expected));
});
@ -63,7 +63,7 @@ fn test_404() {
let mut map = std::collections::HashMap::new();
map.insert("path", "/hello/");
let expected = Template::show(client.cargo(), "error/404", &map).unwrap();
let expected = Template::show(client.rocket(), "error/404", &map).unwrap();
assert_eq!(response.status(), Status::NotFound);
assert_eq!(response.into_string(), Some(expected));
});

View File

@ -8,13 +8,13 @@ fn test() {
let client = Client::tracked(rocket()).unwrap();
client.get("/sync").dispatch();
let atomics = client.cargo().state::<Atomics>().unwrap();
let atomics = client.rocket().state::<Atomics>().unwrap();
assert_eq!(atomics.uncached.load(Ordering::Relaxed), 2);
assert_eq!(atomics.cached.load(Ordering::Relaxed), 1);
client.get("/async").dispatch();
let atomics = client.cargo().state::<Atomics>().unwrap();
let atomics = client.rocket().state::<Atomics>().unwrap();
assert_eq!(atomics.uncached.load(Ordering::Relaxed), 4);
assert_eq!(atomics.cached.load(Ordering::Relaxed), 2);
}

View File

@ -25,17 +25,15 @@ fn test_count() {
assert_eq!(get_count(&client), 100);
}
#[rocket::async_test]
async fn test_raw_state_count() {
#[test]
fn test_raw_state_count() {
use rocket::State;
use super::{count, index};
let mut rocket = super::rocket();
let cargo = rocket.inspect().await;
assert_eq!(count(State::from(cargo).unwrap()), "0");
assert!(index(State::from(cargo).unwrap()).0.contains("Visits: 1"));
assert_eq!(count(State::from(cargo).unwrap()), "1");
let rocket = super::rocket();
assert_eq!(count(State::from(&rocket).unwrap()), "0");
assert!(index(State::from(&rocket).unwrap()).0.contains("Visits: 1"));
assert_eq!(count(State::from(&rocket).unwrap()), "1");
}
// Cargo runs each test in parallel on different threads. We use all of these

View File

@ -30,7 +30,7 @@ fn test_root() {
dispatch!(*method, "/", |client, response| {
let mut map = std::collections::HashMap::new();
map.insert("path", "/");
let expected = Template::show(client.cargo(), "error/404", &map).unwrap();
let expected = Template::show(client.rocket(), "error/404", &map).unwrap();
assert_eq!(response.status(), Status::NotFound);
assert_eq!(response.into_string(), Some(expected));
@ -47,7 +47,7 @@ fn test_name() {
items: vec!["One", "Two", "Three"]
};
let expected = Template::show(client.cargo(), "index", &context).unwrap();
let expected = Template::show(client.rocket(), "index", &context).unwrap();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.into_string(), Some(expected));
});
@ -60,7 +60,7 @@ fn test_404() {
let mut map = std::collections::HashMap::new();
map.insert("path", "/hello/");
let expected = Template::show(client.cargo(), "error/404", &map).unwrap();
let expected = Template::show(client.rocket(), "error/404", &map).unwrap();
assert_eq!(response.status(), Status::NotFound);
assert_eq!(response.into_string(), Some(expected));
});

View File

@ -95,8 +95,8 @@ async fn index(msg: Option<FlashMessage<'_, '_>>, conn: DbConn) -> Template {
Template::render("index", Context::raw(&conn, msg).await)
}
async fn run_db_migrations(mut rocket: Rocket) -> Result<Rocket, Rocket> {
DbConn::get_one(rocket.inspect().await).await
async fn run_db_migrations(rocket: Rocket) -> Result<Rocket, Rocket> {
DbConn::get_one(&rocket).await
.expect("database connection")
.run(|c| match embedded_migrations::run(c) {
Ok(()) => Ok(rocket),
@ -112,8 +112,8 @@ fn rocket() -> Rocket {
rocket::ignite()
.attach(DbConn::fairing())
.attach(AdHoc::on_attach("Database Migrations", run_db_migrations))
.attach(Template::fairing())
.mount("/", StaticFiles::from(crate_relative!("/static")))
.mount("/", routes![index])
.mount("/todo", routes![new, toggle, delete])
.attach(Template::fairing())
}

View File

@ -18,7 +18,7 @@ macro_rules! run_test {
rocket::async_test(async move {
let rocket = super::rocket();
let $client = Client::tracked(rocket).await.expect("Rocket client");
let db = super::DbConn::get_one($client.cargo()).await;
let db = super::DbConn::get_one($client.rocket()).await;
let $conn = db.expect("failed to get database connection for testing");
Task::delete_all(&$conn).await.expect("failed to delete all tasks for testing");

View File

@ -190,8 +190,7 @@ ROCKET_DICT={key="abc",val=123}
## Extracting Values
Your application can extract any configuration that implements [`Deserialize`]
from the configured provider, which is exposed via [`Rocket::figment()`] and
[`Cargo::figment()`]:
from the configured provider, which is exposed via [`Rocket::figment()`]:
```rust
# #[macro_use] extern crate rocket;
@ -201,9 +200,9 @@ use serde::Deserialize;
#[launch]
async fn rocket() -> _ {
let mut rocket = rocket::ignite();
let figment = rocket.figment().await;
fn rocket() -> _ {
let rocket = rocket::ignite();
let figment = rocket.figment();
#[derive(Deserialize)]
struct Config {
@ -256,7 +255,6 @@ fn rocket() -> _ {
```
[`Rocket::figment()`]: @api/rocket/struct.Rocket.html#method.figment
[`Cargo::figment()`]: @api/rocket/struct.Cargo.html#method.figment
## Custom Providers