From 743ae22168b1fcdf2e1e54bcadbb1bb3fce3370d Mon Sep 17 00:00:00 2001 From: "Adam T. Carpenter" Date: Mon, 5 Oct 2020 22:05:58 -0400 Subject: started work on schema, models, and repos --- dichroism/src/bin/dichroismd.rs | 44 +++++++++++++++++++++++++++++++++++++++++ dichroism/src/config.rs | 32 +++++++++++++++++++++++++++++- dichroism/src/constants.rs | 3 +++ dichroism/src/error.rs | 1 + dichroism/src/handlers.rs | 31 +++++++++++++++++++++++++---- dichroism/src/image_api.rs | 11 ++++++----- dichroism/src/image_repo.rs | 32 ++++++++++++++++++++++++++++++ dichroism/src/lib.rs | 16 +++++++++++++++ dichroism/src/main.rs | 35 -------------------------------- dichroism/src/models.rs | 5 +++++ dichroism/src/product_api.rs | 0 dichroism/src/product_repo.rs | 18 +++++++++++++++++ dichroism/src/schema.rs | 6 ++++++ dichroism/src/types.rs | 5 +++++ 14 files changed, 194 insertions(+), 45 deletions(-) create mode 100644 dichroism/src/bin/dichroismd.rs create mode 100644 dichroism/src/constants.rs create mode 100644 dichroism/src/image_repo.rs create mode 100644 dichroism/src/lib.rs delete mode 100644 dichroism/src/main.rs create mode 100644 dichroism/src/models.rs create mode 100644 dichroism/src/product_api.rs create mode 100644 dichroism/src/product_repo.rs create mode 100644 dichroism/src/schema.rs create mode 100644 dichroism/src/types.rs (limited to 'dichroism/src') diff --git a/dichroism/src/bin/dichroismd.rs b/dichroism/src/bin/dichroismd.rs new file mode 100644 index 0000000..2dc059d --- /dev/null +++ b/dichroism/src/bin/dichroismd.rs @@ -0,0 +1,44 @@ +use actix_web::{App, HttpServer}; +use dichroism::config; +use dichroism::handlers; +use dichroism::result::Result; +use diesel::prelude::SqliteConnection; +use diesel::r2d2::ConnectionManager; +use diesel::r2d2::Pool; +use listenfd::ListenFd; + +#[actix_web::main] +async fn main() -> Result<()> { + // Gather config. + let config = config::Config::new_from_env().await?; + let bind_addr = config.bind_addr; + + // Initialize DB connection pool. + //let manager = ConnectionManager::::new(config.db_url); + let manager = ConnectionManager::::new(&config.db_url); + let pool = Pool::builder().build(manager)?; + + // Initialize application server. + let mut server = HttpServer::new(move || { + App::new() + .data(config.clone()) + .data(pool.clone()) + .service(handlers::hello) + .service(handlers::create_image) + .service(handlers::get_products) + }); + + let mut listenfd = ListenFd::from_env(); + server = if let Some(l) = listenfd + .take_tcp_listener(0) + .expect("Unable to grab TCP listener!") + { + // If using listenfd, use it to allow for cargo watch auto-reloading. + server.listen(l)? + } else { + // Bind to config for release. + server.bind(bind_addr)? + }; + + Ok(server.run().await?) +} diff --git a/dichroism/src/config.rs b/dichroism/src/config.rs index e5b4046..c3dec51 100644 --- a/dichroism/src/config.rs +++ b/dichroism/src/config.rs @@ -1 +1,31 @@ -struct Config {} +use crate::constants::*; +use crate::error::DichroismError; +use crate::result::Result; +use async_std::fs::metadata; +use async_std::path::PathBuf; +use std::env; +use std::net::SocketAddr; + +#[derive(Debug, Clone)] +pub struct Config { + pub db_url: String, + pub img_root: PathBuf, + pub bind_addr: SocketAddr, +} + +impl Config { + pub async fn new_from_env() -> Result { + let img_root = PathBuf::from(env::var(ENV_IMG_ROOT)?); + let meta = metadata(&img_root).await?; + + if !meta.is_dir() || meta.permissions().readonly() { + return Err(Box::new(DichroismError::InvalidImageRoot)); + } + + Ok(Config { + db_url: env::var(ENV_DB_URL)?, + img_root, + bind_addr: env::var(ENV_BIND_ADDR)?.parse()?, + }) + } +} diff --git a/dichroism/src/constants.rs b/dichroism/src/constants.rs new file mode 100644 index 0000000..fe45c1e --- /dev/null +++ b/dichroism/src/constants.rs @@ -0,0 +1,3 @@ +pub const ENV_IMG_ROOT: &str = "DICHROISM_IMG_ROOT"; +pub const ENV_BIND_ADDR: &str = "DICHROISM_BIND_ADDR"; +pub const ENV_DB_URL: &str = "DICHROISM_DB_URL"; diff --git a/dichroism/src/error.rs b/dichroism/src/error.rs index 2f01381..5e00abc 100644 --- a/dichroism/src/error.rs +++ b/dichroism/src/error.rs @@ -1,6 +1,7 @@ #[derive(Debug)] pub enum DichroismError { UriDataExtract, + InvalidImageRoot, } impl std::error::Error for DichroismError {} diff --git a/dichroism/src/handlers.rs b/dichroism/src/handlers.rs index 1e0ae28..e4ea6a0 100644 --- a/dichroism/src/handlers.rs +++ b/dichroism/src/handlers.rs @@ -1,13 +1,29 @@ +use super::image_repo; +use super::product_repo; +use super::types::DbPool; +use crate::config::Config; use crate::image_api; -use actix_web::{get, post, HttpResponse, Responder}; +use actix_web::{get, post, web, Error, HttpResponse, Responder}; #[get("/")] async fn hello() -> impl Responder { HttpResponse::Ok().body("Hey, this is an API!") } +#[get("/images")] +async fn get_images(pool: web::Data) -> Result { + let conn = pool.get().expect("Couldn't get DB connection from pool."); + let images = web::block(move || image_repo::read_images(&conn)) + .await + .map_err(|e| { + eprintln!("{}", e); + HttpResponse::InternalServerError().finish() + })?; + Ok(HttpResponse::Ok().json(images)) +} + #[post("/images")] -async fn create_image(req_body: String) -> impl Responder { +async fn create_image(_config: web::Data, req_body: String) -> impl Responder { let data = match image_api::extract_data(&req_body) { Err(e) => return HttpResponse::BadRequest().body(format!("fail: {}", e.to_string())), Ok(d) => d, @@ -24,6 +40,13 @@ async fn create_image(req_body: String) -> impl Responder { } #[get("/products")] -async fn get_products(_req_body: String) -> impl Responder { - HttpResponse::Ok().body("got products!") +async fn get_products(pool: web::Data) -> Result { + let conn = pool.get().expect("Couldn't get DB connection from pool."); + let products = web::block(move || product_repo::read_products(&conn)) + .await + .map_err(|e| { + eprintln!("{}", e); + HttpResponse::InternalServerError().finish() + })?; + Ok(HttpResponse::Ok().json(products)) } diff --git a/dichroism/src/image_api.rs b/dichroism/src/image_api.rs index 44effe4..97faead 100644 --- a/dichroism/src/image_api.rs +++ b/dichroism/src/image_api.rs @@ -3,10 +3,11 @@ use crate::result::Result; use base64::decode; use regex::Regex; -lazy_static! { - static ref DATA_URI_RE: Regex = - Regex::new("^data:image/(png|jpeg);base64,(?P.+)").expect("Couldn't parse Regex!"); -} +use once_cell::sync::Lazy; + +static DATA_URI_RE: Lazy = Lazy::new(|| { + Regex::new("^data:image/(png|jpeg);base64,(?P.+)").expect("Couldn't parse Regex.") +}); pub fn generate_images(data: &str) -> Result<()> { let bytes = decode(data)?; @@ -24,7 +25,7 @@ pub fn extract_data(uri: &str) -> Result<&str> { Ok(caps .name("data") - .expect("Should never fail if regex succeeded") + .expect("Should never fail if regex succeeded.") .as_str()) } diff --git a/dichroism/src/image_repo.rs b/dichroism/src/image_repo.rs new file mode 100644 index 0000000..c36f94e --- /dev/null +++ b/dichroism/src/image_repo.rs @@ -0,0 +1,32 @@ +use super::models::ProductImg; +use diesel::prelude::*; +use diesel::result::Error; + +type DBConn = SqliteConnection; + +pub fn read_images(conn: &DBConn) -> Result, Error> { + use crate::schema::images::dsl::*; + let results = images.load::(conn)?; + Ok(results) +} + +pub fn create_image() { + todo!() +} + +pub fn update_image() { + todo!() +} + +pub fn delete_image() { + todo!() +} + +#[cfg(test)] +mod tests { + + #[test] + fn test() -> std::result::Result<(), Box> { + Ok(()) + } +} diff --git a/dichroism/src/lib.rs b/dichroism/src/lib.rs new file mode 100644 index 0000000..e3842d3 --- /dev/null +++ b/dichroism/src/lib.rs @@ -0,0 +1,16 @@ +#[macro_use] +extern crate serde; +#[macro_use] +extern crate diesel; + +pub mod config; +mod constants; +mod error; +pub mod handlers; +mod image_api; +mod image_repo; +mod models; +mod product_repo; +pub mod result; +mod schema; +pub mod types; diff --git a/dichroism/src/main.rs b/dichroism/src/main.rs deleted file mode 100644 index 442b92d..0000000 --- a/dichroism/src/main.rs +++ /dev/null @@ -1,35 +0,0 @@ -#[macro_use] -extern crate lazy_static; - -use actix_web::{App, HttpServer}; -use listenfd::ListenFd; - -mod config; -mod error; -mod handlers; -mod image_api; -mod result; - -#[actix_web::main] -async fn main() -> std::io::Result<()> { - let mut listenfd = ListenFd::from_env(); - let mut server = HttpServer::new(|| { - App::new() - .service(handlers::hello) - .service(handlers::create_image) - .service(handlers::get_products) - }); - - server = if let Some(l) = listenfd - .take_tcp_listener(0) - .expect("Unable to grab TCP listener!") - { - // "Debug mode" with cargo watch auto-reloading - server.listen(l)? - } else { - // "Release mode" - server.bind("127.0.0.1:8000")? - }; - - server.run().await -} diff --git a/dichroism/src/models.rs b/dichroism/src/models.rs new file mode 100644 index 0000000..5516688 --- /dev/null +++ b/dichroism/src/models.rs @@ -0,0 +1,5 @@ +#[derive(Debug, Queryable, Serialize)] +pub struct ProductImg { + pub id: i32, + pub path: String, +} diff --git a/dichroism/src/product_api.rs b/dichroism/src/product_api.rs new file mode 100644 index 0000000..e69de29 diff --git a/dichroism/src/product_repo.rs b/dichroism/src/product_repo.rs new file mode 100644 index 0000000..67c5d3e --- /dev/null +++ b/dichroism/src/product_repo.rs @@ -0,0 +1,18 @@ +use super::models::ProductImg; +use diesel::prelude::*; +use diesel::result::Error; + +type DBConn = SqliteConnection; + +pub fn read_products(_conn: &DBConn) -> Result, Error> { + todo!() +} + +#[cfg(test)] +mod tests { + + #[test] + fn test() -> std::result::Result<(), Box> { + Ok(()) + } +} diff --git a/dichroism/src/schema.rs b/dichroism/src/schema.rs new file mode 100644 index 0000000..e1c4408 --- /dev/null +++ b/dichroism/src/schema.rs @@ -0,0 +1,6 @@ +table! { + images (id) { + id -> Integer, + path -> Text, + } +} diff --git a/dichroism/src/types.rs b/dichroism/src/types.rs new file mode 100644 index 0000000..91aef95 --- /dev/null +++ b/dichroism/src/types.rs @@ -0,0 +1,5 @@ +use diesel::r2d2::ConnectionManager; +use diesel::r2d2::Pool; +use diesel::SqliteConnection; + +pub type DbPool = Pool>; -- cgit v1.2.3