From 28ec0823f399904125ac8c93e7571f8f91395690 Mon Sep 17 00:00:00 2001 From: Maximilian Pohl Date: Tue, 3 Sep 2024 14:04:24 +0200 Subject: [PATCH] Delete InMemory storage backend --- openadr-vtn/Cargo.toml | 1 + openadr-vtn/src/data_source/memory/event.rs | 113 --------------- openadr-vtn/src/data_source/memory/mod.rs | 39 ------ openadr-vtn/src/data_source/memory/program.rs | 132 ------------------ openadr-vtn/src/data_source/memory/report.rs | 100 ------------- openadr-vtn/src/data_source/memory/user.rs | 14 -- openadr-vtn/src/data_source/mod.rs | 4 - openadr-vtn/src/main.rs | 11 +- 8 files changed, 7 insertions(+), 407 deletions(-) delete mode 100644 openadr-vtn/src/data_source/memory/event.rs delete mode 100644 openadr-vtn/src/data_source/memory/mod.rs delete mode 100644 openadr-vtn/src/data_source/memory/program.rs delete mode 100644 openadr-vtn/src/data_source/memory/report.rs delete mode 100644 openadr-vtn/src/data_source/memory/user.rs diff --git a/openadr-vtn/Cargo.toml b/openadr-vtn/Cargo.toml index 8ad8f74..32a3d98 100644 --- a/openadr-vtn/Cargo.toml +++ b/openadr-vtn/Cargo.toml @@ -44,5 +44,6 @@ dotenvy = {workspace = true, optional = true} tokio = { workspace = true, features = ["full", "test-util"] } [features] +default = ["postgres"] live-db-test = ["postgres"] postgres = ["sqlx/postgres", "dep:dotenvy"] \ No newline at end of file diff --git a/openadr-vtn/src/data_source/memory/event.rs b/openadr-vtn/src/data_source/memory/event.rs deleted file mode 100644 index 456d527..0000000 --- a/openadr-vtn/src/data_source/memory/event.rs +++ /dev/null @@ -1,113 +0,0 @@ -use crate::api::event::QueryParams; -use crate::data_source::{Crud, EventCrud}; -use crate::error::AppError; -use axum::async_trait; -use chrono::Utc; -use openadr_wire::event::{EventContent, EventId}; -use openadr_wire::target::TargetLabel; -use openadr_wire::Event; -use std::collections::HashMap; -use tokio::sync::RwLock; -use uuid::Uuid; - -impl EventCrud for RwLock> {} - -pub fn new_event(content: EventContent) -> Event { - Event { - id: format!("event-{}", Uuid::new_v4()).parse().unwrap(), - created_date_time: Utc::now(), - modification_date_time: Utc::now(), - content, - } -} - -impl QueryParams { - pub fn matches(&self, event: &Event) -> Result { - if let Some(program_id) = &self.program_id { - if &event.content.program_id != program_id { - return Ok(false); - } - } - - if let Some(target_type) = self.target_type.as_ref() { - match target_type { - TargetLabel::EventName => { - let Some(ref event_name) = event.content.event_name else { - return Ok(false); - }; - - let Some(target_values) = &self.target_values else { - return Err(AppError::BadRequest( - "If targetType is specified, targetValues must be specified as well", - )); - }; - - Ok(target_values.iter().any(|name| name == event_name)) - } - _ => Err(AppError::NotImplemented( - "only filtering by event name is supported", - )), - } - } else { - Ok(true) - } - } -} - -#[async_trait] -impl Crud for RwLock> { - type Type = Event; - type Id = EventId; - type NewType = EventContent; - type Error = AppError; - type Filter = QueryParams; - - async fn create(&self, content: Self::NewType) -> Result { - let event = new_event(content); - self.write().await.insert(event.id.clone(), event.clone()); - Ok(event) - } - - async fn retrieve(&self, id: &Self::Id) -> Result { - self.read().await.get(id).cloned().ok_or(AppError::NotFound) - } - - async fn retrieve_all( - &self, - query_params: &Self::Filter, - ) -> Result, Self::Error> { - self.read() - .await - .values() - .filter_map(|event| match query_params.matches(event) { - Ok(true) => Some(Ok(event.clone())), - Ok(false) => None, - Err(err) => Some(Err(err)), - }) - .skip(query_params.skip as usize) - .take(query_params.limit as usize) - .collect::, AppError>>() - } - - async fn update( - &self, - id: &Self::Id, - content: Self::NewType, - ) -> Result { - match self.write().await.get_mut(id) { - Some(occupied) => { - occupied.content = content; - occupied.modification_date_time = Utc::now(); - Ok(occupied.clone()) - } - None => Err(AppError::NotFound), - } - } - - async fn delete(&self, id: &Self::Id) -> Result { - match self.write().await.remove(id) { - Some(event) => Ok(event), - None => Err(AppError::NotFound), - } - } -} diff --git a/openadr-vtn/src/data_source/memory/mod.rs b/openadr-vtn/src/data_source/memory/mod.rs deleted file mode 100644 index d8473b1..0000000 --- a/openadr-vtn/src/data_source/memory/mod.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::data_source::{AuthInfo, AuthSource, DataSource, EventCrud, ProgramCrud, ReportCrud}; -use openadr_wire::event::EventId; -use openadr_wire::program::ProgramId; -use openadr_wire::report::ReportId; -use openadr_wire::{Event, Program, Report}; -use std::collections::HashMap; -use std::sync::Arc; -use tokio::sync::RwLock; - -mod event; -mod program; -mod report; -mod user; - -#[derive(Default, Clone)] -pub struct InMemoryStorage { - pub programs: Arc>>, - pub reports: Arc>>, - pub events: Arc>>, - pub auth: Arc>>, -} - -impl DataSource for InMemoryStorage { - fn programs(&self) -> Arc { - self.programs.clone() - } - - fn reports(&self) -> Arc { - self.reports.clone() - } - - fn events(&self) -> Arc { - self.events.clone() - } - - fn auth(&self) -> Arc { - self.auth.clone() - } -} diff --git a/openadr-vtn/src/data_source/memory/program.rs b/openadr-vtn/src/data_source/memory/program.rs deleted file mode 100644 index d8d46a0..0000000 --- a/openadr-vtn/src/data_source/memory/program.rs +++ /dev/null @@ -1,132 +0,0 @@ -use crate::api::program::QueryParams; -use crate::data_source::{Crud, ProgramCrud}; -use crate::error::AppError; -use axum::async_trait; -use chrono::Utc; -use openadr_wire::program::{ProgramContent, ProgramId}; -use openadr_wire::target::TargetLabel; -use openadr_wire::Program; -use std::collections::HashMap; -use tokio::sync::RwLock; -use tracing::{info, warn}; -use uuid::Uuid; - -impl ProgramCrud for RwLock> {} - -pub fn new_program(content: ProgramContent) -> Program { - Program { - id: format!("program-{}", Uuid::new_v4()).parse().unwrap(), - created_date_time: Utc::now(), - modification_date_time: Utc::now(), - content, - } -} - -impl QueryParams { - pub fn matches(&self, program: &Program) -> Result { - if let Some(target_type) = self.target_type.clone() { - return match target_type { - TargetLabel::ProgramName => Ok(self - .target_values - .clone() - .ok_or(AppError::BadRequest( - "If targetType is specified, targetValues must be specified as well", - ))? - .into_iter() - .any(|name| name == program.content.program_name)), - _ => Err(AppError::NotImplemented( - "Program can only be filtered by name", - )), - }; - } - Ok(true) - } -} - -#[async_trait] -impl Crud for RwLock> { - type Type = Program; - type Id = ProgramId; - type NewType = ProgramContent; - type Error = AppError; - type Filter = QueryParams; - - async fn create(&self, new: Self::NewType) -> Result { - if let Some(conflict) = self - .read() - .await - .values() - .find(|p| p.content.program_name == new.program_name) - { - warn!(id=%conflict.id, program_name=%new.program_name, "Conflicting program_name"); - return Err(AppError::Conflict(format!( - "Program with id {} has the same name", - conflict.id - ))); - } - - let program = new_program(new); - self.write() - .await - .insert(program.id.clone(), program.clone()); - - info!(%program.id, - program.program_name=program.content.program_name, - "program created" - ); - - Ok(program) - } - - async fn retrieve(&self, id: &Self::Id) -> Result { - self.read().await.get(id).cloned().ok_or(AppError::NotFound) - } - - async fn retrieve_all(&self, filter: &Self::Filter) -> Result, Self::Error> { - self.read() - .await - .values() - .filter_map(|program| match filter.matches(program) { - Ok(true) => Some(Ok(program.clone())), - Ok(false) => None, - Err(err) => Some(Err(err)), - }) - .skip(filter.skip as usize) - .take(filter.limit as usize) - .collect::, AppError>>() - } - - async fn update( - &self, - id: &Self::Id, - content: Self::NewType, - ) -> Result { - if let Some((_, conflict)) = - self.read().await.iter().find(|(inner_id, p)| { - id != *inner_id && p.content.program_name == content.program_name - }) - { - warn!(updated=%id, conflicting=%conflict.id, program_name=%content.program_name, "Conflicting program_name"); - return Err(AppError::Conflict(format!( - "Program with id {} has the same name", - conflict.id - ))); - } - - match self.write().await.get_mut(id) { - Some(occupied) => { - occupied.content = content; - occupied.modification_date_time = Utc::now(); - Ok(occupied.clone()) - } - None => Err(AppError::NotFound), - } - } - - async fn delete(&self, id: &Self::Id) -> Result { - match self.write().await.remove(id) { - Some(program) => Ok(program), - None => Err(AppError::NotFound), - } - } -} diff --git a/openadr-vtn/src/data_source/memory/report.rs b/openadr-vtn/src/data_source/memory/report.rs deleted file mode 100644 index 31580ab..0000000 --- a/openadr-vtn/src/data_source/memory/report.rs +++ /dev/null @@ -1,100 +0,0 @@ -use crate::api::report::QueryParams; -use crate::data_source::{Crud, ReportCrud}; -use crate::error::AppError; -use axum::async_trait; -use chrono::Utc; -use openadr_wire::report::{ReportContent, ReportId}; -use openadr_wire::Report; -use std::collections::HashMap; -use tokio::sync::RwLock; -use uuid::Uuid; - -impl ReportCrud for RwLock> {} - -pub fn new_report(content: ReportContent) -> Report { - Report { - id: format!("report-{}", Uuid::new_v4()).parse().unwrap(), - created_date_time: Utc::now(), - modification_date_time: Utc::now(), - content, - } -} - -impl QueryParams { - pub fn matches(&self, report: &Report) -> Result { - if let Some(event_id) = &self.event_id { - Ok(&report.content.event_id == event_id) - } else if let Some(client_name) = &self.client_name { - Ok(&report.content.client_name == client_name) - } else if let Some(program_id) = &self.program_id { - Ok(&report.content.program_id == program_id) - } else { - Ok(true) - } - } -} - -#[async_trait] -impl Crud for RwLock> { - type Type = Report; - type Id = ReportId; - type NewType = ReportContent; - type Error = AppError; - type Filter = QueryParams; - - // TODO - // '409': - // description: Conflict. Implementation dependent response if report with the same reportName exists. - // content: - // application/json: - // schema: - // $ref: '#/components/schemas/problem' - async fn create(&self, content: Self::NewType) -> Result { - let event = new_report(content); - self.write().await.insert(event.id.clone(), event.clone()); - Ok(event) - } - - async fn retrieve(&self, id: &Self::Id) -> Result { - self.read().await.get(id).cloned().ok_or(AppError::NotFound) - } - - async fn retrieve_all( - &self, - query_params: &Self::Filter, - ) -> Result, Self::Error> { - self.read() - .await - .values() - .filter_map(|event| match query_params.matches(event) { - Ok(true) => Some(Ok(event.clone())), - Ok(false) => None, - Err(err) => Some(Err(err)), - }) - .skip(query_params.skip as usize) - .take(query_params.limit as usize) - .collect::, AppError>>() - } - - async fn update( - &self, - id: &Self::Id, - content: Self::NewType, - ) -> Result { - match self.write().await.get_mut(id) { - Some(occupied) => { - occupied.content = content; - occupied.modification_date_time = Utc::now(); - Ok(occupied.clone()) - } - None => Err(AppError::NotFound), - } - } - - async fn delete(&self, id: &Self::Id) -> Result { - match self.write().await.remove(id) { - Some(event) => Ok(event), - None => Err(AppError::NotFound), - } - } -} diff --git a/openadr-vtn/src/data_source/memory/user.rs b/openadr-vtn/src/data_source/memory/user.rs deleted file mode 100644 index e1f4e98..0000000 --- a/openadr-vtn/src/data_source/memory/user.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::data_source::{AuthInfo, AuthSource}; -use axum::async_trait; -use tokio::sync::RwLock; - -#[async_trait] -impl AuthSource for RwLock> { - async fn get_user(&self, client_id: &str, client_secret: &str) -> Option { - self.read() - .await - .iter() - .find(|auth| auth.client_id == client_id && auth.client_secret == client_secret) - .cloned() - } -} diff --git a/openadr-vtn/src/data_source/mod.rs b/openadr-vtn/src/data_source/mod.rs index d591c54..b8b0dab 100644 --- a/openadr-vtn/src/data_source/mod.rs +++ b/openadr-vtn/src/data_source/mod.rs @@ -1,5 +1,3 @@ -#[cfg(not(feature = "sqlx"))] -mod memory; #[cfg(feature = "postgres")] mod postgres; @@ -12,8 +10,6 @@ use openadr_wire::{ }; use std::sync::Arc; -#[cfg(not(feature = "sqlx"))] -pub use memory::InMemoryStorage; #[cfg(feature = "postgres")] pub use postgres::PostgresStorage; diff --git a/openadr-vtn/src/main.rs b/openadr-vtn/src/main.rs index 4effc15..05d9ad9 100644 --- a/openadr-vtn/src/main.rs +++ b/openadr-vtn/src/main.rs @@ -5,8 +5,6 @@ use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::{fmt, EnvFilter}; -#[cfg(not(feature = "postgres"))] -use openadr_vtn::data_source::InMemoryStorage; #[cfg(feature = "postgres")] use openadr_vtn::data_source::PostgresStorage; use openadr_vtn::jwt::JwtManager; @@ -26,10 +24,13 @@ async fn main() { #[cfg(feature = "postgres")] let storage = PostgresStorage::from_env().await.unwrap(); - #[cfg(not(feature = "sqlx"))] - let storage = InMemoryStorage::default(); - let state = AppState::new(storage, JwtManager::from_base64_secret("test").unwrap()); + #[cfg(not(feature = "postgres"))] + compile_error!( + "No storage backend selected. Please enable the `postgres` feature flag during compilation" + ); + // TODO make the JWT secret secure and configurable + let state = AppState::new(storage, JwtManager::from_base64_secret("test").unwrap()); if let Err(e) = axum::serve(listener, state.into_router()) .with_graceful_shutdown(shutdown_signal()) .await