pub mod handler; pub mod state; use std::{collections::HashMap, future::Future, pin::Pin, str::FromStr, sync::Arc}; use futures_util::FutureExt; use giterated_models::{ error::OperationError, 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: HashMap>, get_object: Vec>, } impl Default for OperationHandlers { fn default() -> Self { Self { operations: HashMap::new(), get_object: Vec::new(), } } } impl OperationHandlers { pub fn insert< O: GiteratedObject + Send + Sync, D: GiteratedOperation + 'static, H: GiteratedOperationHandler + Send + Sync + 'static + Clone, >( &mut self, handler: H, ) -> &mut Self { let object_name = handler.object_name().to_string(); let operation_name = handler.operation_name().to_string(); let wrapped = OperationWrapper::new(handler); let pair = ObjectOperationPair { object_name, operation_name, }; assert!(self.operations.insert(pair, wrapped).is_none()); self } pub fn register_object(&mut self) -> &mut Self { let closure = |_: &Instance, operation: ObjectRequest, _state| { async move { if O::from_str(&operation.0).is_ok() { Ok(ObjectResponse(operation.0)) } else { Err(OperationError::Unhandled) } } .boxed() }; let wrapped = OperationWrapper::new(closure); self.get_object.push(wrapped); self } pub async fn handle( &self, object: &O, operation_name: &str, operation: AnyOperation, state: S, ) -> Result, OperationError>> { // 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 } else { Err(OperationError::Unhandled) } } pub async fn resolve_object( &self, instance: AnyObject, request: ObjectRequest, state: S, ) -> Result, OperationError>> { for handler in self.get_object.iter() { if let Ok(response) = handler .handle( instance.clone(), AnyOperation(serde_json::to_value(request.clone()).unwrap()), state.clone(), ) .await { return Ok(response); } } Err(OperationError::Unhandled) } } #[async_trait::async_trait] pub trait GiteratedOperationHandler< O: GiteratedObject, D: GiteratedOperation, S: Send + Sync + Clone, > { fn operation_name(&self) -> &str; fn object_name(&self) -> &str; async fn handle( &self, object: &O, operation: D, state: S, ) -> Result>; } #[async_trait::async_trait] impl GiteratedOperationHandler for F where F: FnMut( &O, D, S, ) -> Pin< Box>> + Send>, > + Send + Sync + Clone, O: GiteratedObject + Send + Sync, D: GiteratedOperation + 'static, >::Failure: Send, S: Send + Sync + Clone + 'static, { fn operation_name(&self) -> &str { D::operation_name() } fn object_name(&self) -> &str { O::object_name() } async fn handle( &self, object: &O, operation: D, state: S, ) -> Result> { self.clone()(object, operation, state).await } } pub struct OperationWrapper { func: Box< dyn Fn( AnyObject, AnyOperation, S, ) -> Pin, OperationError>>> + Send>> + Send + Sync, >, object_name: String, } impl OperationWrapper { pub fn new< O: GiteratedObject + Send + Sync, D: GiteratedOperation + 'static, F: GiteratedOperationHandler + Send + Sync + 'static + Clone, >( handler: F, ) -> Self { let handler = Arc::new(Box::pin(handler)); Self { func: Box::new(move |any_object, any_operation, state| { let handler = handler.clone(); 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( &self, object: AnyObject, operation: AnyOperation, state: S, ) -> Result, OperationError>> { (self.func)(object, operation, state).await } }