refactor!: remove lazy_static dep, use rustfmt on data module
Diff
Cargo.toml | 2 +-
src/data.rs | 121 ++++++++++++++++++++++++++++++-------------------------------
src/main.rs | 71 +++++++++++++++++-------------------
3 files changed, 94 insertions(+), 100 deletions(-)
@@ -7,9 +7,7 @@ edition = "2021"
[dependencies]
async-std = { version = "1.12.0", features = ["attributes"] }
envy = "0.4.2"
jealousy = { version = "0.1.5", features = ["derive"] }
lazy_static = "1.4.0"
serde = { version = "1.0.188", features = ["derive"] }
serde_yaml = "0.9.25"
tide = "0.16.0"
@@ -1,82 +1,81 @@
use std::path::Path;
use serde::Deserialize;
use std::str::FromStr;
use tide::log;
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub struct LicenseDatabase {
pub licenses: Vec<License>,
}
pub trait Queryable {
fn get_licenses(self: &Self, chunk_size: usize) -> Option<String>;
fn get_detailed_licenses(self: &Self) -> Option<String>;
fn get_license(self: &Self, id: &str) -> Option<License>;
fn get_licenses(self: &Self, chunk_size: usize) -> Option<String>;
fn get_detailed_licenses(self: &Self) -> Option<String>;
fn get_license(self: &Self, id: &str) -> Option<License>;
}
impl Queryable for LicenseDatabase {
fn get_licenses(self: &Self, chunk_size: usize) -> Option<String> {
let result = self
.licenses
.iter()
.map(|license| license.id.clone())
.collect::<Vec<String>>()
.chunks(chunk_size)
.map(|chunk| chunk.join(", "))
.collect::<Vec<String>>()
.join("\n");
if result.is_empty() {
log::warn!("License database not found!");
None
}
else {
Some(result)
}
}
fn get_detailed_licenses(self: &Self) -> Option<String> {
const PADDING: usize = 20;
fn get_licenses(self: &Self, chunk_size: usize) -> Option<String> {
let result = self
.licenses
.iter()
.map(|license| license.id.clone())
.collect::<Vec<String>>()
.chunks(chunk_size)
.map(|chunk| chunk.join(", "))
.collect::<Vec<String>>()
.join("\n");
let result: String = self
.licenses
.iter()
.map(|license| {
format!(
"{:padding$}{}",
license.id,
license.description,
padding = PADDING
)
})
.collect::<Vec<String>>()
.join("\n");
if result.is_empty() {
log::warn!("License database not found!");
None
} else {
Some(result)
}
}
if result.is_empty() {
log::warn!("License database not found!");
None
}
else {
Some(result)
}
}
fn get_detailed_licenses(self: &Self) -> Option<String> {
const PADDING: usize = 20;
fn get_license(self: &Self, id: &str) -> Option<License> {
let query: Option<License> = self
.licenses
.iter()
.map(|license| license.clone())
.find(|license| license.id.eq(id));
query
}
let result: String = self
.licenses
.iter()
.map(|license| {
format!(
"{:padding$}{}",
license.id,
license.description,
padding = PADDING
)
})
.collect::<Vec<String>>()
.join("\n");
if result.is_empty() {
log::warn!("License database not found!");
None
} else {
Some(result)
}
}
fn get_license(self: &Self, id: &str) -> Option<License> {
let query: Option<License> = self
.licenses
.iter()
.map(|license| license.clone())
.find(|license| license.id.eq(id));
query
}
}
impl LicenseDatabase {
pub fn load_file(file: &Path) -> LicenseDatabase {
let file_contents = std::fs::read_to_string(file).unwrap();
pub fn load(file: String) -> LicenseDatabase {
let db_path: std::path::PathBuf = std::path::PathBuf::from_str(file.as_str()).unwrap();
let file_contents = std::fs::read_to_string(db_path.as_path()).unwrap();
let database: LicenseDatabase = serde_yaml::from_str(&file_contents).unwrap();
database
}
}
@@ -5,29 +5,26 @@ use async_std::{
use data::LicenseDatabase;
use jealousy::FromEnv;
use serde::Deserialize;
use std::{net::Ipv4Addr, str::FromStr};
use std::net::Ipv4Addr;
use tide::{http::mime, log, Response, Result, Server, StatusCode};
use crate::data::{License, Queryable};
use crate::data::Queryable;
mod data;
#[macro_use]
extern crate lazy_static;
#[derive(Debug, Deserialize, FromEnv)]
#[derive(Debug, Deserialize, FromEnv, Clone)]
#[from_env(prefix = "LICENSE_API")]
struct Config {
#[serde(default = "Config::default_base_url")]
struct ServerConfig {
#[serde(default = "ServerConfig::default_base_url")]
base_url: String,
database: String,
#[serde(default = "Config::default_server_ip")]
#[serde(default = "ServerConfig::default_server_ip")]
server_ip: Ipv4Addr, #[serde(default = "Config::default_server_port")]
#[serde(default = "ServerConfig::default_server_port")]
server_port: u16,
}
impl Config {
impl ServerConfig {
fn default_base_url() -> String {
String::from("/")
}
@@ -41,16 +38,10 @@ impl Config {
}
}
lazy_static! {
#[derive (Debug)]
static ref DATABASE: LicenseDatabase = {
let config = Config::from_env().unwrap();
let db_path: std::path::PathBuf = std::path::PathBuf::from_str(&config.database).unwrap();
let database: LicenseDatabase = LicenseDatabase::load_file(db_path.as_path());
database
};
#[derive(Debug, Clone)]
struct RunningConfig {
config: ServerConfig,
database: LicenseDatabase,
}
const ERROR_LICENSE_NOT_FOUND: &str =
@@ -60,11 +51,17 @@ const ERROR_LICENSE_NOT_FOUND: &str =
async fn main() -> Result<()> {
log::start();
match Config::from_env() {
match ServerConfig::from_env() {
Ok(config) => {
let mut app = tide::new();
let run_config = RunningConfig {
config: config.clone(),
database: LicenseDatabase::load(config.database.clone()),
};
create_routes(&mut app, &config);
let mut app = tide::with_state(run_config);
create_routes(&mut app);
app.listen(format!("{}:{}", config.server_ip, config.server_port))
.await?;
@@ -75,8 +72,10 @@ async fn main() -> Result<()> {
Ok(())
}
fn create_routes(server: &mut Server<()>, config: &Config) {
let mut base_route = server.at(&config.base_url);
fn create_routes(server: &mut Server<RunningConfig>) {
let url = server.clone().state().config.base_url.clone();
let mut base_route = server.at(&url);
base_route.get(get_welcome_message);
base_route.at(":license").get(get_requested_license);
@@ -99,7 +98,7 @@ fn build_response(status: StatusCode, data: String) -> Response {
response
}
async fn get_welcome_message(req: tide::Request<()>) -> tide::Result<Response> {
async fn get_welcome_message(req: tide::Request<RunningConfig>) -> tide::Result<Response> {
log::info!("{:?}", req);
Ok(build_response(
@@ -108,11 +107,11 @@ async fn get_welcome_message(req: tide::Request<()>) -> tide::Result<Response> {
))
}
async fn get_license_list(req: tide::Request<()>) -> tide::Result<Response> {
async fn get_license_list(req: tide::Request<RunningConfig>) -> tide::Result<Response> {
log::info!("{:?}", req);
match DATABASE.get_licenses(5) {
match req.state().database.get_licenses(5) {
Some(licenses) => Ok(build_response(StatusCode::Ok, format!("{}", licenses))),
None => Ok(build_response(
StatusCode::NotFound,
@@ -121,10 +120,10 @@ async fn get_license_list(req: tide::Request<()>) -> tide::Result<Response> {
}
}
async fn get_detailed_license_list(req: tide::Request<()>) -> tide::Result<Response> {
async fn get_detailed_license_list(req: tide::Request<RunningConfig>) -> tide::Result<Response> {
log::info!("{:?}", req);
match DATABASE.get_detailed_licenses() {
match req.state().database.get_detailed_licenses() {
Some(licenses) => Ok(build_response(StatusCode::Ok, format!("{}", licenses))),
None => Ok(build_response(
StatusCode::NotFound,
@@ -133,19 +132,17 @@ async fn get_detailed_license_list(req: tide::Request<()>) -> tide::Result<Respo
}
}
async fn get_requested_license(req: tide::Request<()>) -> tide::Result<Response> {
async fn get_requested_license(req: tide::Request<RunningConfig>) -> tide::Result<Response> {
log::info!("{:?}", req);
let config = Config::from_env().unwrap();
let request = req.url().path().strip_prefix("/").unwrap_or("");
let response = match DATABASE.get_license(request) {
let response = match req.state().database.get_license(request) {
Some(license) => {
let source_dir = PathBuf::from(&config.database);
let source_dir = PathBuf::from(req.state().config.database.clone());
let source_dir = source_dir.parent().unwrap_or(Path::new(""));
let mut license_file_path = PathBuf::from(source_dir);