Changeset View
Changeset View
Standalone View
Standalone View
src/kernel.rs
//! # Service execution utilities. | //! # Service execution utilities. | ||||
//! | //! | ||||
//! Provides methods to start the server and handle the application | //! Provides methods to start the server and handle the application | ||||
use config::Config; | use config::{Config, MinimalConfig}; | ||||
#[cfg(feature = "pgsql")] | |||||
use config::DefaultConfig; | use config::DefaultConfig; | ||||
use database::initialize_database_pool; | #[cfg(feature = "pgsql")] | ||||
use database::test_database_connection; | use database::{initialize_database_pool, test_database_connection}; | ||||
use ErrorResult; | use ErrorResult; | ||||
use rocket::Route; | use rocket::Route; | ||||
use rocket::ignite; | use rocket::ignite; | ||||
use std::process; | use std::process; | ||||
use std::marker::PhantomData; | |||||
use config::EnvironmentConfigurable; | |||||
/* ------------------------------------------------------------- | /* ------------------------------------------------------------- | ||||
Application | Service | ||||
Allow to define config and routes. Launch a server. | Allow to define config and routes. Launch a server. | ||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||||
pub trait Application { | pub trait Service { | ||||
fn get_config(&self) -> &dyn Config; | fn get_config(&self) -> &dyn Config; | ||||
fn get_routes(&self) -> &[Route]; | fn get_routes(&self) -> &[Route]; | ||||
fn launch_server(&mut self) -> ErrorResult<()>; | |||||
fn check_service_configuration(&self) -> ErrorResult<()>; | |||||
fn run (&mut self) -> ErrorResult<()> { | |||||
info!(target: "runner", "Server started."); | |||||
{ | |||||
self.check_service_configuration()? | |||||
} | |||||
self.launch_server()?; | |||||
Ok(()) | |||||
} | |||||
} | |||||
/* ------------------------------------------------------------- | |||||
Default service | |||||
Allow to define config and routes. Launch a server. | |||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |||||
/// The default service offers a pgsql database connection with Diesel and r2d2. | |||||
#[cfg(feature = "pgsql")] | |||||
pub struct DefaultService { | |||||
pub config: DefaultConfig, | |||||
pub routes: Box<Vec<Route>>, | |||||
} | |||||
#[cfg(feature = "pgsql")] | |||||
impl Service for DefaultService { | |||||
fn get_config(&self) -> &dyn Config { &self.config } | |||||
fn get_routes(&self) -> &[Route] { self.routes.as_slice() } | |||||
fn launch_server(&mut self) -> ErrorResult<()> { | fn launch_server(&mut self) -> ErrorResult<()> { | ||||
let config = self.get_config(); | let config = self.get_config(); | ||||
let routes = self.get_routes(); | let routes = self.get_routes(); | ||||
ignite() | let mut server = ignite(); | ||||
.manage( | |||||
if config.with_database() { | |||||
server = server.manage( | |||||
initialize_database_pool(config.get_database_url(), config.get_database_pool_size())? | initialize_database_pool(config.get_database_url(), config.get_database_pool_size())? | ||||
) | ); | ||||
} | |||||
server | |||||
.mount(config.get_entry_point(), routes.to_vec()) | .mount(config.get_entry_point(), routes.to_vec()) | ||||
.launch(); | .launch(); | ||||
Ok(()) | Ok(()) | ||||
} | } | ||||
fn run (&mut self) -> ErrorResult<()> { | fn check_service_configuration(&self) -> ErrorResult<()> { | ||||
info!(target: "runner", "Server started."); | |||||
// Initial connection to test if the database configuration works | |||||
{ | |||||
let config = self.get_config(); | let config = self.get_config(); | ||||
if config.with_database() { | |||||
test_database_connection(config.get_database_url())?; | test_database_connection(config.get_database_url())?; | ||||
info!(target: "runner", "Connection to database established."); | info!(target: "runner", "Connection to database established."); | ||||
} | } | ||||
self.launch_server()?; | Ok(()) | ||||
} | |||||
} | |||||
/* ------------------------------------------------------------- | |||||
Minimal service | |||||
Allow to define config and routes. Launch a server. | |||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |||||
/// The minimal service allows to spawn a server without any extra feature. | |||||
pub struct MinimalService { | |||||
pub config: MinimalConfig, | |||||
pub routes: Box<Vec<Route>>, | |||||
} | |||||
impl Service for MinimalService { | |||||
fn get_config(&self) -> &dyn Config { &self.config } | |||||
fn get_routes(&self) -> &[Route] { self.routes.as_slice() } | |||||
fn launch_server(&mut self) -> ErrorResult<()> { | |||||
let config = self.get_config(); | |||||
let routes = self.get_routes(); | |||||
ignite() | |||||
.mount(config.get_entry_point(), routes.to_vec()) | |||||
.launch(); | |||||
Ok(()) | Ok(()) | ||||
} | } | ||||
fn check_service_configuration(&self) -> ErrorResult<()> { Ok(()) } | |||||
} | } | ||||
/* ------------------------------------------------------------- | /* ------------------------------------------------------------- | ||||
Default application | Base application as concrete implementation | ||||
:: Application | :: Application | ||||
:: sui generis implementation | :: sui generis implementation | ||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||||
/// The application structure allows to encapsulate the service into a CLI application. | |||||
/// | |||||
/// The application takes care to run the service and quits with a correct exit code. | |||||
/// | |||||
/// It also takes care of initialisation logic like parse the environment to extract | |||||
/// the configuration. | |||||
pub struct Application<U> | |||||
where U: Config | |||||
{ | |||||
service: Box<dyn Service>, | |||||
config_type: PhantomData<U>, | |||||
} | |||||
impl<U> Application<U> | |||||
where U: Config + EnvironmentConfigurable | |||||
{ | |||||
pub fn new (config: U, routes: Vec<Route>) -> Self { | |||||
Application { | |||||
service: config.into_service(routes), | |||||
config_type: PhantomData, | |||||
} | |||||
} | |||||
/// Starts the application | |||||
/// | |||||
/// # Exit codes | |||||
/// | |||||
/// The software will exit with the following error codes: | |||||
/// | |||||
/// - 0: Graceful exit (currently not in use, as the application never stops) | |||||
/// - 1: Error during the application run (e.g. routes conflict or Rocket fairings issues) | |||||
/// - 2: Error parsing the configuration (e.g. no database URL has been defined) | |||||
pub fn start (&mut self) { | |||||
info!(target: "runner", "Server initialized."); | |||||
if let Err(error) = self.service.run() { | |||||
error!(target: "runner", "{}", error.description()); | |||||
process::exit(1); | |||||
} | |||||
process::exit(0); | |||||
} | |||||
pub fn start_application (routes: Vec<Route>) { | |||||
let config = <U>::parse_environment().unwrap_or_else(|_error| { | |||||
process::exit(2); | |||||
}); | |||||
let mut app = Application::new(config, routes); | |||||
app.start(); | |||||
} | |||||
} | |||||
/* ------------------------------------------------------------- | |||||
Default application | |||||
:: Application | |||||
:: sui generis implementation, wrapper for Application | |||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |||||
/// The default application implements CLI program behavior to prepare a configuration from the | /// The default application implements CLI program behavior to prepare a configuration from the | ||||
/// `DefaultConfig` implementation, test if it's possible to connect to the database, and if so, | /// `DefaultConfig` implementation, test if it's possible to connect to the database, and if so, | ||||
/// launch a Rocket server. | /// launch a Rocket server. | ||||
/// | /// | ||||
/// # Examples | /// # Examples | ||||
/// | /// | ||||
/// To run an application with some routes in a `requests` module: | /// To run an application with some routes in a `requests` module: | ||||
/// | /// | ||||
Show All 9 Lines | |||||
/// users::get_player, | /// users::get_player, | ||||
/// ]; | /// ]; | ||||
/// | /// | ||||
/// DefaultApplication::start_application(routes); | /// DefaultApplication::start_application(routes); | ||||
/// } | /// } | ||||
/// ``` | /// ``` | ||||
/// | /// | ||||
/// The default configuration will be used and the server started. | /// The default configuration will be used and the server started. | ||||
pub struct DefaultApplication { | #[cfg(feature = "pgsql")] | ||||
config: DefaultConfig, | pub struct DefaultApplication {} | ||||
routes: Box<Vec<Route>>, | |||||
} | |||||
impl Application for DefaultApplication { | |||||
fn get_config(&self) -> &dyn Config { | |||||
&self.config | |||||
} | |||||
fn get_routes(&self) -> &[Route] { | |||||
self.routes.as_slice() | |||||
} | |||||
} | |||||
#[cfg(feature = "pgsql")] | |||||
impl DefaultApplication { | impl DefaultApplication { | ||||
pub fn new (config: DefaultConfig, routes: Vec<Route>) -> Self { | pub fn start_application (routes: Vec<Route>) { | ||||
DefaultApplication { | Application::<DefaultConfig>::start_application(routes); | ||||
config, | |||||
routes: Box::new(routes), | |||||
} | } | ||||
} | } | ||||
/// Starts the application, prepares default configuration | /* ------------------------------------------------------------- | ||||
/// | Minimal application | ||||
/// # Exit codes | |||||
/// | |||||
/// The software will exit with the following error codes: | |||||
/// | |||||
/// - 0: Graceful exit (currently not in use, as the application never stops) | |||||
/// - 1: Error during the application run (e.g. routes conflict or Rocket fairings issues) | |||||
/// - 2: Error parsing the configuration (e.g. no database URL has been defined) | |||||
pub fn start_application (routes: Vec<Route>) { | |||||
info!(target: "runner", "Server initialized."); | |||||
let config = DefaultConfig::parse_environment().unwrap_or_else(|_error| { | |||||
process::exit(2); | |||||
}); | |||||
let mut app = Self::new(config, routes); | :: Application | ||||
:: sui generis implementation, wrapper for Application | |||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |||||
if let Err(error) = app.run() { | pub struct MinimalApplication {} | ||||
error!(target: "runner", "{}", error.description()); | |||||
process::exit(1); | |||||
} | |||||
process::exit(0); | impl MinimalApplication { | ||||
pub fn start_application (routes: Vec<Route>) { | |||||
Application::<MinimalConfig>::start_application(routes); | |||||
} | } | ||||
} | } |
Nasqueron DevCentral · If it had been much bigger the moon would have had a core of ice. · Powered by Phabricator