rocket/rkt.rs
1use std::fmt;
2use std::ops::{Deref, DerefMut};
3use std::net::SocketAddr;
4
5use yansi::Paint;
6use either::Either;
7use figment::{Figment, Provider};
8
9use crate::{Catcher, Config, Route, Shutdown, sentinel, shield::Shield};
10use crate::router::Router;
11use crate::trip_wire::TripWire;
12use crate::fairing::{Fairing, Fairings};
13use crate::phase::{Phase, Build, Building, Ignite, Igniting, Orbit, Orbiting};
14use crate::phase::{Stateful, StateRef, State};
15use crate::http::uri::{self, Origin};
16use crate::http::ext::IntoOwned;
17use crate::error::{Error, ErrorKind};
18use crate::log::PaintExt;
19
20/// The application server itself.
21///
22/// # Phases
23///
24/// A `Rocket` instance represents a web server and its state. It progresses
25/// through three statically-enforced phases: build, ignite, orbit.
26///
27/// * **Build**: _application and server configuration_
28///
29/// This phase enables:
30///
31/// * setting configuration options
32/// * mounting/registering routes/catchers
33/// * managing state
34/// * attaching fairings
35///
36/// This is the _only_ phase in which an instance can be modified. To finalize
37/// changes, an instance is ignited via [`Rocket::ignite()`], progressing it
38/// into the _ignite_ phase, or directly launched into orbit with
39/// [`Rocket::launch()`] which progress the instance through ignite into
40/// orbit.
41///
42/// * **Ignite**: _verification and finalization of configuration_
43///
44/// An instance in the [`Ignite`] phase is in its final configuration,
45/// available via [`Rocket::config()`]. Barring user-supplied interior
46/// mutation, application state is guaranteed to remain unchanged beyond this
47/// point. An instance in the ignite phase can be launched into orbit to serve
48/// requests via [`Rocket::launch()`].
49///
50/// * **Orbit**: _a running web server_
51///
52/// An instance in the [`Orbit`] phase represents a _running_ application,
53/// actively serving requests.
54///
55/// # Launching
56///
57/// To launch a `Rocket` application, the suggested approach is to return an
58/// instance of `Rocket<Build>` from a function named `rocket` marked with the
59/// [`#[launch]`](crate::launch) attribute:
60///
61/// ```rust,no_run
62/// # use rocket::launch;
63/// #[launch]
64/// fn rocket() -> _ {
65/// rocket::build()
66/// }
67/// ```
68///
69/// This generates a `main` function with an `async` runtime that runs the
70/// returned `Rocket` instance.
71///
72/// * **Manual Launching**
73///
74/// To launch an instance of `Rocket`, it _must_ progress through all three
75/// phases. To progress into the ignite or launch phases, a tokio `async`
76/// runtime is required. The [`#[main]`](crate::main) attribute initializes a
77/// Rocket-specific tokio runtime and runs the attributed `async fn` inside of
78/// it:
79///
80/// ```rust,no_run
81/// #[rocket::main]
82/// async fn main() -> Result<(), rocket::Error> {
83/// let _rocket = rocket::build()
84/// .ignite().await?
85/// .launch().await?;
86///
87/// Ok(())
88/// }
89/// ```
90///
91/// Note that [`Rocket::launch()`] automatically progresses an instance of
92/// `Rocket` from any phase into orbit:
93///
94/// ```rust,no_run
95/// #[rocket::main]
96/// async fn main() -> Result<(), rocket::Error> {
97/// let _rocket = rocket::build().launch().await?;
98/// Ok(())
99/// }
100/// ```
101///
102/// For extreme and rare cases in which [`#[main]`](crate::main) imposes
103/// obstinate restrictions, use [`rocket::execute()`](crate::execute()) to
104/// execute Rocket's `launch()` future.
105///
106/// * **Automatic Launching**
107///
108/// Manually progressing an instance of Rocket though its phases is only
109/// necessary when either an instance's finalized state is to be inspected (in
110/// the _ignite_ phase) or the instance is expected to deorbit due to
111/// [`Rocket::shutdown()`]. In the more common case when neither is required,
112/// the [`#[launch]`](crate::launch) attribute can be used. When applied to a
113/// function that returns a `Rocket<Build>`, it automatically initializes an
114/// `async` runtime and launches the function's returned instance:
115///
116/// ```rust,no_run
117/// # use rocket::launch;
118/// use rocket::{Rocket, Build};
119///
120/// #[launch]
121/// fn rocket() -> Rocket<Build> {
122/// rocket::build()
123/// }
124/// ```
125///
126/// To avoid needing to import _any_ items in the common case, the `launch`
127/// attribute will infer a return type written as `_` as `Rocket<Build>`:
128///
129/// ```rust,no_run
130/// # use rocket::launch;
131/// #[launch]
132/// fn rocket() -> _ {
133/// rocket::build()
134/// }
135/// ```
136pub struct Rocket<P: Phase>(pub(crate) P::State);
137
138impl Rocket<Build> {
139 /// Create a new `Rocket` application using the default configuration
140 /// provider, [`Config::figment()`].
141 ///
142 /// This method is typically called through the
143 /// [`rocket::build()`](crate::build) alias.
144 ///
145 /// # Examples
146 ///
147 /// ```rust
148 /// # use rocket::launch;
149 /// #[launch]
150 /// fn rocket() -> _ {
151 /// rocket::build()
152 /// }
153 /// ```
154 #[must_use]
155 #[inline(always)]
156 pub fn build() -> Self {
157 Rocket::custom(Config::figment())
158 }
159
160 /// Creates a new `Rocket` application using the supplied configuration
161 /// provider.
162 ///
163 /// This method is typically called through the
164 /// [`rocket::custom()`](crate::custom()) alias.
165 ///
166 /// # Example
167 ///
168 /// ```rust
169 /// # use rocket::launch;
170 /// use rocket::figment::{Figment, providers::{Toml, Env, Format}};
171 ///
172 /// #[launch]
173 /// fn rocket() -> _ {
174 /// let figment = Figment::from(rocket::Config::default())
175 /// .merge(Toml::file("MyApp.toml").nested())
176 /// .merge(Env::prefixed("MY_APP_").global());
177 ///
178 /// rocket::custom(figment)
179 /// }
180 /// ```
181 #[must_use]
182 pub fn custom<T: Provider>(provider: T) -> Self {
183 // We initialize the logger here so that logging from fairings and so on
184 // are visible; we use the final config to set a max log-level in ignite
185 crate::log::init_default();
186
187 let rocket: Rocket<Build> = Rocket(Building {
188 figment: Figment::from(provider),
189 ..Default::default()
190 });
191
192 rocket.attach(Shield::default())
193 }
194
195 /// Sets the configuration provider in `self` to `provider`.
196 ///
197 /// A [`Figment`] generated from the current `provider` can _always_ be
198 /// retrieved via [`Rocket::figment()`]. However, because the provider can
199 /// be changed at any point prior to ignition, a [`Config`] can only be
200 /// retrieved in the ignite or orbit phases, or by manually extracting one
201 /// from a particular figment.
202 ///
203 /// # Example
204 ///
205 /// ```rust
206 /// use rocket::Config;
207 /// # use std::net::Ipv4Addr;
208 /// # use std::path::{Path, PathBuf};
209 /// # type Result = std::result::Result<(), rocket::Error>;
210 ///
211 /// let config = Config {
212 /// port: 7777,
213 /// address: Ipv4Addr::new(18, 127, 0, 1).into(),
214 /// temp_dir: "/tmp/config-example".into(),
215 /// ..Config::debug_default()
216 /// };
217 ///
218 /// # let _: Result = rocket::async_test(async move {
219 /// let rocket = rocket::custom(&config).ignite().await?;
220 /// assert_eq!(rocket.config().port, 7777);
221 /// assert_eq!(rocket.config().address, Ipv4Addr::new(18, 127, 0, 1));
222 /// assert_eq!(rocket.config().temp_dir.relative(), Path::new("/tmp/config-example"));
223 ///
224 /// // Create a new figment which modifies _some_ keys the existing figment:
225 /// let figment = rocket.figment().clone()
226 /// .merge((Config::PORT, 8888))
227 /// .merge((Config::ADDRESS, "171.64.200.10"));
228 ///
229 /// let rocket = rocket::custom(&config)
230 /// .configure(figment)
231 /// .ignite().await?;
232 ///
233 /// assert_eq!(rocket.config().port, 8888);
234 /// assert_eq!(rocket.config().address, Ipv4Addr::new(171, 64, 200, 10));
235 /// assert_eq!(rocket.config().temp_dir.relative(), Path::new("/tmp/config-example"));
236 /// # Ok(())
237 /// # });
238 /// ```
239 #[must_use]
240 pub fn configure<T: Provider>(mut self, provider: T) -> Self {
241 self.figment = Figment::from(provider);
242 self
243 }
244
245 #[track_caller]
246 fn load<'a, B, T, F, M>(mut self, kind: &str, base: B, items: Vec<T>, m: M, f: F) -> Self
247 where B: TryInto<Origin<'a>> + Clone + fmt::Display,
248 B::Error: fmt::Display,
249 M: Fn(&Origin<'a>, T) -> Result<T, uri::Error<'static>>,
250 F: Fn(&mut Self, T),
251 T: Clone + fmt::Display,
252 {
253 let mut base = match base.clone().try_into() {
254 Ok(origin) => origin.into_owned(),
255 Err(e) => {
256 error!("invalid {} base: {}", kind, Paint::white(&base));
257 error_!("{}", e);
258 info_!("{} {}", "in".primary(), std::panic::Location::caller());
259 panic!("aborting due to {} base error", kind);
260 }
261 };
262
263 if base.query().is_some() {
264 warn!("query in {} base '{}' is ignored", kind, Paint::white(&base));
265 base.clear_query();
266 }
267
268 for unmounted_item in items {
269 let item = match m(&base, unmounted_item.clone()) {
270 Ok(item) => item,
271 Err(e) => {
272 error!("malformed URI in {} {}", kind, unmounted_item);
273 error_!("{}", e);
274 info_!("{} {}", Paint::white("in"), std::panic::Location::caller());
275 panic!("aborting due to invalid {} URI", kind);
276 }
277 };
278
279 f(&mut self, item)
280 }
281
282 self
283 }
284
285 /// Mounts all of the routes in the supplied vector at the given `base`
286 /// path. Mounting a route with path `path` at path `base` makes the route
287 /// available at `base/path`.
288 ///
289 /// # Panics
290 ///
291 /// Panics if either:
292 /// * the `base` mount point is not a valid static path: a valid origin
293 /// URI without dynamic parameters.
294 ///
295 /// * any route's URI is not a valid origin URI.
296 ///
297 /// **Note:** _This kind of panic is guaranteed not to occur if the routes
298 /// were generated using Rocket's code generation._
299 ///
300 /// # Examples
301 ///
302 /// Use the `routes!` macro to mount routes created using the code
303 /// generation facilities. Requests to the `/hello/world` URI will be
304 /// dispatched to the `hi` route.
305 ///
306 /// ```rust,no_run
307 /// # #[macro_use] extern crate rocket;
308 /// #
309 /// #[get("/world")]
310 /// fn hi() -> &'static str {
311 /// "Hello!"
312 /// }
313 ///
314 /// #[launch]
315 /// fn rocket() -> _ {
316 /// rocket::build().mount("/hello", routes![hi])
317 /// }
318 /// ```
319 ///
320 /// Manually create a route named `hi` at path `"/world"` mounted at base
321 /// `"/hello"`. Requests to the `/hello/world` URI will be dispatched to the
322 /// `hi` route.
323 ///
324 /// ```rust
325 /// # #[macro_use] extern crate rocket;
326 /// use rocket::{Request, Route, Data, route};
327 /// use rocket::http::Method;
328 ///
329 /// fn hi<'r>(req: &'r Request, _: Data<'r>) -> route::BoxFuture<'r> {
330 /// route::Outcome::from(req, "Hello!").pin()
331 /// }
332 ///
333 /// #[launch]
334 /// fn rocket() -> _ {
335 /// let hi_route = Route::new(Method::Get, "/world", hi);
336 /// rocket::build().mount("/hello", vec![hi_route])
337 /// }
338 /// ```
339 #[must_use]
340 #[track_caller]
341 pub fn mount<'a, B, R>(self, base: B, routes: R) -> Self
342 where B: TryInto<Origin<'a>> + Clone + fmt::Display,
343 B::Error: fmt::Display,
344 R: Into<Vec<Route>>
345 {
346 self.load("route", base, routes.into(),
347 |base, route| route.map_base(|old| format!("{}{}", base, old)),
348 |r, route| r.0.routes.push(route))
349 }
350
351 /// Registers all of the catchers in the supplied vector, scoped to `base`.
352 ///
353 /// # Panics
354 ///
355 /// Panics if `base` is not a valid static path: a valid origin URI without
356 /// dynamic parameters.
357 ///
358 /// # Examples
359 ///
360 /// ```rust,no_run
361 /// # #[macro_use] extern crate rocket;
362 /// use rocket::Request;
363 ///
364 /// #[catch(500)]
365 /// fn internal_error() -> &'static str {
366 /// "Whoops! Looks like we messed up."
367 /// }
368 ///
369 /// #[catch(404)]
370 /// fn not_found(req: &Request) -> String {
371 /// format!("I couldn't find '{}'. Try something else?", req.uri())
372 /// }
373 ///
374 /// #[launch]
375 /// fn rocket() -> _ {
376 /// rocket::build().register("/", catchers![internal_error, not_found])
377 /// }
378 /// ```
379 #[must_use]
380 pub fn register<'a, B, C>(self, base: B, catchers: C) -> Self
381 where B: TryInto<Origin<'a>> + Clone + fmt::Display,
382 B::Error: fmt::Display,
383 C: Into<Vec<Catcher>>
384 {
385 self.load("catcher", base, catchers.into(),
386 |base, catcher| catcher.map_base(|old| format!("{}{}", base, old)),
387 |r, catcher| r.0.catchers.push(catcher))
388 }
389
390 /// Add `state` to the state managed by this instance of Rocket.
391 ///
392 /// This method can be called any number of times as long as each call
393 /// refers to a different `T`.
394 ///
395 /// Managed state can be retrieved by any request handler via the
396 /// [`State`](crate::State) request guard. In particular, if a value of type `T`
397 /// is managed by Rocket, adding `State<T>` to the list of arguments in a
398 /// request handler instructs Rocket to retrieve the managed value.
399 ///
400 /// # Panics
401 ///
402 /// Panics if state of type `T` is already being managed.
403 ///
404 /// # Example
405 ///
406 /// ```rust,no_run
407 /// # #[macro_use] extern crate rocket;
408 /// use rocket::State;
409 ///
410 /// struct MyInt(isize);
411 /// struct MyString(String);
412 ///
413 /// #[get("/int")]
414 /// fn int(state: &State<MyInt>) -> String {
415 /// format!("The stateful int is: {}", state.0)
416 /// }
417 ///
418 /// #[get("/string")]
419 /// fn string(state: &State<MyString>) -> &str {
420 /// &state.0
421 /// }
422 ///
423 /// #[launch]
424 /// fn rocket() -> _ {
425 /// rocket::build()
426 /// .manage(MyInt(10))
427 /// .manage(MyString("Hello, managed state!".to_string()))
428 /// .mount("/", routes![int, string])
429 /// }
430 /// ```
431 #[must_use]
432 pub fn manage<T>(self, state: T) -> Self
433 where T: Send + Sync + 'static
434 {
435 let type_name = std::any::type_name::<T>();
436 if !self.state.set(state) {
437 error!("state for type '{}' is already being managed", type_name);
438 panic!("aborting due to duplicated managed state");
439 }
440
441 self
442 }
443
444 /// Attaches a fairing to this instance of Rocket. No fairings are eagerly
445 /// executed; fairings are executed at their appropriate time.
446 ///
447 /// If the attached fairing is _fungible_ and a fairing of the same name
448 /// already exists, this fairing replaces it.
449 ///
450 /// # Example
451 ///
452 /// ```rust,no_run
453 /// # #[macro_use] extern crate rocket;
454 /// use rocket::Rocket;
455 /// use rocket::fairing::AdHoc;
456 ///
457 /// #[launch]
458 /// fn rocket() -> _ {
459 /// rocket::build()
460 /// .attach(AdHoc::on_liftoff("Liftoff Message", |_| Box::pin(async {
461 /// println!("We have liftoff!");
462 /// })))
463 /// }
464 /// ```
465 #[must_use]
466 pub fn attach<F: Fairing>(mut self, fairing: F) -> Self {
467 self.fairings.add(Box::new(fairing));
468 self
469 }
470
471 /// Returns a `Future` that transitions this instance of `Rocket` into the
472 /// _ignite_ phase.
473 ///
474 /// When `await`ed, the future runs all _ignite_ fairings in serial,
475 /// [attach](Rocket::attach()) order, and verifies that `self` represents a
476 /// valid instance of `Rocket` ready for launch. This means that:
477 ///
478 /// * All ignite fairings succeeded.
479 /// * A valid [`Config`] was extracted from [`Rocket::figment()`].
480 /// * If `secrets` are enabled, the extracted `Config` contains a safe
481 /// secret key.
482 /// * There are no [`Route#collisions`] or [`Catcher#collisions`]
483 /// collisions.
484 /// * No [`Sentinel`](crate::Sentinel) triggered an abort.
485 ///
486 /// If any of these conditions fail to be met, a respective [`Error`] is
487 /// returned.
488 ///
489 /// [configured]: Rocket::figment()
490 ///
491 /// # Example
492 ///
493 /// ```rust
494 /// use rocket::fairing::AdHoc;
495 ///
496 /// #[rocket::main]
497 /// async fn main() -> Result<(), rocket::Error> {
498 /// let rocket = rocket::build()
499 /// # .configure(rocket::Config::debug_default())
500 /// .attach(AdHoc::on_ignite("Manage State", |rocket| async move {
501 /// rocket.manage(String::from("managed string"))
502 /// }));
503 ///
504 /// // No fairings are run until ignition occurs.
505 /// assert!(rocket.state::<String>().is_none());
506 ///
507 /// let rocket = rocket.ignite().await?;
508 /// assert_eq!(rocket.state::<String>().unwrap(), "managed string");
509 ///
510 /// Ok(())
511 /// }
512 /// ```
513 pub async fn ignite(mut self) -> Result<Rocket<Ignite>, Error> {
514 self = Fairings::handle_ignite(self).await;
515 self.fairings.audit().map_err(|f| ErrorKind::FailedFairings(f.to_vec()))?;
516
517 // Extract the configuration; initialize the logger.
518 #[allow(unused_mut)]
519 let mut config = Config::try_from(&self.figment).map_err(ErrorKind::Config)?;
520 crate::log::init(&config);
521
522 // Check for safely configured secrets.
523 #[cfg(feature = "secrets")]
524 if !config.secret_key.is_provided() {
525 if config.profile != Config::DEBUG_PROFILE {
526 return Err(Error::new(ErrorKind::InsecureSecretKey(config.profile.clone())));
527 }
528
529 if config.secret_key.is_zero() {
530 config.secret_key = crate::config::SecretKey::generate()
531 .unwrap_or_else(crate::config::SecretKey::zero);
532 }
533 } else if config.known_secret_key_used() {
534 warn!("The configured `secret_key` is exposed and insecure.");
535 warn_!("The configured key is publicly published and thus insecure.");
536 warn_!("Try generating a new key with `head -c64 /dev/urandom | base64`.");
537 }
538
539 // Initialize the router; check for collisions.
540 let mut router = Router::new();
541 self.routes.clone().into_iter().for_each(|r| router.add_route(r));
542 self.catchers.clone().into_iter().for_each(|c| router.add_catcher(c));
543 router.finalize().map_err(ErrorKind::Collisions)?;
544
545 // Finally, freeze managed state.
546 self.state.freeze();
547
548 // Log everything we know: config, routes, catchers, fairings.
549 // TODO: Store/print managed state type names?
550 config.pretty_print(self.figment());
551 log_items("📬 ", "Routes", self.routes(), |r| &r.uri.base, |r| &r.uri);
552 log_items("🥅 ", "Catchers", self.catchers(), |c| &c.base, |c| &c.base);
553 self.fairings.pretty_print();
554
555 // Ignite the rocket.
556 let rocket: Rocket<Ignite> = Rocket(Igniting {
557 router, config,
558 shutdown: Shutdown(TripWire::new()),
559 figment: self.0.figment,
560 fairings: self.0.fairings,
561 state: self.0.state,
562 });
563
564 // Query the sentinels, abort if requested.
565 let sentinels = rocket.routes().flat_map(|r| r.sentinels.iter());
566 sentinel::query(sentinels, &rocket).map_err(ErrorKind::SentinelAborts)?;
567
568 Ok(rocket)
569 }
570}
571
572fn log_items<T, I, B, O>(e: &str, t: &str, items: I, base: B, origin: O)
573 where T: fmt::Display + Copy, I: Iterator<Item = T>,
574 B: Fn(&T) -> &Origin<'_>, O: Fn(&T) -> &Origin<'_>
575{
576 let mut items: Vec<_> = items.collect();
577 if !items.is_empty() {
578 launch_meta!("{}{}:", e.emoji(), t.magenta());
579 }
580
581 items.sort_by_key(|i| origin(i).path().as_str().chars().count());
582 items.sort_by_key(|i| origin(i).path().segments().len());
583 items.sort_by_key(|i| base(i).path().as_str().chars().count());
584 items.sort_by_key(|i| base(i).path().segments().len());
585 items.iter().for_each(|i| launch_meta_!("{}", i));
586}
587
588impl Rocket<Ignite> {
589 /// Returns the finalized, active configuration. This is guaranteed to
590 /// remain stable through ignition and into orbit.
591 ///
592 /// # Example
593 ///
594 /// ```rust,no_run
595 /// #[rocket::main]
596 /// async fn main() -> Result<(), rocket::Error> {
597 /// let rocket = rocket::build().ignite().await?;
598 /// let config = rocket.config();
599 /// Ok(())
600 /// }
601 /// ```
602 pub fn config(&self) -> &Config {
603 &self.config
604 }
605
606 /// Returns a handle which can be used to trigger a shutdown and detect a
607 /// triggered shutdown.
608 ///
609 /// A completed graceful shutdown resolves the future returned by
610 /// [`Rocket::launch()`]. If [`Shutdown::notify()`] is called _before_ an
611 /// instance is launched, it will be immediately shutdown after liftoff. See
612 /// [`Shutdown`] and [`config::Shutdown`](crate::config::Shutdown) for
613 /// details on graceful shutdown.
614 ///
615 /// # Example
616 ///
617 /// ```rust,no_run
618 /// # use std::time::Duration;
619 /// use rocket::tokio::{self, time};
620 ///
621 /// #[rocket::main]
622 /// async fn main() -> Result<(), rocket::Error> {
623 /// let rocket = rocket::build().ignite().await?;
624 ///
625 /// let shutdown = rocket.shutdown();
626 /// tokio::spawn(async move {
627 /// time::sleep(time::Duration::from_secs(5)).await;
628 /// shutdown.notify();
629 /// });
630 ///
631 /// // The `launch()` future resolves after ~5 seconds.
632 /// let result = rocket.launch().await;
633 /// assert!(result.is_ok());
634 ///
635 /// Ok(())
636 /// }
637 /// ```
638 pub fn shutdown(&self) -> Shutdown {
639 self.shutdown.clone()
640 }
641
642 fn into_orbit(self) -> Rocket<Orbit> {
643 Rocket(Orbiting {
644 router: self.0.router,
645 fairings: self.0.fairings,
646 figment: self.0.figment,
647 config: self.0.config,
648 state: self.0.state,
649 shutdown: self.0.shutdown,
650 })
651 }
652
653 async fn _local_launch(self) -> Rocket<Orbit> {
654 let rocket = self.into_orbit();
655 rocket.fairings.handle_liftoff(&rocket).await;
656 launch_info!("{}{}", "🚀 ".emoji(), "Rocket has launched locally".primary().bold());
657 rocket
658 }
659
660 async fn _launch(self) -> Result<Rocket<Ignite>, Error> {
661 self.into_orbit()
662 .default_tcp_http_server(|rkt| Box::pin(async move {
663 rkt.fairings.handle_liftoff(&rkt).await;
664
665 let proto = rkt.config.tls_enabled().then(|| "https").unwrap_or("http");
666 let socket_addr = SocketAddr::new(rkt.config.address, rkt.config.port);
667 let addr = format!("{}://{}", proto, socket_addr);
668 launch_info!("{}{} {}",
669 "🚀 ".emoji(),
670 "Rocket has launched from".bold().primary().linger(),
671 addr.underline());
672 }))
673 .await
674 .map(|rocket| rocket.into_ignite())
675 }
676}
677
678impl Rocket<Orbit> {
679 pub(crate) fn into_ignite(self) -> Rocket<Ignite> {
680 Rocket(Igniting {
681 router: self.0.router,
682 fairings: self.0.fairings,
683 figment: self.0.figment,
684 config: self.0.config,
685 state: self.0.state,
686 shutdown: self.0.shutdown,
687 })
688 }
689
690 /// Returns the finalized, active configuration. This is guaranteed to
691 /// remain stable after [`Rocket::ignite()`], through ignition and into
692 /// orbit.
693 ///
694 /// # Example
695 ///
696 /// ```rust,no_run
697 /// # #[macro_use] extern crate rocket;
698 /// use rocket::fairing::AdHoc;
699 ///
700 /// #[launch]
701 /// fn rocket() -> _ {
702 /// rocket::build()
703 /// .attach(AdHoc::on_liftoff("Config", |rocket| Box::pin(async move {
704 /// println!("Rocket launch config: {:?}", rocket.config());
705 /// })))
706 /// }
707 /// ```
708 pub fn config(&self) -> &Config {
709 &self.config
710 }
711
712 /// Returns a handle which can be used to trigger a shutdown and detect a
713 /// triggered shutdown.
714 ///
715 /// A completed graceful shutdown resolves the future returned by
716 /// [`Rocket::launch()`]. See [`Shutdown`] and
717 /// [`config::Shutdown`](crate::config::Shutdown) for details on graceful
718 /// shutdown.
719 ///
720 /// # Example
721 ///
722 /// ```rust,no_run
723 /// # #[macro_use] extern crate rocket;
724 /// use rocket::tokio::{self, time};
725 /// use rocket::fairing::AdHoc;
726 ///
727 /// #[launch]
728 /// fn rocket() -> _ {
729 /// rocket::build()
730 /// .attach(AdHoc::on_liftoff("Shutdown", |rocket| Box::pin(async move {
731 /// let shutdown = rocket.shutdown();
732 /// tokio::spawn(async move {
733 /// time::sleep(time::Duration::from_secs(5)).await;
734 /// shutdown.notify();
735 /// });
736 /// })))
737 /// }
738 /// ```
739 pub fn shutdown(&self) -> Shutdown {
740 self.shutdown.clone()
741 }
742}
743
744impl<P: Phase> Rocket<P> {
745 /// Returns an iterator over all of the routes mounted on this instance of
746 /// Rocket. The order is unspecified.
747 ///
748 /// # Example
749 ///
750 /// ```rust
751 /// # use rocket::*;
752 /// use rocket::Rocket;
753 /// use rocket::fairing::AdHoc;
754 ///
755 /// #[get("/hello")]
756 /// fn hello() -> &'static str {
757 /// "Hello, world!"
758 /// }
759 ///
760 /// let rocket = rocket::build()
761 /// .mount("/", routes![hello])
762 /// .mount("/hi", routes![hello]);
763 ///
764 /// assert_eq!(rocket.routes().count(), 2);
765 /// assert!(rocket.routes().any(|r| r.uri == "/hello"));
766 /// assert!(rocket.routes().any(|r| r.uri == "/hi/hello"));
767 /// ```
768 pub fn routes(&self) -> impl Iterator<Item = &Route> {
769 match self.0.as_state_ref() {
770 StateRef::Build(p) => Either::Left(p.routes.iter()),
771 StateRef::Ignite(p) => Either::Right(p.router.routes()),
772 StateRef::Orbit(p) => Either::Right(p.router.routes()),
773 }
774 }
775
776 /// Returns an iterator over all of the catchers registered on this instance
777 /// of Rocket. The order is unspecified.
778 ///
779 /// # Example
780 ///
781 /// ```rust
782 /// # use rocket::*;
783 /// use rocket::Rocket;
784 /// use rocket::fairing::AdHoc;
785 ///
786 /// #[catch(404)] fn not_found() -> &'static str { "Nothing here, sorry!" }
787 /// #[catch(500)] fn just_500() -> &'static str { "Whoops!?" }
788 /// #[catch(default)] fn some_default() -> &'static str { "Everything else." }
789 ///
790 /// let rocket = rocket::build()
791 /// .register("/foo", catchers![not_found])
792 /// .register("/", catchers![just_500, some_default]);
793 ///
794 /// assert_eq!(rocket.catchers().count(), 3);
795 /// assert!(rocket.catchers().any(|c| c.code == Some(404) && c.base == "/foo"));
796 /// assert!(rocket.catchers().any(|c| c.code == Some(500) && c.base == "/"));
797 /// assert!(rocket.catchers().any(|c| c.code == None && c.base == "/"));
798 /// ```
799 pub fn catchers(&self) -> impl Iterator<Item = &Catcher> {
800 match self.0.as_state_ref() {
801 StateRef::Build(p) => Either::Left(p.catchers.iter()),
802 StateRef::Ignite(p) => Either::Right(p.router.catchers()),
803 StateRef::Orbit(p) => Either::Right(p.router.catchers()),
804 }
805 }
806
807 /// Returns `Some` of the managed state value for the type `T` if it is
808 /// being managed by `self`. Otherwise, returns `None`.
809 ///
810 /// # Example
811 ///
812 /// ```rust
813 /// #[derive(PartialEq, Debug)]
814 /// struct MyState(&'static str);
815 ///
816 /// let rocket = rocket::build().manage(MyState("hello!"));
817 /// assert_eq!(rocket.state::<MyState>().unwrap(), &MyState("hello!"));
818 /// ```
819 pub fn state<T: Send + Sync + 'static>(&self) -> Option<&T> {
820 match self.0.as_state_ref() {
821 StateRef::Build(p) => p.state.try_get(),
822 StateRef::Ignite(p) => p.state.try_get(),
823 StateRef::Orbit(p) => p.state.try_get(),
824 }
825 }
826
827 /// Returns the figment derived from the configuration provider set for
828 /// `self`. To extract a typed config, prefer to use
829 /// [`AdHoc::config()`](crate::fairing::AdHoc::config()).
830 ///
831 /// # Example
832 ///
833 /// ```rust
834 /// let rocket = rocket::build();
835 /// let figment = rocket.figment();
836 /// ```
837 pub fn figment(&self) -> &Figment {
838 match self.0.as_state_ref() {
839 StateRef::Build(p) => &p.figment,
840 StateRef::Ignite(p) => &p.figment,
841 StateRef::Orbit(p) => &p.figment,
842 }
843 }
844
845 pub(crate) async fn local_launch(self) -> Result<Rocket<Orbit>, Error> {
846 let rocket = match self.0.into_state() {
847 State::Build(s) => Rocket::from(s).ignite().await?._local_launch().await,
848 State::Ignite(s) => Rocket::from(s)._local_launch().await,
849 State::Orbit(s) => Rocket::from(s)
850 };
851
852 Ok(rocket)
853 }
854
855 /// Returns a `Future` that transitions this instance of `Rocket` from any
856 /// phase into the _orbit_ phase. When `await`ed, the future drives the
857 /// server forward, listening for and dispatching requests to mounted routes
858 /// and catchers.
859 ///
860 /// In addition to all of the processes that occur during
861 /// [ignition](Rocket::ignite()), a successful launch results in _liftoff_
862 /// fairings being executed _after_ binding to any respective network
863 /// interfaces but before serving the first request. Liftoff fairings are
864 /// run concurrently; resolution of all fairings is `await`ed before
865 /// resuming request serving.
866 ///
867 /// The `Future` resolves as an `Err` if any of the following occur:
868 ///
869 /// * there is an error igniting; see [`Rocket::ignite()`].
870 /// * there is an I/O error starting the server.
871 /// * an unrecoverable, system-level error occurs while running.
872 ///
873 /// The `Future` resolves as an `Ok` if any of the following occur:
874 ///
875 /// * graceful shutdown via [`Shutdown::notify()`] completes.
876 ///
877 /// The returned value on `Ok(())` is previously running instance.
878 ///
879 /// The `Future` does not resolve otherwise.
880 ///
881 /// # Error
882 ///
883 /// If there is a problem starting the application or the application fails
884 /// unexpectedly while running, an [`Error`] is returned. Note that a value
885 /// of type `Error` panics if dropped without first being inspected. See the
886 /// [`Error`] documentation for more information.
887 ///
888 /// # Example
889 ///
890 /// ```rust,no_run
891 /// #[rocket::main]
892 /// async fn main() {
893 /// let result = rocket::build().launch().await;
894 ///
895 /// // this is reachable only after `Shutdown::notify()` or `Ctrl+C`.
896 /// println!("Rocket: deorbit.");
897 /// }
898 /// ```
899 pub async fn launch(self) -> Result<Rocket<Ignite>, Error> {
900 match self.0.into_state() {
901 State::Build(s) => Rocket::from(s).ignite().await?._launch().await,
902 State::Ignite(s) => Rocket::from(s)._launch().await,
903 State::Orbit(s) => Ok(Rocket::from(s).into_ignite())
904 }
905 }
906}
907
908#[doc(hidden)]
909impl<P: Phase> Deref for Rocket<P> {
910 type Target = P::State;
911
912 fn deref(&self) -> &Self::Target {
913 &self.0
914 }
915}
916
917#[doc(hidden)]
918impl<P: Phase> DerefMut for Rocket<P> {
919 fn deref_mut(&mut self) -> &mut Self::Target {
920 &mut self.0
921 }
922}
923
924impl<P: Phase> fmt::Debug for Rocket<P> {
925 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
926 self.0.fmt(f)
927 }
928}