diff --git a/Cargo.lock b/Cargo.lock index ee77d2d..a07bcf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -844,6 +844,7 @@ dependencies = [ "futures-util", "git2", "giterated-api", + "giterated-cache", "giterated-models", "giterated-stack", "jsonwebtoken", diff --git a/giterated-cache/src/cache_get.rs b/giterated-cache/src/cache_get.rs index caa2e8c..b212436 100644 --- a/giterated-cache/src/cache_get.rs +++ b/giterated-cache/src/cache_get.rs @@ -14,3 +14,41 @@ // ) -> Result> { // todo!() // } + +use std::sync::Arc; + +use giterated_models::error::OperationError; +use giterated_stack::{AnyObject, AnyValue, GiteratedStack, StackOperationState}; +use tracing::trace; + +use crate::{CacheKey, CacheSubstack}; + +pub async fn get_cached( + object: AnyObject, + value_kind: String, + cache: CacheSubstack, + _operation_state: StackOperationState, + stack: Arc, +) -> Result> { + let object_meta = stack + .metadata + .objects + .get(object.kind()) + .ok_or_else(|| OperationError::Unhandled)?; + let object_str = (object_meta.to_str)(object.clone()); + let cache_key = CacheKey { + object: object_str, + value_name: value_kind.clone(), + }; + + trace!("Check cache for {}::{}", object.kind(), value_kind); + + if let Some(cached_value) = cache.cache.get(&cache_key).await { + trace!("Found cached for {}::{}", object.kind(), value_kind); + + Ok(cached_value.clone()) + } else { + trace!("Nothing cached for {}::{}", object.kind(), value_kind); + Err(OperationError::Unhandled) + } +} diff --git a/giterated-cache/src/cache_update.rs b/giterated-cache/src/cache_update.rs index 479b50c..819098a 100644 --- a/giterated-cache/src/cache_update.rs +++ b/giterated-cache/src/cache_update.rs @@ -1,348 +1,42 @@ -// use std::{any::Any, pin::Pin, process::Output, sync::Arc}; - -// use futures_util::{future::LocalBoxFuture, Future, FutureExt}; -// use giterated_models::{ -// error::{ExtractorError, OperationError, RepositoryError}, -// object::GiteratedObject, -// operation::GiteratedOperation, -// repository::{Repository, RepositoryBranch, RepositoryBranchesRequest}, -// settings::SetSetting, -// user::{DisplayName, User}, -// value::{GetValue, GiteratedObjectValue}, -// }; -// use giterated_stack::{ -// AuthorizedUser, FromOperationState, GiteratedStack, MissingValue, StackOperationState, -// }; - -// use crate::CacheSubstack; - -// async fn value_update( -// object: AnyObject<'_>, -// value: AnyValue<'_>, -// cache: CacheSubstack, -// stack: Arc, -// ) -> Result<(), anyhow::Error> { -// todo!() -// } - -// pub struct AnyObject<'o>(&'o (dyn Any + Send + Sync)); - -// pub struct AnyValue<'v>(&'v (dyn Any + Send + Sync)); - -// #[async_trait::async_trait(?Send)] -// pub trait GiteratedHandler -// { -// async fn handle( -// &self, -// parameters: RequiredParameters, -// additional_parameters: AdditionalParameters, -// state: Arc, -// operation_state: &OperationState, -// ) -> Output; -// } - -// #[async_trait::async_trait(?Send)] -// impl GiteratedHandler<(R1,), (), S, O, Output> for F -// where -// F: FnMut(R1, S, &O) -> Fut, -// Fut: Future, -// S: 'static, -// R1: 'static, -// { -// async fn handle( -// &self, -// parameters: (R1,), -// additional_parameters: (), -// state: Arc, -// operation_state: &O, -// ) -> Output { -// todo!() -// } -// } - -// #[async_trait::async_trait(?Send)] -// impl GiteratedHandler<(R1,), (A1,), S, O, Output> for F -// where -// F: FnMut(R1, S, &O, A1) -> Fut, -// Fut: Future, -// S: 'static, -// R1: 'static, -// A1: 'static + HandlerResolvable<(R1,), O, A1>, -// { -// async fn handle( -// &self, -// parameters: (R1,), -// additional_parameters: (A1,), -// state: Arc, -// operation_state: &O, -// ) -> Output { -// todo!() -// } -// } - -// #[async_trait::async_trait(?Send)] -// impl GiteratedHandler<(R1,), (A1, A2), S, O, Output> for F -// where -// F: FnMut(R1, S, &O, A1, A2) -> Fut, -// Fut: Future, -// S: 'static, -// R1: 'static, -// A1: 'static + HandlerResolvable<(R1,), O, A1>, -// A2: 'static + HandlerResolvable<(R1,), O, A2>, -// { -// async fn handle( -// &self, -// parameters: (R1,), -// additional_parameters: (A1, A2), -// state: Arc, -// operation_state: &O, -// ) -> Output { -// todo!() -// } -// } - -// #[async_trait::async_trait(?Send)] -// impl GiteratedHandler<(R1,), (A1, A2, A3), S, O, Output> for F -// where -// F: FnMut(R1, S, &O, A1, A2, A3) -> Fut, -// Fut: Future, -// S: 'static, -// R1: 'static, -// A1: 'static + HandlerResolvable<(R1,), O, A1>, -// A2: 'static + HandlerResolvable<(R1,), O, A2>, -// A3: 'static + HandlerResolvable<(R1,), O, A3>, -// { -// async fn handle( -// &self, -// parameters: (R1,), -// additional_parameters: (A1, A2, A3), -// state: Arc, -// operation_state: &O, -// ) -> Output { -// todo!() -// } -// } - -// #[async_trait::async_trait(?Send)] -// impl GiteratedHandler<(R1, R2), (), S, O, Output> for F -// where -// F: FnMut(R1, R2, S, &O) -> Fut, -// Fut: Future, -// S: 'static, -// R1: 'static, -// R2: 'static, -// { -// async fn handle( -// &self, -// parameters: (R1, R2), -// additional_parameters: (), -// state: Arc, -// operation_state: &O, -// ) -> Output { -// todo!() -// } -// } - -// #[async_trait::async_trait(?Send)] -// impl GiteratedHandler<(R1, R2), (A1,), S, O, Output> for F -// where -// F: FnMut(R1, R2, S, &O, A1) -> Fut, -// Fut: Future, -// S: 'static, -// R1: 'static, -// R2: 'static, -// A1: 'static + HandlerResolvable<(R1, R2), O, A1>, -// { -// async fn handle( -// &self, -// parameters: (R1, R2), -// additional_parameters: (A1,), -// state: Arc, -// operation_state: &O, -// ) -> Output { -// todo!() -// } -// } - -// #[async_trait::async_trait(?Send)] -// impl GiteratedHandler<(R1, R2), (A1, A2), S, O, Output> for F -// where -// F: FnMut(R1, R2, S, &O, A1, A2) -> Fut, -// Fut: Future, -// S: 'static, -// R1: 'static, -// R2: 'static, -// A1: 'static + HandlerResolvable<(R1, R2), O, A1>, -// A2: 'static + HandlerResolvable<(R1, R2), O, A2>, -// { -// async fn handle( -// &self, -// parameters: (R1, R2), -// additional_parameters: (A1, A2), -// state: Arc, -// operation_state: &O, -// ) -> Output { -// todo!() -// } -// } - -// #[async_trait::async_trait(?Send)] -// impl -// GiteratedHandler<(R1, R2), (A1, A2, A3), S, O, Output> for F -// where -// F: FnMut(R1, R2, S, &O, A1, A2, A3) -> Fut, -// Fut: Future, -// S: 'static, -// R1: 'static, -// R2: 'static, -// A1: 'static + HandlerResolvable<(R1, R2), O, A1>, -// A2: 'static + HandlerResolvable<(R1, R2), O, A2>, -// A3: 'static + HandlerResolvable<(R1, R2), O, A3>, -// { -// async fn handle( -// &self, -// parameters: (R1, R2), -// additional_parameters: (A1, A2, A3), -// state: Arc, -// operation_state: &O, -// ) -> Output { -// todo!() -// } -// } - -// #[async_trait::async_trait(?Send)] -// impl GiteratedHandler<(R1, R2, R3), (), S, O, Output> for F -// where -// F: FnMut(R1, R2, R3, S, &O) -> Fut, -// Fut: Future, -// S: 'static, -// R1: 'static, -// R2: 'static, -// R3: 'static, -// { -// async fn handle( -// &self, -// parameters: (R1, R2, R3), -// additional_parameters: (), -// state: Arc, -// operation_state: &O, -// ) -> Output { -// todo!() -// } -// } - -// fn test_fn(handler: F) -// where -// F: GiteratedHandler<(O, V), A, S, StackOperationState, Result<(), anyhow::Error>>, -// O: GiteratedObject, -// V: GiteratedObjectValue, -// { -// } - -// fn other_fn() { -// let a = String::from("a"); -// let test = move |object: User, -// value: GetValue, -// state: (), -// operation_state: &StackOperationState, -// authorized_user: AuthorizedUser| { async move { () } }; - -// let wrapper = HandlerWrapper::<(User, GetValue), _>::new((), test); -// } - -// pub struct HandlerWrapper { -// func: Box LocalBoxFuture<'static, O>>, -// state: Arc, -// } - -// impl HandlerWrapper { -// pub fn new(state: S, handler: F) -> Self -// where -// F: GiteratedHandler, -// S: Send + Sync + 'static, -// A: HandlerResolvableGroup

, -// { -// let state = Arc::new(state); - -// let func = |required: P, operation_state: StackOperationState| { -// // async move { handler.handle(required, (), state, &operation_state) }.boxed_local() -// todo!() -// }; - -// Self { -// func: Box::new(func), -// state, -// } -// } -// } - -// #[async_trait::async_trait(?Send)] -// pub trait HandlerResolvable { -// async fn from_handler_state( -// required_parameters: &RequiredParameters, -// operation_state: &OperationState, -// ) -> Output; -// } - -// #[async_trait::async_trait(?Send)] -// impl HandlerResolvable<(User, GetValue), StackOperationState, Self> for Arc { -// async fn from_handler_state( -// required_parameters: &(User, GetValue), -// operation_state: &StackOperationState, -// ) -> Self { -// todo!() -// } -// } - -// // #[async_trait::async_trait(?Send)] -// // impl HandlerResolvable<(O, D), StackOperationState, T> for T -// // where -// // O: GiteratedObject, -// // D: GiteratedOperation, -// // T: FromOperationState, -// // { -// // async fn from_handler_state( -// // required_parameters: &(O, D), -// // operation_state: &StackOperationState, -// // ) -> T { -// // todo!() -// // } -// // } - -// #[async_trait::async_trait(?Send)] -// pub trait HandlerResolvableGroup { -// async fn group_from_handler_state( -// required_parameters: &RequiredParameters, -// operation_state: &StackOperationState, -// ) -> Self; -// } - -// #[async_trait::async_trait(?Send)] -// impl HandlerResolvableGroup for (A1,) -// where -// A1: HandlerResolvable, -// { -// async fn group_from_handler_state( -// required_parameters: &RequiredParameters, -// operation_state: &StackOperationState, -// ) -> (A1,) { -// (A1::from_handler_state(required_parameters, operation_state).await,) -// } -// } - -// #[async_trait::async_trait(?Send)] -// impl HandlerResolvableGroup for (A1, A2) -// where -// A1: HandlerResolvable, -// A2: HandlerResolvable, -// { -// async fn group_from_handler_state( -// required_parameters: &RequiredParameters, -// operation_state: &StackOperationState, -// ) -> (A1, A2) { -// ( -// A1::from_handler_state(required_parameters, operation_state).await, -// A2::from_handler_state(required_parameters, operation_state).await, -// ) -// } -// } +use std::sync::Arc; + +use giterated_models::error::OperationError; +use giterated_stack::{AnyObject, AnyValue, GiteratedStack, StackOperationState}; +use tracing::trace; + +use crate::{CacheKey, CacheSubstack}; + +pub async fn cache_updated( + object: AnyObject, + value: AnyValue, + state: CacheSubstack, + _operation_state: StackOperationState, + stack: Arc, +) -> Result<(), OperationError> { + let object_meta = stack + .metadata + .objects + .get(object.kind()) + .ok_or_else(|| OperationError::Unhandled)?; + let object_str = (object_meta.to_str)(object.clone()); + let cache_key = CacheKey { + object: object_str, + value_name: value.kind().value_kind.to_string(), + }; + + let value_kind = value.kind().value_kind; + trace!( + "Beginning cache update for {}::{}", + object.kind(), + value_kind + ); + + state.cache.insert(cache_key, value).await; + + trace!( + "Completed cache update for {}::{}", + object.kind(), + value_kind + ); + Ok(()) +} diff --git a/giterated-cache/src/lib.rs b/giterated-cache/src/lib.rs index 28a558b..43cb5aa 100644 --- a/giterated-cache/src/lib.rs +++ b/giterated-cache/src/lib.rs @@ -1,25 +1,42 @@ -// pub mod cache_get; -// pub mod cache_update; +use cache_get::get_cached; +use giterated_stack::{AnyValue, SubstackBuilder}; +use moka::future::Cache; + +use crate::cache_update::cache_updated; + +pub mod cache_get; +pub mod cache_update; // use giterated_stack::{ObjectValuePair, SubstackBuilder}; // use moka::future::Cache; // use serde_json::Value; -// #[derive(Clone)] -// pub struct CacheSubstack { -// cache: Cache, -// } - -// impl Default for CacheSubstack { -// fn default() -> Self { -// Self { -// cache: Cache::new(20_000), -// } -// } -// } - -// impl CacheSubstack { -// pub fn into_substack(self) -> SubstackBuilder { -// todo!() -// } -// } +#[derive(Hash, PartialEq, Eq)] +pub struct CacheKey { + object: String, + value_name: String, +} + +#[derive(Clone)] +pub struct CacheSubstack { + cache: Cache, +} + +impl Default for CacheSubstack { + fn default() -> Self { + Self { + cache: Cache::new(20_000), + } + } +} + +impl CacheSubstack { + pub fn into_substack(self) -> SubstackBuilder { + let mut stack = SubstackBuilder::new(self); + + stack.value_change(cache_updated); + stack.dynamic_value(get_cached); + + stack + } +} diff --git a/giterated-daemon/Cargo.toml b/giterated-daemon/Cargo.toml index 252ec3b..deb447d 100644 --- a/giterated-daemon/Cargo.toml +++ b/giterated-daemon/Cargo.toml @@ -32,6 +32,7 @@ semver = {version = "1.0", features = ["serde"]} giterated-models = { path = "../giterated-models" } giterated-api = { path = "../../giterated-api" } giterated-stack = { path = "../giterated-stack" } +giterated-cache = { path = "../giterated-cache" } deadpool = "0.9" bincode = "1.3" tokio-util = {version = "0.7", features = ["rt"]} diff --git a/giterated-daemon/src/database_backend/mod.rs b/giterated-daemon/src/database_backend/mod.rs index cb10d7e..a07a8de 100644 --- a/giterated-daemon/src/database_backend/mod.rs +++ b/giterated-daemon/src/database_backend/mod.rs @@ -25,7 +25,7 @@ use self::handler::{ instance_registration_request, repository_commit_before, repository_commit_by_id, repository_diff, repository_diff_patch, repository_file_from_id, repository_file_from_path, repository_get_branches, repository_get_statistics, repository_info, - repository_last_commit_of_file, repository_latest_commit, user_get_repositories, + repository_last_commit_of_file, user_get_repositories, }; /// A backend implementation which attempts to resolve data from the instance's database. @@ -75,7 +75,7 @@ impl DatabaseBackend { .value_setting::() .value_setting::(); - builder.value(repository_latest_commit); + // builder.value(repository_latest_commit); builder .operation(user_get_repositories) @@ -116,13 +116,13 @@ impl MetadataProvider for DatabaseBackend { setting: AnySetting, setting_meta: &SettingMeta, ) -> Result<(), anyhow::Error> { - if let Some(repository) = object.0.downcast_ref::() { + if let Some(repository) = object.downcast_ref::() { sqlx::query!("INSERT INTO repository_settings VALUES ($1, $2, $3) ON CONFLICT (repository, name) DO UPDATE SET value = $3", repository.to_string(), setting_meta.name, serde_json::to_string(&(setting_meta.serialize)(setting).unwrap())?) .execute(&self.pool).await?; Ok(()) - } else if let Some(user) = object.0.downcast_ref::() { + } else if let Some(user) = object.downcast_ref::() { sqlx::query!("INSERT INTO user_settings VALUES ($1, $2, $3) ON CONFLICT (username, name) DO UPDATE SET value = $3", user.username, setting_meta.name, serde_json::to_string(&(setting_meta.serialize)(setting).unwrap())?) .execute(&self.pool).await?; @@ -139,7 +139,7 @@ impl MetadataProvider for DatabaseBackend { _object_meta: &ObjectMeta, setting_meta: &SettingMeta, ) -> Result { - if let Some(repository) = object.0.downcast_ref::() { + if let Some(repository) = object.downcast_ref::() { let row = sqlx::query_as!( RepositorySettingRow, "SELECT * FROM repository_settings WHERE repository = $1 AND name = $2", @@ -153,7 +153,7 @@ impl MetadataProvider for DatabaseBackend { serde_json::from_str(&row.value).context("deserializing setting from database")?; Ok(setting) - } else if let Some(user) = object.0.downcast_ref::() { + } else if let Some(user) = object.downcast_ref::() { info!("User for {}", setting_meta.name); let row = sqlx::query_as!( UserSettingRow, diff --git a/giterated-daemon/src/main.rs b/giterated-daemon/src/main.rs index 78cecad..321bbf7 100644 --- a/giterated-daemon/src/main.rs +++ b/giterated-daemon/src/main.rs @@ -1,5 +1,6 @@ use anyhow::Error; use connection::{Connections, RawConnection}; +use giterated_cache::CacheSubstack; use giterated_daemon::{ authentication::AuthenticationTokenGranter, backend::{ @@ -100,6 +101,9 @@ async fn main() -> Result<(), Error> { let database_backend = database_backend.into_substack(); runtime.merge_builder(database_backend); + let cache_backend = CacheSubstack::default(); + runtime.merge_builder(cache_backend.into_substack()); + let runtime = Arc::new(runtime); stack_cell diff --git a/giterated-models/src/settings/operations.rs b/giterated-models/src/settings/operations.rs index 853f031..0ab701f 100644 --- a/giterated-models/src/settings/operations.rs +++ b/giterated-models/src/settings/operations.rs @@ -42,5 +42,5 @@ impl GiteratedOperation for SetSetting { #[derive(Error, Debug, Serialize, Deserialize, Clone)] pub enum SetSettingError { #[error("Invalid setting `{0}` on object `{0}`")] - InvalidSetting(String, String) + InvalidSetting(String, String), } diff --git a/giterated-stack/src/lib.rs b/giterated-stack/src/lib.rs index 523ef00..7e5c4b3 100644 --- a/giterated-stack/src/lib.rs +++ b/giterated-stack/src/lib.rs @@ -29,7 +29,7 @@ use giterated_models::{ value::{GetValue, GiteratedObjectValue}, }; -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] pub struct ObjectOperationPair<'a> { pub object_name: &'a str, pub operation_name: &'a str, @@ -45,7 +45,7 @@ impl ObjectOperationPair<'static> { } } -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] pub struct ObjectValuePair<'a> { pub object_kind: &'a str, pub value_kind: &'a str, @@ -60,7 +60,7 @@ impl ObjectValuePair<'static> { } } -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] pub struct ObjectSettingPair<'a> { pub object_kind: &'a str, pub setting_name: &'a str, @@ -452,19 +452,213 @@ where } #[derive(Clone)] -pub struct AnyObject(pub Arc); +pub struct AnyObject { + inner: Arc, + kind: &'static str, +} + +impl AnyObject { + pub fn new(object: O) -> Self { + Self { + inner: Arc::new(object) as _, + kind: O::object_name(), + } + } + + pub fn new_raw(_object: Arc, _kind: &'static str) -> Self { + todo!() + } + + pub fn kind(&self) -> &'static str { + self.kind + } +} + +impl Deref for AnyObject { + type Target = dyn Any + Send + Sync; + + fn deref(&self) -> &Self::Target { + self.inner.as_ref() + } +} #[derive(Clone)] -pub struct AnyOperation(pub Arc); +pub struct AnyOperation { + inner: Arc, + kind: ObjectOperationPair<'static>, +} + +impl AnyOperation { + pub fn new + 'static>(operation: D) -> Self { + Self { + inner: Arc::new(operation) as _, + kind: ObjectOperationPair::from_types::(), + } + } + + pub fn new_raw( + _operation: Arc, + _kind: ObjectOperationPair<'static>, + ) -> Self { + todo!() + } + + pub fn kind(&self) -> ObjectOperationPair<'static> { + self.kind + } +} + +impl Deref for AnyOperation { + type Target = dyn Any + Send + Sync; + + fn deref(&self) -> &Self::Target { + self.inner.as_ref() + } +} #[derive(Clone)] -pub struct AnySuccess(pub Arc); +pub struct AnyValue { + inner: Arc, + kind: ObjectValuePair<'static>, +} + +impl AnyValue { + pub fn new + 'static>( + value: V, + ) -> Self { + Self { + inner: Arc::new(value) as _, + kind: ObjectValuePair::from_types::(), + } + } + + pub fn new_raw(_value: Arc, _kind: ObjectValuePair<'static>) -> Self { + todo!() + } + + pub fn kind(&self) -> ObjectValuePair<'static> { + self.kind + } +} + +impl Deref for AnyValue { + type Target = dyn Any + Send + Sync; + + fn deref(&self) -> &Self::Target { + self.inner.as_ref() + } +} #[derive(Clone)] -pub struct AnyFailure(pub Arc); +pub struct AnySetting { + inner: Arc, + kind: ObjectSettingPair<'static>, +} + +impl AnySetting { + pub fn new(setting: S) -> Self { + Self { + inner: Arc::new(setting) as _, + kind: ObjectSettingPair::from_types::(), + } + } + + pub fn new_raw( + _setting: Arc, + _kind: ObjectSettingPair<'static>, + ) -> Self { + todo!() + } + + pub fn kind(&self) -> ObjectSettingPair<'static> { + self.kind + } +} + +impl Deref for AnySetting { + type Target = dyn Any + Send + Sync; + + fn deref(&self) -> &Self::Target { + self.inner.as_ref() + } +} #[derive(Clone)] -pub struct AnyValue(pub Arc); +pub struct AnySuccess(pub Arc); #[derive(Clone)] -pub struct AnySetting(pub Arc); +pub struct AnyFailure(pub Arc); + +/// Should be renamed. +/// +/// Allows accepting object types that are either GiteratedObject types or +/// AnyObject. +pub trait MaybeDynamicObject: Clone { + fn from_any(object: &AnyObject) -> Self; + + fn object_name() -> &'static str; +} + +impl MaybeDynamicObject for O { + fn from_any(_object: &AnyObject) -> Self { + todo!() + } + + fn object_name() -> &'static str { + ::object_name() + } +} + +impl MaybeDynamicObject for AnyObject { + fn from_any(object: &AnyObject) -> Self { + object.clone() + } + + fn object_name() -> &'static str { + "any" + } +} + +pub trait MaybeDynamicValue { + fn from_any(value: &AnyValue) -> Self; + fn into_any(self) -> AnyValue; + fn meta() -> Option; + + fn value_name() -> &'static str; +} + +impl MaybeDynamicValue for V { + fn from_any(_object: &AnyValue) -> Self { + todo!() + } + + fn value_name() -> &'static str { + todo!() + } + + fn into_any(self) -> AnyValue { + todo!() + } + + fn meta() -> Option { + todo!() + } +} + +impl MaybeDynamicValue for AnyValue { + fn value_name() -> &'static str { + "any" + } + + fn from_any(value: &AnyValue) -> Self { + value.clone() + } + + fn into_any(self) -> AnyValue { + self + } + + fn meta() -> Option { + todo!() + } +} diff --git a/giterated-stack/src/meta/mod.rs b/giterated-stack/src/meta/mod.rs index 516f789..a9033fa 100644 --- a/giterated-stack/src/meta/mod.rs +++ b/giterated-stack/src/meta/mod.rs @@ -141,11 +141,11 @@ impl + 'static> IntoValu } fn deserialize(buffer: &[u8]) -> Result { - Ok(AnyValue(Arc::new(serde_json::from_slice(buffer)?))) + Ok(AnyValue::new(serde_json::from_slice::(buffer)?)) } fn serialize(value: AnyValue) -> Result, serde_json::Error> { - let value = value.0.downcast_ref::().unwrap(); + let value = value.downcast_ref::().unwrap(); serde_json::to_vec(&*value) } @@ -157,7 +157,7 @@ impl + 'static> IntoValu } fn is_get_value_typed(typed_get_value: AnyOperation) -> bool { - typed_get_value.0.is::>() + typed_get_value.is::>() } } @@ -202,9 +202,7 @@ where } fn deserialize(buffer: &[u8]) -> Result { - Ok(AnyOperation( - Arc::new(serde_json::from_slice::(buffer)?) as Arc - )) + Ok(AnyOperation::new(serde_json::from_slice::(buffer)?)) } fn serialize_success(success: AnySuccess) -> Result, serde_json::Error> { @@ -237,6 +235,7 @@ impl OperationMeta { pub struct ObjectMeta { pub name: String, + pub to_str: Box String + Send + Sync>, pub from_str: Box Result + Send + Sync>, pub any_is_same: fn(&dyn Any) -> bool, } @@ -257,13 +256,18 @@ impl IntoObjectMeta for O { } impl ObjectMeta { - pub fn new() -> Self { + pub fn new() -> Self { Self { name: I::name(), from_str: Box::new(|source| { let object = I::from_str(source).map_err(|_| ())?; - Ok(AnyObject(Arc::new(object) as Arc)) + Ok(AnyObject::new(object)) + }), + to_str: Box::new(|source| { + let object: &I = source.downcast_ref().unwrap(); + + object.to_string() }), any_is_same: I::any_is_same, } @@ -300,11 +304,11 @@ impl IntoSettingMeta } fn deserialize(value: Value) -> Result { - Ok(AnySetting(Arc::new(serde_json::from_value::(value)?))) + Ok(AnySetting::new::(serde_json::from_value::(value)?)) } fn serialize(setting: AnySetting) -> Result { - serde_json::to_value(setting.0.downcast_ref::().unwrap()) + serde_json::to_value(setting.downcast_ref::().unwrap()) } fn setting_updated( @@ -316,8 +320,8 @@ impl IntoSettingMeta async move { stack .setting_update( - object.0.downcast_ref::().unwrap().clone(), - setting.0.downcast_ref::().unwrap().clone(), + object.downcast_ref::().unwrap().clone(), + setting.downcast_ref::().unwrap().clone(), operation_state, ) .await diff --git a/giterated-stack/src/stack.rs b/giterated-stack/src/stack.rs index f0d7323..ee4d440 100644 --- a/giterated-stack/src/stack.rs +++ b/giterated-stack/src/stack.rs @@ -1,6 +1,7 @@ use std::any::Any; use std::fmt::Debug; +use std::ops::Deref; use std::{collections::HashMap, sync::Arc}; use giterated_models::authenticated::AuthenticatedPayload; @@ -8,7 +9,7 @@ use giterated_models::error::{GetValueError, IntoInternalError}; use giterated_models::message::GiteratedMessage; use giterated_models::object::NetworkAnyObject; use giterated_models::operation::NetworkAnyOperation; -use giterated_models::settings::{GetSettingError, Setting, SetSettingError}; +use giterated_models::settings::{GetSettingError, SetSettingError, Setting}; use giterated_models::value::{GetValue, GiteratedObjectValue}; use giterated_models::{ error::OperationError, @@ -17,8 +18,8 @@ use giterated_models::{ operation::GiteratedOperation, settings::{GetSetting, SetSetting}, }; -use serde_json::Value; -use tracing::{info, trace}; + +use tracing::{trace, warn}; use crate::handler::HandlerTree; use crate::provider::MetadataProvider; @@ -30,7 +31,7 @@ use crate::{ pub type OperationHandler = HandlerWrapper<(AnyObject, AnyOperation), AnySuccess, AnyFailure>; -pub type ValueGetter = HandlerWrapper<(AnyObject,), AnyValue, AnyFailure>; +pub type ValueGetter = HandlerWrapper<(AnyObject, String), AnyValue, AnyFailure>; pub type SettingGetter = HandlerWrapper<(AnyObject,), AnySetting, AnyFailure>; @@ -102,13 +103,50 @@ impl GiteratedStack { trace!("value updated {}::{}", O::object_name(), V::value_name()); let target = ObjectValuePair::from_types::(); + let object = AnyObject::new(object); + let value = AnyValue::new(new_value); + + // First, resolve a handler for the exact object value pair if let Some(handler) = self.value_change.get(&target) { // TODO let _ = handler - .handle( - (AnyObject(Arc::new(object)), AnyValue(Arc::new(new_value))), - operation_state.clone(), - ) + .handle((object.clone(), value.clone()), operation_state.clone()) + .await; + } + + // We need to resolve for `any` object and `any` value combination + let target = ObjectValuePair { + object_kind: "any", + value_kind: V::value_name(), + }; + if let Some(handler) = self.value_change.get(&target) { + // TODO + let _ = handler + .handle((object.clone(), value.clone()), operation_state.clone()) + .await; + } + + let target = ObjectValuePair { + object_kind: O::object_name(), + value_kind: "any", + }; + if let Some(handler) = self.value_change.get(&target) { + // TODO + let _ = handler + .handle((object.clone(), value.clone()), operation_state.clone()) + .await; + } + + // Now resolve for both `any` + + let target = ObjectValuePair { + object_kind: "any", + value_kind: "any", + }; + if let Some(handler) = self.value_change.get(&target) { + // TODO + let _ = handler + .handle((object.clone(), value.clone()), operation_state.clone()) .await; } } @@ -128,10 +166,7 @@ impl GiteratedStack { if let Some(handler) = self.setting_change.get(&target) { let _ = handler .handle( - ( - AnyObject(Arc::new(object)), - AnySetting(Arc::new(new_setting)), - ), + (AnyObject::new(object), AnySetting::new::(new_setting)), operation_state.clone(), ) .await; @@ -171,9 +206,9 @@ impl GiteratedStack { let result = provider .write( - AnyObject(Arc::new(object.clone())), + AnyObject::new(object.clone()), object_meta, - AnySetting(Arc::new(setting)), + AnySetting::new::(setting), setting_meta, ) .await @@ -213,11 +248,7 @@ impl GiteratedStack { .ok_or_else(|| OperationError::Unhandled)?; let value = provider - .read( - AnyObject(Arc::new(object.clone())), - object_meta, - setting_meta, - ) + .read(AnyObject::new(object.clone()), object_meta, setting_meta) .await .as_internal_error_with_context(format!("getting setting {}", S::name()))?; @@ -367,7 +398,13 @@ impl GiteratedStack { setting_name: &operation.setting_name, }) // TODO: Check this - .ok_or(OperationError::Operation(serde_json::to_vec(&SetSettingError::InvalidSetting(operation.setting_name.clone(), object_type.clone())).as_internal_error()?))?; + .ok_or(OperationError::Operation( + serde_json::to_vec(&SetSettingError::InvalidSetting( + operation.setting_name.clone(), + object_type.clone(), + )) + .as_internal_error()?, + ))?; let setting = (setting_meta.deserialize)(operation.value) .as_internal_error_with_context(format!( @@ -382,7 +419,7 @@ impl GiteratedStack { ); for provider in self.metadata_providers.iter() { - if provider.provides_for(object.0.as_ref()) { + if provider.provides_for(object.deref()) { trace!( "Resolved setting provider for setting {} for object {}", operation.setting_name, @@ -506,45 +543,175 @@ impl GiteratedStack { ) -> Result, OperationError>> { trace!("Handling network get_value for {}", operation.value_name); - let value_meta = self - .metadata - .values - .get(&ObjectValuePair { - object_kind: &object_kind, - value_kind: &operation.value_name, - }) - .ok_or_else(|| OperationError::Unhandled)?; + // We first attempt generic handlers + if let Some(handler) = self.value_getters.get(&ObjectValuePair { + object_kind: "any", + value_kind: &operation.value_name, + }) { + match handler + .handle( + (object.clone(), operation.value_name.clone()), + operation_state.clone(), + ) + .await + { + Ok(success) => { + // Resolve the metadata to serialize + let value_meta = self + .metadata + .values + .get(&success.kind()) + .ok_or_else(|| OperationError::Unhandled)?; + + return Ok((value_meta.serialize)(success).as_internal_error()?); + } + Err(err) => { + match err { + OperationError::Operation(operation_error) => { + // This DOES result in an early return, because it was handled + let error: &GetValueError = operation_error.0.downcast_ref().unwrap(); + + return Err(OperationError::Operation( + serde_json::to_vec(&error).as_internal_error()?, + )); + } + OperationError::Internal(internal) => { + // This DOES NOT result in an early return + warn!("An internal error occurred during a failable handler operation. {:?}", internal); + } + OperationError::Unhandled => { + // This DOES NOT result in an early return + } + } + } + } + } + if let Some(handler) = self.value_getters.get(&ObjectValuePair { + object_kind: &object_kind, + value_kind: "any", + }) { + match handler + .handle( + (object.clone(), operation.value_name.clone()), + operation_state.clone(), + ) + .await + { + Ok(success) => { + // Resolve the metadata to serialize + let value_meta = self + .metadata + .values + .get(&success.kind()) + .ok_or_else(|| OperationError::Unhandled)?; - for (target, getter) in self.value_getters.iter() { - if target.object_kind != object_kind { - continue; + return Ok((value_meta.serialize)(success).as_internal_error()?); + } + Err(err) => { + match err { + OperationError::Operation(operation_error) => { + // This DOES result in an early return, because it was handled + let error: &GetValueError = operation_error.0.downcast_ref().unwrap(); + + return Err(OperationError::Operation( + serde_json::to_vec(&error).as_internal_error()?, + )); + } + OperationError::Internal(internal) => { + // This DOES NOT result in an early return + warn!("An internal error occurred during a failable handler operation. {:?}", internal); + } + OperationError::Unhandled => { + // This DOES NOT result in an early return + } + } + } } + } + if let Some(handler) = self.value_getters.get(&ObjectValuePair { + object_kind: "any", + value_kind: "any", + }) { + match handler + .handle( + (object.clone(), operation.value_name.clone()), + operation_state.clone(), + ) + .await + { + Ok(success) => { + // Resolve the metadata to serialize + let value_meta = self + .metadata + .values + .get(&success.kind()) + .ok_or_else(|| OperationError::Unhandled)?; - if target.value_kind != operation.value_name { - continue; + return Ok((value_meta.serialize)(success).as_internal_error()?); + } + Err(err) => { + match err { + OperationError::Operation(operation_error) => { + // This DOES result in an early return, because it was handled + let error: &GetValueError = operation_error.0.downcast_ref().unwrap(); + + return Err(OperationError::Operation( + serde_json::to_vec(&error).as_internal_error()?, + )); + } + OperationError::Internal(internal) => { + // This DOES NOT result in an early return + warn!("An internal error occurred during a failable handler operation. {:?}", internal); + } + OperationError::Unhandled => { + // This DOES NOT result in an early return + } + } + } } + } - return match getter - .handle((object.clone(),), operation_state.clone()) + if let Some(handler) = self.value_getters.get(&ObjectValuePair { + object_kind: &object_kind, + value_kind: &operation.value_name, + }) { + match handler + .handle( + (object.clone(), operation.value_name.clone()), + operation_state.clone(), + ) .await { Ok(success) => { - // Serialize success, which is the value type itself - let serialized = (value_meta.serialize)(success).as_internal_error()?; + // Resolve the metadata to serialize + let value_meta = self + .metadata + .values + .get(&success.kind()) + .ok_or_else(|| OperationError::Unhandled)?; - Ok(serialized) + return Ok((value_meta.serialize)(success).as_internal_error()?); } - Err(err) => Err(match err { - OperationError::Operation(failure) => { - // Failure is sourced from GetValue operation, but this is hardcoded for now - let failure: &GetValueError = failure.0.downcast_ref().unwrap(); - - OperationError::Operation(serde_json::to_vec(&failure).as_internal_error()?) + Err(err) => { + match err { + OperationError::Operation(operation_error) => { + // This DOES result in an early return, because it was handled + let error: &GetValueError = operation_error.0.downcast_ref().unwrap(); + + return Err(OperationError::Operation( + serde_json::to_vec(&error).as_internal_error()?, + )); + } + OperationError::Internal(internal) => { + // This DOES NOT result in an early return + warn!("An internal error occurred during a failable handler operation. {:?}", internal); + } + OperationError::Unhandled => { + // This DOES NOT result in an early return + } } - OperationError::Internal(internal) => OperationError::Internal(internal), - OperationError::Unhandled => OperationError::Unhandled, - }), - }; + } + } } Err(OperationError::Unhandled) @@ -564,7 +731,7 @@ impl GiteratedStack { ); for provider in self.metadata_providers.iter() { - if provider.provides_for(object.0.as_ref()) { + if provider.provides_for(object.deref()) { let setting_meta = self .metadata .settings @@ -671,13 +838,12 @@ impl ObjectBackend for Arc { D::Failure: Clone, { // Erase object and operation types. - let object = AnyObject(Arc::new(in_object.clone()) as Arc); - let operation = AnyOperation(Arc::new(payload) as Arc); + let object = AnyObject::new(in_object.clone()); + let operation = AnyOperation::new(payload); // We need to hijack get_value, set_setting, and get_setting. if operation_name == "get_value" { let get_value = operation - .0 .downcast_ref::() .ok_or_else(|| OperationError::Unhandled)?; @@ -713,7 +879,10 @@ impl ObjectBackend for Arc { ); return match getter - .handle((object.clone(),), operation_state.clone()) + .handle( + (object.clone(), get_value.value_name.clone()), + operation_state.clone(), + ) .await { Ok(success) => Ok(*(Box::new((value_meta.serialize)(success).unwrap()) @@ -735,8 +904,8 @@ impl ObjectBackend for Arc { }), }; } - } else if operation.0.is::() { - let get_setting: &GetSetting = operation.0.downcast_ref().unwrap(); + } else if operation.is::() { + let get_setting: &GetSetting = operation.downcast_ref().unwrap(); let setting_name = get_setting.setting_name.clone(); let raw_result = self @@ -754,7 +923,7 @@ impl ObjectBackend for Arc { // let serialized = (setting_meta.serialize)(success).unwrap(); // Ok(serde_json::to_vec(&serialized).unwrap()) - Ok(success.0.downcast_ref::().unwrap().clone()) + Ok(success.downcast_ref::().unwrap().clone()) } Err(err) => Err(match err { OperationError::Operation(failure) => { @@ -771,9 +940,9 @@ impl ObjectBackend for Arc { OperationError::Unhandled => OperationError::Unhandled, }), }; - } else if operation.0.is::() { + } else if operation.is::() { todo!() - } else if operation.0.is::() { + } else if operation.is::() { todo!() } @@ -841,10 +1010,7 @@ impl ObjectBackend for Arc { for (_object_name, object_meta) in self.metadata.objects.iter() { if let Ok(object) = (object_meta.from_str)(object_str) { return Ok(unsafe { - Object::new_unchecked( - object.0.downcast_ref::().unwrap().clone(), - self.clone(), - ) + Object::new_unchecked(object.downcast_ref::().unwrap().clone(), self.clone()) }); } } diff --git a/giterated-stack/src/substack.rs b/giterated-stack/src/substack.rs index 6cfad65..6c15622 100644 --- a/giterated-stack/src/substack.rs +++ b/giterated-stack/src/substack.rs @@ -14,8 +14,9 @@ use tracing::{info, trace}; use crate::{ handler::HandlerWrapper, provider::MetadataProvider, AnyFailure, AnyObject, AnyOperation, AnySetting, AnySuccess, AnyValue, GiteratedStack, GiteratedStackState, IntoGiteratedHandler, - ObjectOperationPair, ObjectSettingPair, ObjectValuePair, OperationHandler, RuntimeMetadata, - SettingChange, SettingGetter, StackOperationState, ValueChange, ValueGetter, + MaybeDynamicObject, MaybeDynamicValue, ObjectOperationPair, ObjectSettingPair, ObjectValuePair, + OperationHandler, RuntimeMetadata, SettingChange, SettingGetter, StackOperationState, + ValueChange, ValueGetter, }; pub struct SubstackBuilder { @@ -75,8 +76,8 @@ impl SubstackBuilder { |(any_object, any_operation): &(AnyObject, AnyOperation), _state: &StackOperationState| { Ok(( - any_object.0.downcast_ref::().unwrap().clone(), - any_operation.0.downcast_ref::().unwrap().clone(), + any_object.downcast_ref::().unwrap().clone(), + any_operation.downcast_ref::().unwrap().clone(), )) }, ); @@ -172,8 +173,8 @@ impl SubstackBuilder { ); let object = object.clone(); async move { - let object = object.0.downcast_ref::().unwrap(); - let setting = setting.0.downcast_ref::().unwrap(); + let object = object.downcast_ref::().unwrap(); + let setting = setting.downcast_ref::().unwrap(); stack .value_update(object.clone(), setting.clone(), &operation_state) .await; @@ -187,6 +188,7 @@ impl SubstackBuilder { let wrapped = HandlerWrapper::new( self.state.clone(), |object: AnyObject, + _name: String, _state: _, _operation_state: StackOperationState, stack: Arc| { @@ -194,10 +196,10 @@ impl SubstackBuilder { let object = object.clone(); async move { match stack - .new_get_setting::(object.0.downcast_ref().unwrap()) + .new_get_setting::(object.downcast_ref().unwrap()) .await { - Ok(setting) => Ok(AnyValue(Arc::new(setting))), + Ok(setting) => Ok(AnyValue::new(setting)), Err(err) => { panic!("Error: {:?}", err); } @@ -219,30 +221,29 @@ impl SubstackBuilder { /// # Type Registration /// This will register the provided [`GiteratedObjectValue`] type for its matching / specified /// object type. It will **not** register the object type automatically. - pub fn value(&mut self, handler: F) -> &mut Self + pub fn dynamic_value(&mut self, handler: F) -> &mut Self where - O: GiteratedObject + 'static, - V: GiteratedObjectValue + 'static + Clone, - F: IntoGiteratedHandler<(O,), A, S, StackOperationState, Result>> - + Send + O: MaybeDynamicObject + 'static, + F: IntoGiteratedHandler< + (O, String), + A, + S, + StackOperationState, + Result>, + > + Send + Sync, - E: Into + 'static + std::fmt::Debug + Clone, F: 'static, { let wrapped = HandlerWrapper::new(self.state.clone(), handler); let wrapped = wrapped.map( - |(any_object,): &(AnyObject,), _state: &StackOperationState| { - Ok((any_object - .0 - .downcast_ref::() - .ok_or_else(|| OperationError::Internal(DowncastError.into()))? - .clone(),)) + |(any_object, name): &(AnyObject, String), _state: &StackOperationState| { + Ok((O::from_any(any_object), name.clone())) }, ); let wrapped = wrapped.map_return(|ret_val, _state| match ret_val { - Ok(success) => Ok(AnyValue(Arc::new(success))), + Ok(success) => Ok(success.into_any()), Err(err) => Err(match err { OperationError::Operation(failure) => OperationError::Internal(failure.into()), OperationError::Internal(err) => OperationError::Internal(err), @@ -252,17 +253,20 @@ impl SubstackBuilder { assert!(self .value_getters - .insert(ObjectValuePair::from_types::(), wrapped) + .insert( + ObjectValuePair { + object_kind: O::object_name(), + value_kind: "any" + }, + wrapped + ) .is_none()); - self.metadata.register_value::(); - self } pub fn value_change(&mut self, handler: F) -> &mut Self where - O: GiteratedObject + 'static, F: IntoGiteratedHandler< (O, V), A, @@ -271,8 +275,8 @@ impl SubstackBuilder { Result<(), OperationError>, > + Send + Sync, - V: GiteratedObjectValue + Clone + 'static, - O: 'static, + V: MaybeDynamicValue + Clone + 'static, + O: 'static + MaybeDynamicObject, V: 'static, F: 'static, { @@ -280,24 +284,19 @@ impl SubstackBuilder { let wrapped = wrapped.map( |(any_object, any_value): &(AnyObject, AnyValue), _state: &StackOperationState| { - Ok(( - any_object - .0 - .downcast_ref::() - .ok_or_else(|| OperationError::Internal(DowncastError.into()))? - .clone(), - any_value - .0 - .downcast_ref::() - .ok_or_else(|| OperationError::Internal(DowncastError.into()))? - .clone(), - )) + Ok((O::from_any(any_object), V::from_any(any_value))) }, ); assert!(self .value_change - .insert(ObjectValuePair::from_types::(), wrapped) + .insert( + ObjectValuePair { + object_kind: O::object_name(), + value_kind: V::value_name() + }, + wrapped + ) .is_none()); self