diff --git a/giterated-stack/src/lib.rs b/giterated-stack/src/lib.rs index 8a3d012..6f252ea 100644 --- a/giterated-stack/src/lib.rs +++ b/giterated-stack/src/lib.rs @@ -1,7 +1,7 @@ pub mod handler; pub mod state; -use std::{future::Future, pin::Pin, sync::Arc}; +use std::{collections::HashMap, future::Future, pin::Pin, str::FromStr, sync::Arc}; use futures_util::FutureExt; use giterated_models::{ @@ -9,17 +9,26 @@ use giterated_models::{ instance::Instance, object::{AnyObject, GiteratedObject, ObjectRequest, ObjectResponse}, operation::{AnyOperation, GiteratedOperation}, + repository::Repository, + user::User, }; +use tracing::info; + +#[derive(Clone, Debug, Hash, Eq, PartialEq)] +struct ObjectOperationPair { + object_name: String, + operation_name: String, +} pub struct OperationHandlers { - operations: Vec>, + operations: HashMap>, get_object: Vec>, } impl Default for OperationHandlers { fn default() -> Self { Self { - operations: Vec::new(), + operations: HashMap::new(), get_object: Vec::new(), } } @@ -34,11 +43,17 @@ impl OperationHandlers { &mut self, handler: H, ) -> &mut Self { - let _operation_name = handler.operation_name().to_string(); + let object_name = handler.object_name().to_string(); + let operation_name = handler.operation_name().to_string(); let wrapped = OperationWrapper::new(handler); - self.operations.push(wrapped); + let pair = ObjectOperationPair { + object_name, + operation_name, + }; + + assert!(self.operations.insert(pair, wrapped).is_none()); self } @@ -65,29 +80,42 @@ impl OperationHandlers { pub async fn handle( &self, object: &O, - _operation_name: &str, + operation_name: &str, operation: AnyOperation, state: S, ) -> Result, OperationError>> { - for handler in self.operations.iter() { - return match handler + // TODO + let object = object.to_string(); + + let object_name = { + if User::from_str(&object).is_ok() { + User::object_name() + } else if Repository::from_str(&object).is_ok() { + Repository::object_name() + } else if Instance::from_str(&object).is_ok() { + Instance::object_name() + } else { + return Err(OperationError::Unhandled); + } + } + .to_string(); + + let target_handler = ObjectOperationPair { + object_name, + operation_name: operation_name.to_string(), + }; + + if let Some(handler) = self.operations.get(&target_handler) { + handler .handle( AnyObject(object.to_string()), operation.clone(), state.clone(), ) .await - { - Ok(ok) => Ok(ok), - Err(err) => Err(match err { - OperationError::Operation(err) => OperationError::Operation(err), - OperationError::Internal(err) => OperationError::Internal(err), - OperationError::Unhandled => continue, - }), - }; + } else { + Err(OperationError::Unhandled) } - - Err(OperationError::Unhandled) } pub async fn resolve_object( @@ -166,8 +194,8 @@ where } } -pub struct OperationWrapper( - Box< +pub struct OperationWrapper { + func: Box< dyn Fn( AnyObject, AnyOperation, @@ -177,7 +205,8 @@ pub struct OperationWrapper( + Send + Sync, >, -); + object_name: String, +} impl OperationWrapper { pub fn new< @@ -188,28 +217,33 @@ impl OperationWrapper { handler: F, ) -> Self { let handler = Arc::new(Box::pin(handler)); - Self(Box::new(move |any_object, any_operation, state| { - let handler = handler.clone(); - async move { + Self { + func: Box::new(move |any_object, any_operation, state| { let handler = handler.clone(); - let object: O = - O::from_object_str(&any_object.0).map_err(|_| OperationError::Unhandled)?; - let operation: D = serde_json::from_value(any_operation.0.clone()) - .map_err(|_| OperationError::Unhandled)?; - - let result = handler.handle(&object, operation, state).await; - result - .map(|success| serde_json::to_vec(&success).unwrap()) - .map_err(|err| match err { - OperationError::Operation(err) => { - OperationError::Operation(serde_json::to_vec(&err).unwrap()) - } - OperationError::Internal(internal) => OperationError::Internal(internal), - OperationError::Unhandled => OperationError::Unhandled, - }) - } - .boxed() - })) + async move { + let handler = handler.clone(); + let object: O = + O::from_object_str(&any_object.0).map_err(|_| OperationError::Unhandled)?; + let operation: D = serde_json::from_value(any_operation.0.clone()) + .map_err(|_| OperationError::Unhandled)?; + + let result = handler.handle(&object, operation, state).await; + result + .map(|success| serde_json::to_vec(&success).unwrap()) + .map_err(|err| match err { + OperationError::Operation(err) => { + OperationError::Operation(serde_json::to_vec(&err).unwrap()) + } + OperationError::Internal(internal) => { + OperationError::Internal(internal) + } + OperationError::Unhandled => OperationError::Unhandled, + }) + } + .boxed() + }), + object_name: O::object_name().to_string(), + } } async fn handle( @@ -218,6 +252,6 @@ impl OperationWrapper { operation: AnyOperation, state: S, ) -> Result, OperationError>> { - self.0(object, operation, state).await + (self.func)(object, operation, state).await } }