From 07d84821303ccd0c44e2170b00d3a82637bdaf79 Mon Sep 17 00:00:00 2001 From: Andrey Ermilov Date: Sun, 27 Aug 2023 17:56:29 +0200 Subject: [PATCH] refactor(config): layer uses generic Configurable --- examples/examples/axum.rs | 29 +++-- hitbox-tower/src/configuration/builder.rs | 88 ++++++++++++++ hitbox-tower/src/configuration/endpoint.rs | 47 +++++++- .../src/configuration/extractors/request.rs | 2 +- hitbox-tower/src/configuration/mod.rs | 1 + .../src/configuration/predicates/request.rs | 2 +- .../src/configuration/predicates/response.rs | 2 +- hitbox-tower/src/layer.rs | 107 +++++------------- hitbox-tower/src/service.rs | 5 +- hitbox/src/policy.rs | 5 +- 10 files changed, 194 insertions(+), 94 deletions(-) create mode 100644 hitbox-tower/src/configuration/builder.rs diff --git a/examples/examples/axum.rs b/examples/examples/axum.rs index f9602f5..8db2503 100644 --- a/examples/examples/axum.rs +++ b/examples/examples/axum.rs @@ -6,7 +6,7 @@ use hitbox_tower::{ }; use hitbox_redis::RedisBackend; -use hitbox_tower::Cache; +use hitbox_tower::{Cache, EndpointConfig}; async fn handler_result(Path(_name): Path) -> Result { //dbg!("axum::handler_result"); @@ -41,9 +41,12 @@ async fn main() { .finish(); tracing::subscriber::set_global_default(subscriber).unwrap(); - let backend = RedisBackend::new().unwrap(); - let json_cache = Cache::builder() - .backend(backend) + let redis_backend = RedisBackend::new().unwrap(); + let inmemory_backend = hitbox_stretto::StrettoBackend::builder(10) + .finalize() + .unwrap(); + + let json_config = EndpointConfig::builder() .request( request::method(Method::GET) .query("cache", "true") @@ -53,14 +56,22 @@ async fn main() { .response(response::status_code(StatusCode::OK)) .cache_key(extractor::method().query("cache").path("/{path}*")) .build(); - let backend = hitbox_stretto::StrettoBackend::builder(10) - .finalize() - .unwrap(); - let health_check = Cache::builder() - .backend(backend) // FIX: it should work withod backend + + let health_config = EndpointConfig::builder() .request(request::path("/health").method(Method::GET)) .disable() .build(); + + let json_cache = Cache::builder() + .backend(redis_backend) + .config(json_config) + .build(); + + let health_check = Cache::builder() + .backend(inmemory_backend) // FIX: it should work withod backend + .config(health_config) + .build(); + let app = Router::new() .route("/greet/:name/", get(handler_result)) .route("/", get(handler)) diff --git a/hitbox-tower/src/configuration/builder.rs b/hitbox-tower/src/configuration/builder.rs new file mode 100644 index 0000000..ef7b887 --- /dev/null +++ b/hitbox-tower/src/configuration/builder.rs @@ -0,0 +1,88 @@ +use crate::configuration::{ + ExtractorBuilder, RequestExtractor, RequestPredicate, RequestPredicateBuilder, + ResponsePredicate, ResponsePredicateBuilder, +}; +use crate::EndpointConfig; +use hitbox::policy::PolicyConfig; + +#[derive(Debug)] +pub struct EndpointConfigBuilder { + pub request_predicates: Vec, + pub response_predicates: Vec, + pub extractors: Vec, + pub policy: PolicyConfig, +} + +impl EndpointConfigBuilder { + pub fn new() -> Self { + Self { + request_predicates: Vec::new(), + response_predicates: Vec::new(), + extractors: Vec::new(), + policy: Default::default(), + } + } + + pub fn disable(self) -> Self { + Self { + request_predicates: self.request_predicates, + response_predicates: self.response_predicates, + extractors: self.extractors, + policy: PolicyConfig::Disabled, + } + } + + pub fn request(self, predicates: RequestPredicateBuilder) -> Self { + Self { + request_predicates: predicates.build(), + response_predicates: self.response_predicates, + extractors: self.extractors, + policy: self.policy, + } + } + + pub fn response(self, predicates: ResponsePredicateBuilder) -> Self { + Self { + request_predicates: self.request_predicates, + response_predicates: predicates.build(), + extractors: self.extractors, + policy: self.policy, + } + } + + pub fn cache_key(self, extractors: ExtractorBuilder) -> Self { + Self { + request_predicates: self.request_predicates, + response_predicates: self.response_predicates, + extractors: extractors.build(), + policy: self.policy, + } + } + + pub fn build(self) -> EndpointConfig { + EndpointConfig { + request_predicates: self.request_predicates, + response_predicates: self.response_predicates, + extractors: self.extractors, + policy: self.policy, + } + } +} + +impl Default for EndpointConfigBuilder { + fn default() -> Self { + Self { + request_predicates: Vec::new(), + response_predicates: vec![ResponsePredicate::StatusCode { + code: http::StatusCode::OK, + }], + extractors: vec![ + RequestExtractor::Path { + path: String::from("{path}*"), + }, + RequestExtractor::Method, + ], + policy: Default::default(), + } + } +} diff --git a/hitbox-tower/src/configuration/endpoint.rs b/hitbox-tower/src/configuration/endpoint.rs index dca5375..7f6a3ec 100644 --- a/hitbox-tower/src/configuration/endpoint.rs +++ b/hitbox-tower/src/configuration/endpoint.rs @@ -1,4 +1,6 @@ -use crate::configuration::{RequestExtractor, RequestPredicate, ResponsePredicate}; +use crate::configuration::{ + builder::EndpointConfigBuilder, RequestExtractor, RequestPredicate, ResponsePredicate, +}; use crate::Configurable; use hitbox::policy::PolicyConfig; use hitbox::predicate::Predicate; @@ -14,8 +16,9 @@ use hitbox_http::predicates::{ }; use hitbox_http::{CacheableHttpRequest, CacheableHttpResponse}; use serde::{Deserialize, Serialize}; +use std::sync::Arc; -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct EndpointConfig { pub request_predicates: Vec, pub response_predicates: Vec, @@ -32,6 +35,10 @@ impl EndpointConfig { policy: Default::default(), } } + + pub fn builder() -> EndpointConfigBuilder { + EndpointConfigBuilder::new() + } } impl Configurable for EndpointConfig { @@ -93,6 +100,42 @@ impl Configurable for EndpointConfig { } } +impl Configurable for Arc +where + C: Configurable, +{ + fn request_predicates( + &self, + ) -> Box> + Send + Sync> + where + ReqBody: Send + 'static, + { + self.as_ref().request_predicates() + } + + fn response_predicates( + &self, + ) -> Box> + Send + Sync> + where + ResBody: Send + 'static, + { + self.as_ref().response_predicates() + } + + fn extractors( + &self, + ) -> Box> + Send + Sync> + where + ReqBody: Send + 'static, + { + self.as_ref().extractors() + } + + fn policy(&self) -> PolicyConfig { + self.as_ref().policy() + } +} + impl Default for EndpointConfig { fn default() -> Self { Self { diff --git a/hitbox-tower/src/configuration/extractors/request.rs b/hitbox-tower/src/configuration/extractors/request.rs index 11fc3ec..0a02971 100644 --- a/hitbox-tower/src/configuration/extractors/request.rs +++ b/hitbox-tower/src/configuration/extractors/request.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum RequestExtractor { Path { path: String }, Method, diff --git a/hitbox-tower/src/configuration/mod.rs b/hitbox-tower/src/configuration/mod.rs index ea25e19..d7ac6c0 100644 --- a/hitbox-tower/src/configuration/mod.rs +++ b/hitbox-tower/src/configuration/mod.rs @@ -1,3 +1,4 @@ +pub mod builder; mod endpoint; mod extractors; mod predicates; diff --git a/hitbox-tower/src/configuration/predicates/request.rs b/hitbox-tower/src/configuration/predicates/request.rs index 368dfa0..fe749fb 100644 --- a/hitbox-tower/src/configuration/predicates/request.rs +++ b/hitbox-tower/src/configuration/predicates/request.rs @@ -1,7 +1,7 @@ use crate::configuration::serializers::method; use serde::{Deserialize, Serialize}; -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum RequestPredicate { Path { path: String, diff --git a/hitbox-tower/src/configuration/predicates/response.rs b/hitbox-tower/src/configuration/predicates/response.rs index 4637cd1..e75f0e4 100644 --- a/hitbox-tower/src/configuration/predicates/response.rs +++ b/hitbox-tower/src/configuration/predicates/response.rs @@ -1,7 +1,7 @@ use crate::configuration::serializers::status_code; use serde::{Deserialize, Serialize}; -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum ResponsePredicate { #[serde(with = "status_code")] StatusCode { code: http::StatusCode }, diff --git a/hitbox-tower/src/layer.rs b/hitbox-tower/src/layer.rs index 05f1fcb..2ad27fb 100644 --- a/hitbox-tower/src/layer.rs +++ b/hitbox-tower/src/layer.rs @@ -1,134 +1,87 @@ -use crate::configuration::{ - EndpointConfig, ExtractorBuilder, RequestPredicateBuilder, ResponsePredicateBuilder, -}; +use crate::configuration::EndpointConfig; use std::sync::Arc; -use hitbox::{ - backend::CacheBackend, - policy::{EnabledCacheConfig, PolicyConfig}, -}; +use hitbox::backend::CacheBackend; use hitbox_stretto::StrettoBackend; use tower::Layer; use crate::service::CacheService; #[derive(Clone)] -pub struct Cache { +pub struct Cache { pub backend: Arc, - pub configuration: Arc, + pub configuration: C, } -impl Cache { - pub fn new(backend: B) -> Cache { +impl Cache +where + C: Default, +{ + pub fn new(backend: B) -> Cache { Cache { backend: Arc::new(backend), - configuration: Arc::new(Default::default()), + configuration: Default::default(), } } } -impl Layer for Cache { - type Service = CacheService; +impl Layer for Cache +where + C: Clone, +{ + type Service = CacheService; fn layer(&self, upstream: S) -> Self::Service { CacheService::new( upstream, Arc::clone(&self.backend), - Arc::clone(&self.configuration), + self.configuration.clone(), ) } } -impl Cache { - pub fn builder() -> CacheBuilder { +impl Cache { + pub fn builder() -> CacheBuilder { CacheBuilder::default() } } -pub struct CacheBuilder { +pub struct CacheBuilder { backend: Option, - configuration: EndpointConfig, + configuration: C, } -impl CacheBuilder +impl CacheBuilder where B: CacheBackend, + C: Default, { - pub fn backend(self, backend: NB) -> CacheBuilder { + pub fn backend(self, backend: NB) -> CacheBuilder { CacheBuilder { backend: Some(backend), configuration: self.configuration, } } - pub fn enable(self, policy: EnabledCacheConfig) -> Self { - let configuration = EndpointConfig { - request_predicates: self.configuration.request_predicates, - response_predicates: self.configuration.response_predicates, - extractors: self.configuration.extractors, - policy: PolicyConfig::Enabled(policy), - }; - CacheBuilder { - backend: self.backend, - configuration, - } - } - - pub fn disable(self) -> Self { - CacheBuilder { - backend: self.backend, - configuration: self.configuration, - } - } - - pub fn request(self, predicates: RequestPredicateBuilder) -> Self { - let configuration = EndpointConfig { - request_predicates: predicates.build(), - response_predicates: self.configuration.response_predicates, - extractors: self.configuration.extractors, - policy: self.configuration.policy, - }; - CacheBuilder { - backend: self.backend, - configuration, - } - } - - pub fn response(self, predicates: ResponsePredicateBuilder) -> Self { - let configuration = EndpointConfig { - request_predicates: self.configuration.request_predicates, - response_predicates: predicates.build(), - extractors: self.configuration.extractors, - policy: self.configuration.policy, - }; - CacheBuilder { - backend: self.backend, - configuration, - } - } - - pub fn cache_key(self, extractors: ExtractorBuilder) -> Self { - let configuration = EndpointConfig { - request_predicates: self.configuration.request_predicates, - response_predicates: self.configuration.response_predicates, - extractors: extractors.build(), - policy: self.configuration.policy, - }; + pub fn config(self, configuration: NC) -> CacheBuilder { CacheBuilder { backend: self.backend, configuration, } } - pub fn build(self) -> Cache { + pub fn build(self) -> Cache { Cache { backend: Arc::new(self.backend.expect("Please add some cache backend")), - configuration: Arc::new(self.configuration), + configuration: self.configuration, } } } -impl Default for CacheBuilder { +impl Default for CacheBuilder +where + C: Default, +{ fn default() -> Self { Self { backend: None, diff --git a/hitbox-tower/src/service.rs b/hitbox-tower/src/service.rs index c58e958..f88866e 100644 --- a/hitbox-tower/src/service.rs +++ b/hitbox-tower/src/service.rs @@ -12,11 +12,11 @@ use crate::future::Transformer; pub struct CacheService { upstream: S, backend: Arc, - configuration: Arc, + configuration: C, } impl CacheService { - pub fn new(upstream: S, backend: Arc, configuration: Arc) -> Self { + pub fn new(upstream: S, backend: Arc, configuration: C) -> Self { CacheService { upstream, backend, @@ -29,6 +29,7 @@ impl Clone for CacheService where S: Clone, B: Clone, + C: Clone, { fn clone(&self) -> Self { Self { diff --git a/hitbox/src/policy.rs b/hitbox/src/policy.rs index 449ae61..1c5ff2c 100644 --- a/hitbox/src/policy.rs +++ b/hitbox/src/policy.rs @@ -14,6 +14,9 @@ pub enum PolicyConfig { impl Default for PolicyConfig { fn default() -> Self { - Self::Enabled(Default::default()) + Self::Enabled(EnabledCacheConfig { + ttl: Some(5), + stale_cache: None, + }) } }