diff --git a/app/src/main.rs b/app/src/main.rs index ab1021b..f77a62e 100644 --- a/app/src/main.rs +++ b/app/src/main.rs @@ -2,6 +2,53 @@ use std::sync::Arc; use sqlx::SqlitePool; +type PermissionService = + service_impl::PermissionServiceImpl; +type HelloService = service_impl::HelloServiceImpl; + +#[derive(Clone)] +pub struct RestStateImpl { + hello_service: Arc, + permission_service: Arc, +} +impl rest::RestStateDef for RestStateImpl { + type HelloService = HelloService; + type PermissionService = PermissionService; + + fn hello_service(&self) -> Arc { + self.hello_service.clone() + } + fn permission_service(&self) -> Arc { + self.permission_service.clone() + } +} +impl RestStateImpl { + pub fn new(pool: Arc>) -> Self { + let hello_dao = dao_impl::HelloDaoImpl::new(pool.clone()); + let permission_dao = dao_impl::PermissionDaoImpl::new(pool); + + // Always authenticate with DEVUSER during development. + // This is used to test the permission service locally without a login service. + // + // TODO: Implement a proper authentication service when used in produciton. Maybe + // use differnet implementations on debug then on release. Or control it via a + // feature. + let user_service = service_impl::UserServiceDev; + let permission_service = Arc::new(service_impl::PermissionServiceImpl::new( + permission_dao.into(), + user_service.into(), + )); + let hello_service = Arc::new(service_impl::HelloServiceImpl::new( + hello_dao.into(), + permission_service.clone(), + )); + Self { + hello_service, + permission_service, + } + } +} + #[tokio::main] async fn main() { let pool = Arc::new( @@ -9,19 +56,6 @@ async fn main() { .await .expect("Could not connect to database"), ); - let hello_dao = dao_impl::HelloDaoImpl::new(pool.clone()); - let permission_dao = dao_impl::PermissionDaoImpl::new(pool); - - // Always authenticate with DEVUSER during development. - // This is used to test the permission service locally without a login service. - // - // TODO: Implement a proper authentication service when used in produciton. Maybe - // use differnet implementations on debug then on release. Or control it via a - // feature. - let user_service = service_impl::UserServiceDev; - let permission_service = - service_impl::PermissionServiceImpl::new(permission_dao.into(), user_service.into()); - let hello_service = - service_impl::HelloServiceImpl::new(hello_dao.into(), permission_service.into()); - rest::start_server(hello_service).await + let rest_state = RestStateImpl::new(pool); + rest::start_server(rest_state).await } diff --git a/rest/src/hello.rs b/rest/src/hello.rs new file mode 100644 index 0000000..4e9ae6b --- /dev/null +++ b/rest/src/hello.rs @@ -0,0 +1,14 @@ +use axum::{extract::State, response::Response}; + +use crate::{error_handler, RestStateDef, RoString}; +use service::HelloService; + +pub async fn hello(State(rest_state): State) -> Response { + error_handler( + (async { + let string = rest_state.hello_service().hello().await?; + Ok(RoString::from(string).into()) + }) + .await, + ) +} diff --git a/rest/src/lib.rs b/rest/src/lib.rs index 7dddcc5..fc97bdc 100644 --- a/rest/src/lib.rs +++ b/rest/src/lib.rs @@ -1,14 +1,9 @@ -use serde::{Deserialize, Serialize}; use std::{convert::Infallible, sync::Arc}; -use uuid::Uuid; -use axum::{ - body::Body, - extract::State, - response::Response, - routing::{get, post}, - Json, Router, -}; +mod hello; +mod permission; + +use axum::{body::Body, response::Response, routing::get, Router}; pub struct RoString(Arc, bool); impl http_body::Body for RoString { @@ -57,38 +52,19 @@ fn error_handler(result: Result) -> Response { } } -async fn root( - State(hello_service): State>, -) -> Response { - error_handler( - (async { - let string = hello_service.hello().await?; - Ok(RoString::from(string).into()) - }) - .await, - ) +pub trait RestStateDef: Clone + Send + Sync + 'static { + type HelloService: service::HelloService + Send + Sync + 'static; + type PermissionService: service::PermissionService + Send + Sync + 'static; + + fn hello_service(&self) -> Arc; + fn permission_service(&self) -> Arc; } -#[derive(Debug, Serialize, Deserialize)] -pub struct User { - #[serde(default)] - pub id: Uuid, - pub name: String, -} - -async fn add_user(Json(user): Json) -> Response { - println!("Adding user: {:?}", user); - Response::builder().status(200).body(Body::empty()).unwrap() -} - -pub async fn start_server(hello_service: HelloService) -where - HelloService: service::HelloService + Send + Sync + 'static, -{ +pub async fn start_server(rest_state: RestState) { let app = Router::new() - .route("/", get(root)) - .route("/user", post(add_user)) - .with_state(Arc::new(hello_service)); + .route("/", get(hello::hello::)) + .nest("/permission", permission::generate_route()) + .with_state(rest_state); let listener = tokio::net::TcpListener::bind("127.0.0.1:3000") .await .expect("Could not bind server"); diff --git a/rest/src/permission.rs b/rest/src/permission.rs new file mode 100644 index 0000000..3b26440 --- /dev/null +++ b/rest/src/permission.rs @@ -0,0 +1,37 @@ +use axum::{body::Body, extract::State, response::Response, routing::post, Json, Router}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use crate::{error_handler, RestStateDef}; +use service::PermissionService; + +#[derive(Debug, Serialize, Deserialize)] +pub struct User { + #[serde(default)] + pub id: Uuid, + pub name: String, +} + +pub fn generate_route() -> Router { + Router::new().route("/user/", post(add_user::)) +} + +pub async fn add_user( + rest_state: State, + Json(user): Json, +) -> Response { + println!("Adding user: {:?}", user); + error_handler( + (async { + rest_state + .permission_service() + .create_user(user.name.as_str()) + .await?; + Ok(Response::builder() + .status(200) + .body(Body::from("")) + .unwrap()) + }) + .await, + ) +}