Page MenuHomeDevCentral

D1863.id4706.diff
No OneTemporary

D1863.id4706.diff

diff --git a/Cargo.toml b/Cargo.toml
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,9 +19,15 @@
repository = "https://devcentral.nasqueron.org/source/limiting-factor/"
[dependencies]
-diesel = { version = "^1.0.0", features = ["postgres", "r2d2", "chrono"] }
+diesel = { version = "^1.0.0", features = ["postgres", "r2d2", "chrono"], optional = true }
dotenv = "0.9.0"
log = "^0.4.4"
-r2d2 = "^0.8.2"
+r2d2 = { version = "^0.8.2", optional = true }
rocket = "^0.3.16"
rocket_contrib = { version = "^0.3.16", features = [ "json" ] }
+
+[features]
+default = ["pgsql"]
+minimal = []
+
+pgsql = ["diesel", "r2d2"]
diff --git a/src/api/replies.rs b/src/api/replies.rs
--- a/src/api/replies.rs
+++ b/src/api/replies.rs
@@ -2,15 +2,15 @@
//!
//! This module provides useful traits and methods to craft API replies from an existing type.
-use std::error::Error;
-
-use diesel::result::DatabaseErrorInformation;
-use diesel::result::DatabaseErrorKind;
+#[cfg(feature = "pgsql")]
+use diesel::result::{DatabaseErrorInformation, DatabaseErrorKind, QueryResult};
+#[cfg(feature = "pgsql")]
use diesel::result::Error as ResultError;
-use diesel::result::QueryResult;
+
use rocket::http::Status;
use rocket::response::Failure;
use rocket_contrib::Json;
+use std::error::Error;
/* -------------------------------------------------------------
Custom types
@@ -30,6 +30,7 @@
fn into_json_response(self) -> ApiJsonResponse<T>;
}
+#[cfg(feature = "pgsql")]
impl<T> ApiResponse<T> for QueryResult<T> {
/// Prepares an API response from a query result.
///
@@ -92,6 +93,7 @@
fn into_failure_response(self) -> Failure;
}
+#[cfg(feature = "pgsql")]
impl FailureResponse for ResultError {
/// Consumes the error and creates a Failure 500 Internal server error response.
fn into_failure_response(self) -> Failure {
@@ -109,6 +111,7 @@
Failure::from(Status::InternalServerError)
}
+#[cfg(feature = "pgsql")]
fn build_database_error_response(error_kind: DatabaseErrorKind, info: Box<dyn DatabaseErrorInformation>) -> Failure {
match error_kind {
// Case IIIa - The query tries to do an INSERT violating an unique constraint
diff --git a/src/config.rs b/src/config.rs
--- a/src/config.rs
+++ b/src/config.rs
@@ -21,6 +21,7 @@
fn get_database_url(&self) -> &str;
fn get_entry_point(&self) -> &str;
fn get_database_pool_size(&self) -> u32;
+ fn with_database(&self) -> bool;
}
/* -------------------------------------------------------------
@@ -40,6 +41,7 @@
database_url: String,
entry_point: String,
database_pool_size: u32,
+ with_database: bool,
}
impl Config for DefaultConfig {
@@ -54,6 +56,8 @@
fn get_database_pool_size(&self) -> u32 {
self.database_pool_size
}
+
+ fn with_database(&self) -> bool { self.with_database }
}
impl DefaultConfig {
@@ -64,11 +68,17 @@
warn!(target: "config", "Can't parse .env: {}", error.description());
};
+ let with_database = env::var("LF_DISABLE_DATABASE").is_err();
+
let database_url = match env::var("DATABASE_URL") {
Ok(url) => url,
Err(e) => {
- error!(target: "config", "You need to specify a DATABASE_URL variable in the environment (or .env file).");
- return Err(Box::new(e));
+ if with_database {
+ error!(target: "config", "You need to specify a DATABASE_URL variable in the environment (or .env file).");
+ return Err(Box::new(e));
+ }
+
+ String::new()
}
};
@@ -92,7 +102,54 @@
database_url,
entry_point,
database_pool_size,
+ with_database,
})
}
}
+/* -------------------------------------------------------------
+ MinimalConfig
+
+ :: Config
+ :: sui generis implementation
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/// This is a minimal implementation of the `Config` trait, which extracts the following variables
+/// from an .env file or environment:
+///
+/// - `API_ENTRY_POINT` (facultative, by default `/`): the mouting point of the API methods
+///
+/// It sets the server not to use a database.
+pub struct MinimalConfig {
+ entry_point: String,
+}
+
+impl Config for MinimalConfig {
+ fn get_database_url(&self) -> &str {
+ ""
+ }
+
+ fn get_entry_point(&self) -> &str {
+ &self.entry_point
+ }
+
+ fn get_database_pool_size(&self) -> u32 {
+ 0
+ }
+
+ fn with_database(&self) -> bool { false }
+}
+
+impl MinimalConfig {
+ pub fn parse_environment() -> ErrorResult<Self> {
+ if let Err(error) = dotenv() {
+ warn!(target: "config", "Can't parse .env: {}", error.description());
+ };
+
+ let entry_point = env::var("API_ENTRY_POINT").unwrap_or(String::from("/"));
+
+ Ok(MinimalConfig {
+ entry_point,
+ })
+ }
+}
diff --git a/src/kernel.rs b/src/kernel.rs
--- a/src/kernel.rs
+++ b/src/kernel.rs
@@ -4,6 +4,7 @@
use config::Config;
use config::DefaultConfig;
+use config::MinimalConfig;
use database::initialize_database_pool;
use database::test_database_connection;
use ErrorResult;
@@ -26,10 +27,15 @@
let config = self.get_config();
let routes = self.get_routes();
- ignite()
- .manage(
+ let mut server = ignite();
+
+ if config.with_database() {
+ server = server.manage(
initialize_database_pool(config.get_database_url(), config.get_database_pool_size())?
- )
+ );
+ }
+
+ server
.mount(config.get_entry_point(), routes.to_vec())
.launch();
@@ -42,8 +48,10 @@
// Initial connection to test if the database configuration works
{
let config = self.get_config();
- test_database_connection(config.get_database_url())?;
- info!(target: "runner", "Connection to database established.");
+ if config.with_database() {
+ test_database_connection(config.get_database_url())?;
+ info!(target: "runner", "Connection to database established.");
+ }
}
self.launch_server()?;
@@ -53,12 +61,73 @@
}
/* -------------------------------------------------------------
- Default application
+ Base application as concrete implementation
:: Application
:: sui generis implementation
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/// The base application is a generic Application structure to implement the Application trait
+/// with a CLI program behavior to prepare a configuration, for example
+/// from environment (like DefaultApplication and MinimalApplication do),
+/// check if the configuration works fine and if so launch a Rocket server.
+pub struct BaseApplication<T>
+ where T: Config
+{
+ config: T,
+ routes: Box<Vec<Route>>,
+}
+
+impl<T> Application for BaseApplication<T>
+ where T: Config
+{
+ fn get_config(&self) -> &dyn Config {
+ &self.config
+ }
+
+ fn get_routes(&self) -> &[Route] {
+ self.routes.as_slice()
+ }
+}
+
+impl<T> BaseApplication<T>
+ where T: Config
+{
+ pub fn new (config: T, routes: Vec<Route>) -> Self {
+ BaseApplication {
+ config,
+ routes: Box::new(routes),
+ }
+ }
+
+ /// 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.run() {
+ error!(target: "runner", "{}", error.description());
+ process::exit(1);
+ }
+
+ process::exit(0);
+ }
+}
+
+/* -------------------------------------------------------------
+ Default application
+
+ :: Application
+ :: sui generis implementation, wrapper for BaseApplication
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
/// 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,
/// launch a Rocket server.
@@ -84,52 +153,50 @@
/// ```
///
/// The default configuration will be used and the server started.
-pub struct DefaultApplication {
- config: DefaultConfig,
- 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()
- }
-}
+pub struct DefaultApplication {}
impl DefaultApplication {
- pub fn new (config: DefaultConfig, routes: Vec<Route>) -> Self {
- DefaultApplication {
+ pub fn new (config: DefaultConfig, routes: Vec<Route>) -> BaseApplication<DefaultConfig> {
+ BaseApplication {
config,
routes: Box::new(routes),
}
}
- /// Starts the application, prepares default configuration
- ///
- /// # 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);
+ let mut app = BaseApplication::new(config, routes);
+ app.start();
+ }
+}
- if let Err(error) = app.run() {
- error!(target: "runner", "{}", error.description());
- process::exit(1);
+/* -------------------------------------------------------------
+ Minimal application
+
+ :: Application
+ :: sui generis implementation, wrapper for BaseApplication
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+pub struct MinimalApplication {}
+
+impl MinimalApplication {
+ pub fn new (config: MinimalConfig, routes: Vec<Route>) -> BaseApplication<MinimalConfig> {
+ BaseApplication {
+ config,
+ routes: Box::new(routes),
}
+ }
- process::exit(0);
+ pub fn start_application (routes: Vec<Route>) {
+ let config = MinimalConfig::parse_environment().unwrap_or_else(|_error| {
+ process::exit(2);
+ });
+
+ let mut app = BaseApplication::new(config, routes);
+ app.start();
}
}
+
diff --git a/src/lib.rs b/src/lib.rs
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -13,14 +13,14 @@
//! A simple server serving a 200 ALIVE response on /status :
//!
//! ```no_run
-//! use limiting_factor::kernel::DefaultApplication;
+//! use limiting_factor::kernel::BaseApplication;
//!
//! pub fn run () {
//! let routes = routes![
//! status,
//! ];
//!
-//! DefaultApplication::start_application(routes);
+//! BaseApplication::start_application(routes);
//! }
//!
//! #[get("/status")]
@@ -29,9 +29,12 @@
//! }
//! ```
+#[cfg(feature = "pgsql")]
extern crate diesel;
extern crate dotenv;
-#[macro_use] extern crate log;
+#[macro_use]
+extern crate log;
+#[cfg(feature = "pgsql")]
extern crate r2d2;
extern crate rocket;
extern crate rocket_contrib;
@@ -42,9 +45,15 @@
pub mod api;
pub mod config;
-pub mod database;
pub mod kernel;
+/* -------------------------------------------------------------
+ Optional public features modules offered by this crate
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#[cfg(feature = "pgsql")]
+pub mod database;
+
/* -------------------------------------------------------------
Custom types
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

File Metadata

Mime Type
text/plain
Expires
Mon, Jul 7, 03:30 (34 m, 2 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2791270
Default Alt Text
D1863.id4706.diff (12 KB)

Event Timeline