1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
//! The running application part.
//!
//! The convenient way to manage the application runtime is through
//! [`Builder::run`][crate::SpiritBuilder::run]. If more flexibility is needed, the
//! [`Builder::build`][crate::SpiritBuilder::build] can be used instead. That method returns the
//! [`App`][crate::app::App] object, representing the application runner. The application can then
//! be run at any later time, as convenient.
use std::process;
use std::sync::Arc;
use std::thread;
use log::debug;
use serde::de::DeserializeOwned;
use structopt::StructOpt;
use crate::bodies::{InnerBody, WrapBody};
use crate::error;
use crate::spirit::Spirit;
use crate::terminate_guard::TerminateGuard;
use crate::utils::FlushGuard;
use crate::AnyError;
/// The running application part.
///
/// This is returned by [`Builder::build`][crate::SpiritBuilder::build] and represents the rest of
/// the application runtime except the actual application body. It can be used to run at any later
/// time, after the spirit has been created.
///
/// This carries all the [around-bodies][crate::Extensible::run_around] and
/// [before-bodies][crate::Extensible::run_before]. If you run the application body directly, not
/// through this, some of the pipelines or extensions might not work as expected.
///
/// The [`Builder::run`][crate::SpiritBuilder::run] is just a convenient wrapper around this. Note
/// that that one handles and logs errors from the application startup as well as from its runtime.
/// Here it is up to the caller to handle the startup errors.
///
/// # Examples
///
/// ```rust
/// use spirit::{AnyError, Empty, Spirit};
/// use spirit::prelude::*;
///
/// # fn main() -> Result<(), AnyError> {
/// Spirit::<Empty, Empty>::new()
/// .build(true)?
/// .run_term(|| {
/// println!("Hello world");
/// Ok(())
/// });
/// # Ok(())
/// # }
/// ```
pub struct App<O, C> {
spirit: Arc<Spirit<O, C>>,
inner: InnerBody,
wrapper: WrapBody,
}
impl<O, C> App<O, C>
where
O: StructOpt + Send + Sync + 'static,
C: DeserializeOwned + Send + Sync + 'static,
{
pub(crate) fn new(spirit: Arc<Spirit<O, C>>, inner: InnerBody, wrapper: WrapBody) -> Self {
Self {
spirit,
inner,
wrapper,
}
}
/// Access to the built spirit object.
///
/// The object can be used to manipulate the runtime of the application, access the current
/// configuration and register further callbacks (and extensions and pipelines).
///
/// Depending on your needs, you may pass it to the closure started with [`run`][App::run] or
/// even placed into some kind of global storage.
pub fn spirit(&self) -> &Arc<Spirit<O, C>> {
&self.spirit
}
/// Run the application with provided body.
///
/// This will run the provided body. However, it'll wrap it in all the
/// [around-bodies][crate::Extensible::run_around] and precede it with all the
/// [before-bodies][crate::Extensible::run_before]. If any of these fail, or if the `body`
/// fails, the error is propagated (and further bodies are not started).
///
/// Furthermore, depending on the [`autojoin_bg_thread`][crate::Extensible::autojoin_bg_thread]
/// configuration, termination and joining of the background thread may be performed. If the
/// body errors, termination is done unconditionally (which may be needed in some corner cases
/// to not deadlock on error).
///
/// In other words, unless you have very special needs, this is how you actually invoke the
/// application itself.
///
/// Any errors are simply returned and it is up to the caller to handle them somehow.
pub fn run<B>(self, body: B) -> Result<(), AnyError>
where
B: FnOnce() -> Result<(), AnyError> + Send + 'static,
{
debug!("Running bodies");
let _flush = FlushGuard;
struct ScopeGuard<F: FnOnce()>(Option<F>);
impl<F: FnOnce()> Drop for ScopeGuard<F> {
fn drop(&mut self) {
self.0.take().expect("Drop called twice")();
}
}
let spirit = &self.spirit;
let _thread = ScopeGuard(Some(|| {
if thread::panicking() {
spirit.terminate();
}
spirit.maybe_autojoin_bg_thread();
}));
let inner = self.inner;
let inner = move || inner().and_then(|()| body());
let result = (self.wrapper)(Box::new(inner));
if result.is_err() {
self.spirit.terminate();
}
result
}
/// Similar to [`run`][App::run], but with error handling.
///
/// This calls the [`run`][App::run]. However, if there are any errors, they are logged and the
/// application terminates with non-zero exit code.
pub fn run_term<B>(self, body: B)
where
B: FnOnce() -> Result<(), AnyError> + Send + 'static,
{
let flush = FlushGuard;
if error::log_errors("top-level", || self.run(body)).is_err() {
drop(flush);
process::exit(1);
}
}
/// Run the application in a background thread for testing purposes.
///
/// This'll run the application and return an RAII guard. That guard can be used to access the
/// [Spirit] and manipulate it. It also terminates the application and background thread when
/// dropped.
///
/// This is for testing purposes (it panics if there are errors). See the [testing guide].
///
/// testing guide: crate::guide::testing
pub fn run_test<B>(self, body: B) -> TerminateGuard<O, C>
where
B: FnOnce() -> Result<(), AnyError> + Send + 'static,
{
let spirit = Arc::clone(self.spirit());
let bg_thread = thread::spawn(move || self.run(body));
TerminateGuard::new(spirit, bg_thread)
}
}