diff --git a/Cargo.lock b/Cargo.lock index 8b5bc9f..1d0524d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,33 +321,6 @@ dependencies = [ ] [[package]] -name = "color-eyre" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - -[[package]] name = "const-oid" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -475,18 +448,6 @@ dependencies = [ ] [[package]] -name = "deadpool" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb84100978c1c7b37f09ed3ce3e5f843af02c2a2c431bae5b19230dad2c1b490" -dependencies = [ - "async-trait", - "deadpool-runtime", - "num_cpus", - "tokio", -] - -[[package]] name = "deadpool-runtime" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -588,16 +549,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] -name = "eyre" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] name = "fastrand" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -787,31 +738,6 @@ dependencies = [ ] [[package]] -name = "giterated-api" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-trait", - "bincode", - "chrono", - "color-eyre", - "deadpool 0.10.0", - "futures-util", - "giterated-models", - "jsonwebtoken", - "rand", - "reqwest", - "semver", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-tungstenite", - "tracing", - "tracing-subscriber", -] - -[[package]] name = "giterated-cache" version = "0.1.0" dependencies = [ @@ -840,10 +766,9 @@ dependencies = [ "base64 0.21.4", "bincode", "chrono", - "deadpool 0.9.5", + "deadpool", "futures-util", "git2", - "giterated-api", "giterated-cache", "giterated-models", "giterated-protocol", @@ -896,7 +821,10 @@ name = "giterated-protocol" version = "0.1.0" dependencies = [ "giterated-stack", + "rand", + "rsa", "serde", + "serde_json", "tracing", ] @@ -1076,20 +1004,6 @@ dependencies = [ ] [[package]] -name = "hyper-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" -dependencies = [ - "futures-util", - "http", - "hyper", - "rustls", - "tokio", - "tokio-rustls", -] - -[[package]] name = "hyper-tls" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1136,12 +1050,6 @@ dependencies = [ ] [[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - -[[package]] name = "indexmap" version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1586,12 +1494,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] -name = "owo-colors" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" - -[[package]] name = "parking_lot" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1820,7 +1722,6 @@ dependencies = [ "http", "http-body", "hyper", - "hyper-rustls", "hyper-tls", "ipnet", "js-sys", @@ -1830,21 +1731,17 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "system-configuration", "tokio", "tokio-native-tls", - "tokio-rustls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", "winreg", ] @@ -1921,49 +1818,6 @@ dependencies = [ ] [[package]] -name = "rustls" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" -dependencies = [ - "log", - "ring", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-native-certs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" -dependencies = [ - "base64 0.21.4", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] name = "ryu" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1994,16 +1848,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "sct" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] name = "secrecy" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2638,16 +2482,6 @@ dependencies = [ ] [[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] name = "tokio-stream" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2666,10 +2500,7 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls", - "rustls-native-certs", "tokio", - "tokio-rustls", "tungstenite", ] @@ -2764,16 +2595,6 @@ dependencies = [ ] [[package]] -name = "tracing-error" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" -dependencies = [ - "tracing", - "tracing-subscriber", -] - -[[package]] name = "tracing-log" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2823,7 +2644,6 @@ dependencies = [ "httparse", "log", "rand", - "rustls", "sha1", "thiserror", "url", @@ -3041,12 +2861,6 @@ dependencies = [ ] [[package]] -name = "webpki-roots" -version = "0.25.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" - -[[package]] name = "whoami" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/giterated-cache/src/cache_get.rs b/giterated-cache/src/cache_get.rs index b212436..6fe0e47 100644 --- a/giterated-cache/src/cache_get.rs +++ b/giterated-cache/src/cache_get.rs @@ -15,10 +15,8 @@ // todo!() // } -use std::sync::Arc; - use giterated_models::error::OperationError; -use giterated_stack::{AnyObject, AnyValue, GiteratedStack, StackOperationState}; +use giterated_stack::{AnyObject, AnyValue, GiteratedStack}; use tracing::trace; use crate::{CacheKey, CacheSubstack}; @@ -27,8 +25,7 @@ pub async fn get_cached( object: AnyObject, value_kind: String, cache: CacheSubstack, - _operation_state: StackOperationState, - stack: Arc, + stack: GiteratedStack, ) -> Result> { let object_meta = stack .metadata diff --git a/giterated-cache/src/cache_update.rs b/giterated-cache/src/cache_update.rs index 819098a..b83a020 100644 --- a/giterated-cache/src/cache_update.rs +++ b/giterated-cache/src/cache_update.rs @@ -1,7 +1,5 @@ -use std::sync::Arc; - use giterated_models::error::OperationError; -use giterated_stack::{AnyObject, AnyValue, GiteratedStack, StackOperationState}; +use giterated_stack::{AnyObject, AnyValue, GiteratedStack}; use tracing::trace; use crate::{CacheKey, CacheSubstack}; @@ -10,8 +8,7 @@ pub async fn cache_updated( object: AnyObject, value: AnyValue, state: CacheSubstack, - _operation_state: StackOperationState, - stack: Arc, + stack: GiteratedStack, ) -> Result<(), OperationError> { let object_meta = stack .metadata diff --git a/giterated-cache/src/lib.rs b/giterated-cache/src/lib.rs index 43cb5aa..4d8eb2d 100644 --- a/giterated-cache/src/lib.rs +++ b/giterated-cache/src/lib.rs @@ -1,5 +1,5 @@ use cache_get::get_cached; -use giterated_stack::{AnyValue, SubstackBuilder}; +use giterated_stack::{AnyValue, StackOperationState, SubstackBuilder}; use moka::future::Cache; use crate::cache_update::cache_updated; @@ -31,7 +31,7 @@ impl Default for CacheSubstack { } impl CacheSubstack { - pub fn into_substack(self) -> SubstackBuilder { + pub fn into_substack(self) -> SubstackBuilder { let mut stack = SubstackBuilder::new(self); stack.value_change(cache_updated); diff --git a/giterated-daemon/Cargo.toml b/giterated-daemon/Cargo.toml index 84c55a3..c43a603 100644 --- a/giterated-daemon/Cargo.toml +++ b/giterated-daemon/Cargo.toml @@ -30,7 +30,6 @@ argon2 = "0.5" aes-gcm = "0.10" 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" } giterated-protocol = { path = "../giterated-protocol" } diff --git a/giterated-daemon/src/backend/git.rs b/giterated-daemon/src/backend/git.rs index 4eaa5ce..14450b1 100644 --- a/giterated-daemon/src/backend/git.rs +++ b/giterated-daemon/src/backend/git.rs @@ -153,7 +153,7 @@ pub struct GitBackend { pub pg_pool: PgPool, pub repository_folder: String, pub instance: Instance, - pub stack: Arc>>, + pub stack: Arc>, } impl GitBackend { @@ -161,7 +161,7 @@ impl GitBackend { pg_pool: &PgPool, repository_folder: &str, instance: impl ToOwned, - stack: Arc>>, + stack: Arc>, ) -> Self { let instance = instance.to_owned(); diff --git a/giterated-daemon/src/backend/settings.rs b/giterated-daemon/src/backend/settings.rs index 15acab0..037b82b 100644 --- a/giterated-daemon/src/backend/settings.rs +++ b/giterated-daemon/src/backend/settings.rs @@ -15,7 +15,7 @@ use super::MetadataBackend; pub struct DatabaseSettings { pub pg_pool: PgPool, - pub stack: Arc>>, + pub stack: Arc>, } #[async_trait::async_trait] diff --git a/giterated-daemon/src/client.rs b/giterated-daemon/src/client.rs index 1093c29..d206c22 100644 --- a/giterated-daemon/src/client.rs +++ b/giterated-daemon/src/client.rs @@ -1,13 +1,10 @@ -use std::sync::Arc; - use futures_util::{SinkExt, StreamExt}; use giterated_models::{ - authenticated::AuthenticatedPayload, error::{IntoInternalError, OperationError}, instance::Instance, object_backend::ObjectBackend, }; -use giterated_protocol::{NetworkedObject, NetworkedOperation}; +use giterated_protocol::{AuthenticatedPayload, NetworkedObject, NetworkedOperation}; use giterated_stack::{GiteratedStack, StackOperationState}; use tokio::net::TcpStream; use tokio_tungstenite::{tungstenite::Message, WebSocketStream}; @@ -15,7 +12,7 @@ use tokio_tungstenite::{tungstenite::Message, WebSocketStream}; pub async fn client_wrapper( our_instance: Instance, mut socket: WebSocketStream, - runtime: Arc, + runtime: GiteratedStack, ) { loop { let message = socket.next().await; @@ -88,7 +85,7 @@ pub async fn client_wrapper( pub async fn handle_client_message( payload: AuthenticatedPayload, operation_state: StackOperationState, - runtime: Arc, + runtime: GiteratedStack, ) -> Result, OperationError>> { let mut networked_object = runtime .get_object::(&payload.object, &operation_state) diff --git a/giterated-daemon/src/database_backend/handler.rs b/giterated-daemon/src/database_backend/handler.rs index 15f11e0..ac64e02 100644 --- a/giterated-daemon/src/database_backend/handler.rs +++ b/giterated-daemon/src/database_backend/handler.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use giterated_models::{ authenticated::UserAuthenticationToken, error::{InstanceError, IntoInternalError, OperationError, RepositoryError, UserError}, @@ -17,7 +15,7 @@ use giterated_models::{ }, user::{User, UserRepositoriesRequest}, }; -use giterated_stack::{AuthenticatedUser, GiteratedStack, StackOperationState}; +use giterated_stack::{AuthenticatedUser, GiteratedStack, OperationState, StackOperationState}; use super::DatabaseBackend; @@ -25,7 +23,7 @@ pub async fn user_get_repositories( object: User, _operation: UserRepositoriesRequest, state: DatabaseBackend, - _operation_state: StackOperationState, + OperationState(_operation_state): OperationState, requester: Option, ) -> Result, OperationError> { let object = object.clone(); @@ -57,8 +55,8 @@ pub async fn repository_info( object: Repository, operation: RepositoryInfoRequest, state: DatabaseBackend, - operation_state: StackOperationState, - backend: Arc, + OperationState(operation_state): OperationState, + backend: GiteratedStack, requester: Option, ) -> Result> { info!("Called"); @@ -118,8 +116,8 @@ pub async fn repository_get_statistics( object: Repository, operation: RepositoryStatisticsRequest, state: DatabaseBackend, - operation_state: StackOperationState, - backend: Arc, + OperationState(operation_state): OperationState, + backend: GiteratedStack, requester: Option, ) -> Result> { let object = backend @@ -147,8 +145,8 @@ pub async fn repository_get_branches( object: Repository, operation: RepositoryBranchesRequest, state: DatabaseBackend, - operation_state: StackOperationState, - backend: Arc, + OperationState(operation_state): OperationState, + backend: GiteratedStack, requester: Option, ) -> Result, OperationError> { let object = backend @@ -170,8 +168,8 @@ pub async fn repository_file_from_id( object: Repository, operation: RepositoryFileFromIdRequest, state: DatabaseBackend, - operation_state: StackOperationState, - backend: Arc, + OperationState(operation_state): OperationState, + backend: GiteratedStack, requester: Option, ) -> Result> { @@ -198,8 +196,8 @@ pub async fn repository_file_from_path( object: Repository, operation: RepositoryFileFromPathRequest, state: DatabaseBackend, - operation_state: StackOperationState, - backend: Arc, + OperationState(operation_state): OperationState, + backend: GiteratedStack, requester: Option, ) -> Result<(RepositoryFile, String), OperationError> { let object = backend @@ -228,8 +226,8 @@ pub async fn repository_last_commit_of_file( object: Repository, operation: RepositoryLastCommitOfFileRequest, state: DatabaseBackend, - operation_state: StackOperationState, - backend: Arc, + OperationState(operation_state): OperationState, + backend: GiteratedStack, requester: Option, ) -> Result> { let object = backend @@ -258,8 +256,8 @@ pub async fn repository_commit_by_id( object: Repository, operation: RepositoryCommitFromIdRequest, state: DatabaseBackend, - operation_state: StackOperationState, - backend: Arc, + OperationState(operation_state): OperationState, + backend: GiteratedStack, requester: Option, ) -> Result> { let object = backend @@ -285,8 +283,8 @@ pub async fn repository_diff( object: Repository, operation: RepositoryDiffRequest, state: DatabaseBackend, - operation_state: StackOperationState, - backend: Arc, + OperationState(operation_state): OperationState, + backend: GiteratedStack, requester: Option, ) -> Result> { let object = backend @@ -308,8 +306,8 @@ pub async fn repository_diff_patch( object: Repository, operation: RepositoryDiffPatchRequest, state: DatabaseBackend, - operation_state: StackOperationState, - backend: Arc, + OperationState(operation_state): OperationState, + backend: GiteratedStack, requester: Option, ) -> Result> { let object = backend @@ -331,8 +329,8 @@ pub async fn repository_commit_before( object: Repository, operation: RepositoryCommitBeforeRequest, state: DatabaseBackend, - operation_state: StackOperationState, - backend: Arc, + OperationState(operation_state): OperationState, + backend: GiteratedStack, requester: Option, ) -> Result> { let object = backend @@ -354,7 +352,7 @@ pub async fn instance_authentication_request( object: Instance, operation: AuthenticationTokenRequest, state: DatabaseBackend, - _operation_state: StackOperationState, + OperationState(_operation_state): OperationState, // Authorizes the request for SAME-INSTANCE // _authorized_instance: AuthorizedInstance, ) -> Result> { @@ -370,8 +368,8 @@ pub async fn instance_registration_request( _object: Instance, operation: RegisterAccountRequest, state: DatabaseBackend, - _operation_state: StackOperationState, // Authorizes the request for SAME-INSTANCE - // _authorized_instance: AuthorizedInstance, + OperationState(_operation_state): OperationState, // Authorizes the request for SAME-INSTANCE + // _authorized_instance: AuthorizedInstance, ) -> Result> { let mut backend = state.user_backend.lock().await; @@ -385,7 +383,7 @@ pub async fn instance_create_repository_request( _object: Instance, operation: RepositoryCreateRequest, state: DatabaseBackend, - _operation_state: StackOperationState, + OperationState(_operation_state): OperationState, requester: AuthenticatedUser, // Authorizes the request for SAME-INSTANCE // _authorized_instance: AuthorizedInstance, @@ -401,7 +399,7 @@ pub async fn instance_create_repository_request( pub async fn repository_latest_commit( _repository: Repository, _state: DatabaseBackend, - _operation_state: StackOperationState, + OperationState(_operation_state): OperationState, ) -> Result> { Ok(LatestCommit(None)) } diff --git a/giterated-daemon/src/database_backend/mod.rs b/giterated-daemon/src/database_backend/mod.rs index a07a8de..44b6f05 100644 --- a/giterated-daemon/src/database_backend/mod.rs +++ b/giterated-daemon/src/database_backend/mod.rs @@ -10,8 +10,8 @@ use giterated_models::instance::Instance; use giterated_models::repository::{DefaultBranch, Description, Repository, Visibility}; use giterated_models::user::{Bio, DisplayName, User}; use giterated_stack::provider::MetadataProvider; -use giterated_stack::SettingMeta; use giterated_stack::{AnyObject, AnySetting, GiteratedStack, ObjectMeta, SubstackBuilder}; +use giterated_stack::{SettingMeta, StackOperationState}; use serde_json::Value; use sqlx::PgPool; use std::fmt::Debug; @@ -36,7 +36,7 @@ pub struct DatabaseBackend { pub(self) pool: PgPool, pub(self) user_backend: Arc>, pub(self) repository_backend: Arc>, - pub stack: Arc>>, + pub stack: Arc>, } impl DatabaseBackend { @@ -45,7 +45,7 @@ impl DatabaseBackend { user_backend: Arc>, repository_backend: Arc>, pool: PgPool, - stack: Arc>>, + stack: Arc>, ) -> Self { Self { our_instance: instance, @@ -56,8 +56,8 @@ impl DatabaseBackend { } } - pub fn into_substack(self) -> SubstackBuilder { - let mut builder = SubstackBuilder::::new(self.clone()); + pub fn into_substack(self) -> SubstackBuilder { + let mut builder = SubstackBuilder::::new(self.clone()); builder.object_metadata_provider(Box::new(self)); diff --git a/giterated-daemon/src/main.rs b/giterated-daemon/src/main.rs index 62d7262..a65f070 100644 --- a/giterated-daemon/src/main.rs +++ b/giterated-daemon/src/main.rs @@ -11,7 +11,7 @@ use giterated_daemon::{ use giterated_models::instance::Instance; -use giterated_stack::GiteratedStack; +use giterated_stack::GiteratedStackBuilder; use sqlx::{postgres::PgConnectOptions, ConnectOptions, PgPool}; use std::{net::SocketAddr, str::FromStr, sync::Arc}; use tokio::{ @@ -92,7 +92,7 @@ async fn main() -> Result<(), Error> { stack_cell.clone(), ); - let mut runtime = GiteratedStack::default(); + let mut runtime = GiteratedStackBuilder::default(); let database_backend = database_backend.into_substack(); runtime.merge_builder(database_backend); @@ -100,7 +100,7 @@ async fn main() -> Result<(), Error> { let cache_backend = CacheSubstack::default(); runtime.merge_builder(cache_backend.into_substack()); - let runtime = Arc::new(runtime); + let runtime = runtime.finish(); stack_cell .set(runtime.clone()) diff --git a/giterated-models/src/authenticated.rs b/giterated-models/src/authenticated.rs index 7510d03..4a10a85 100644 --- a/giterated-models/src/authenticated.rs +++ b/giterated-models/src/authenticated.rs @@ -1,152 +1,6 @@ -use std::{fmt::Debug, sync::Arc}; - -use rsa::{ - pkcs1::DecodeRsaPrivateKey, - pss::SigningKey, - sha2::Sha256, - signature::{RandomizedSigner, SignatureEncoding}, - RsaPrivateKey, -}; use serde::{Deserialize, Serialize}; -use crate::{ - instance::Instance, - message::GiteratedMessage, - object::{GiteratedObject, NetworkAnyObject}, - operation::{GiteratedOperation, NetworkAnyOperation}, - user::User, -}; - -#[derive(Debug, Serialize, Deserialize)] -pub struct UserTokenMetadata { - pub user: User, - pub generated_for: Instance, - pub exp: u64, -} - -#[derive(Debug)] -pub struct Authenticated> { - pub source: Vec>, - pub message: GiteratedMessage, -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] -pub struct AuthenticatedPayload { - pub source: Vec, - pub object: String, - pub operation: String, - pub payload: Vec, -} - -impl AuthenticatedPayload { - pub fn into_message(self) -> GiteratedMessage { - GiteratedMessage { - object: NetworkAnyObject(self.object), - operation: self.operation, - payload: NetworkAnyOperation(self.payload), - } - } -} - -pub trait AuthenticationSourceProvider: Debug { - fn authenticate(&self, payload: &Vec) -> AuthenticationSource; -} - -pub trait AuthenticationSourceProviders: Debug { - fn authenticate_all(&self, payload: &Vec) -> Vec; -} - -impl AuthenticationSourceProviders for A -where - A: AuthenticationSourceProvider, -{ - fn authenticate_all(&self, payload: &Vec) -> Vec { - vec![self.authenticate(payload)] - } -} - -impl AuthenticationSourceProviders for (A, B) -where - A: AuthenticationSourceProvider, - B: AuthenticationSourceProvider, -{ - fn authenticate_all(&self, payload: &Vec) -> Vec { - let (first, second) = self; - - vec![first.authenticate(payload), second.authenticate(payload)] - } -} - -impl> Authenticated { - pub fn new(message: GiteratedMessage) -> Self { - Self { - source: vec![], - message, - } - } - - pub fn append_authentication( - &mut self, - authentication: Arc, - ) { - self.source.push(authentication); - } - - pub fn into_payload(mut self) -> AuthenticatedPayload { - let payload = serde_json::to_vec(&self.message.payload).unwrap(); - - AuthenticatedPayload { - object: self.message.object.to_string(), - operation: self.message.operation, - source: self - .source - .drain(..) - .map(|provider| provider.as_ref().authenticate_all(&payload)) - .flatten() - .collect::>(), - payload, - } - } -} - -mod verified {} - -#[derive(Clone, Debug)] -pub struct UserAuthenticator { - pub user: User, - pub token: UserAuthenticationToken, -} - -impl AuthenticationSourceProvider for UserAuthenticator { - fn authenticate(&self, _payload: &Vec) -> AuthenticationSource { - AuthenticationSource::User { - user: self.user.clone(), - token: self.token.clone(), - } - } -} - -#[derive(Debug, Clone)] -pub struct InstanceAuthenticator { - pub instance: Instance, - pub private_key: String, -} - -impl AuthenticationSourceProvider for InstanceAuthenticator { - fn authenticate(&self, payload: &Vec) -> AuthenticationSource { - let mut rng = rand::thread_rng(); - - let private_key = RsaPrivateKey::from_pkcs1_pem(&self.private_key).unwrap(); - let signing_key = SigningKey::::new(private_key); - let signature = signing_key.sign_with_rng(&mut rng, payload); - - AuthenticationSource::Instance { - instance: self.instance.clone(), - // TODO: Actually parse signature from private key - signature: InstanceSignature(signature.to_bytes().into_vec()), - } - } -} +use crate::{instance::Instance, user::User}; #[repr(transparent)] #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] @@ -179,14 +33,9 @@ impl AsRef<[u8]> for InstanceSignature { } } -#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] -pub enum AuthenticationSource { - User { - user: User, - token: UserAuthenticationToken, - }, - Instance { - instance: Instance, - signature: InstanceSignature, - }, +#[derive(Debug, Serialize, Deserialize)] +pub struct UserTokenMetadata { + pub user: User, + pub generated_for: Instance, + pub exp: u64, } diff --git a/giterated-protocol/Cargo.toml b/giterated-protocol/Cargo.toml index 78fc0d4..fc87fe8 100644 --- a/giterated-protocol/Cargo.toml +++ b/giterated-protocol/Cargo.toml @@ -15,4 +15,7 @@ keywords = ["giterated"] [dependencies] giterated-stack = {path = "../giterated-stack" } serde = { version = "1.0.188", features = [ "derive" ]} -tracing = "0.1" \ No newline at end of file +tracing = "0.1" +rand = "0.8" +rsa = {version = "0.9", features = ["sha2"]} +serde_json = "1.0" \ No newline at end of file diff --git a/giterated-protocol/src/lib.rs b/giterated-protocol/src/lib.rs index b5d92fb..2b3f8b7 100644 --- a/giterated-protocol/src/lib.rs +++ b/giterated-protocol/src/lib.rs @@ -1,3 +1,261 @@ mod substack; +use std::convert::Infallible; +use std::fmt::Debug; +use std::str::FromStr; +use std::{fmt::Display, sync::Arc}; + +use giterated_stack::models::{Error, GiteratedObject, GiteratedOperation, Instance, User}; +use rsa::pkcs1::DecodeRsaPrivateKey; +use rsa::pkcs1v15::SigningKey; +use rsa::sha2::Sha256; +use rsa::signature::{RandomizedSigner, SignatureEncoding}; +use rsa::RsaPrivateKey; +use serde::{Deserialize, Serialize}; pub use substack::{NetworkedObject, NetworkedOperation, NetworkedSubstack}; + +#[derive(Clone, Default)] +pub struct NetworkOperationState { + authentication: Vec>, +} + +impl NetworkOperationState { + pub fn authenticate( + &mut self, + provider: impl AuthenticationSourceProviders + Send + Sync + 'static, + ) { + self.authentication.push(Arc::new(provider)) + } +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] +pub struct AuthenticatedPayload { + pub source: Vec, + pub object: String, + pub operation: String, + pub payload: Vec, +} + +impl AuthenticatedPayload { + pub fn into_message(self) -> GiteratedMessage { + GiteratedMessage { + object: NetworkAnyObject(self.object), + operation: self.operation, + payload: NetworkAnyOperation(self.payload), + } + } +} + +pub trait AuthenticationSourceProvider: Debug { + fn authenticate(&self, payload: &Vec) -> AuthenticationSource; +} + +pub trait AuthenticationSourceProviders: Debug { + fn authenticate_all(&self, payload: &Vec) -> Vec; +} + +impl AuthenticationSourceProviders for A +where + A: AuthenticationSourceProvider, +{ + fn authenticate_all(&self, payload: &Vec) -> Vec { + vec![self.authenticate(payload)] + } +} + +impl AuthenticationSourceProviders for (A, B) +where + A: AuthenticationSourceProvider, + B: AuthenticationSourceProvider, +{ + fn authenticate_all(&self, payload: &Vec) -> Vec { + let (first, second) = self; + + vec![first.authenticate(payload), second.authenticate(payload)] + } +} + +mod verified {} + +#[derive(Clone, Debug)] +pub struct UserAuthenticator { + pub user: User, + pub token: UserAuthenticationToken, +} + +impl AuthenticationSourceProvider for UserAuthenticator { + fn authenticate(&self, _payload: &Vec) -> AuthenticationSource { + AuthenticationSource::User { + user: self.user.clone(), + token: self.token.clone(), + } + } +} + +#[derive(Debug, Clone)] +pub struct InstanceAuthenticator { + pub instance: Instance, + pub private_key: String, +} + +impl AuthenticationSourceProvider for InstanceAuthenticator { + fn authenticate(&self, payload: &Vec) -> AuthenticationSource { + let mut rng = rand::thread_rng(); + + let private_key = RsaPrivateKey::from_pkcs1_pem(&self.private_key).unwrap(); + let signing_key = SigningKey::::new(private_key); + let signature = signing_key.sign_with_rng(&mut rng, payload); + + AuthenticationSource::Instance { + instance: self.instance.clone(), + // TODO: Actually parse signature from private key + signature: InstanceSignature(signature.to_bytes().into_vec()), + } + } +} + +#[repr(transparent)] +#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +pub struct UserAuthenticationToken(String); + +impl From for UserAuthenticationToken { + fn from(value: String) -> Self { + Self(value) + } +} + +impl ToString for UserAuthenticationToken { + fn to_string(&self) -> String { + self.0.clone() + } +} + +impl AsRef for UserAuthenticationToken { + fn as_ref(&self) -> &str { + &self.0 + } +} + +#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +pub struct InstanceSignature(Vec); + +impl AsRef<[u8]> for InstanceSignature { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +pub enum AuthenticationSource { + User { + user: User, + token: UserAuthenticationToken, + }, + Instance { + instance: Instance, + signature: InstanceSignature, + }, +} + +#[derive(Serialize)] +#[serde(bound(deserialize = "O: GiteratedObject, V: GiteratedOperation"))] +pub struct GiteratedMessage> { + #[serde(with = "string")] + pub object: O, + pub operation: String, + pub payload: V, +} + +#[allow(unused)] +mod string { + use std::fmt::Display; + use std::str::FromStr; + + use serde::{de, Deserialize, Deserializer, Serializer}; + + pub fn serialize(value: &T, serializer: S) -> Result + where + T: Display, + S: Serializer, + { + serializer.collect_str(value) + } + + pub fn deserialize<'de, T, D>(deserializer: D) -> Result + where + T: FromStr, + T::Err: Display, + D: Deserializer<'de>, + { + String::deserialize(deserializer)? + .parse() + .map_err(de::Error::custom) + } +} + +impl GiteratedMessage { + pub fn try_into>( + &self, + ) -> Result, ()> { + let object = O::from_object_str(&self.object.0).map_err(|_| ())?; + let payload = serde_json::from_slice::(&self.payload.0).map_err(|_| ())?; + + Ok(GiteratedMessage { + object, + operation: self.operation.clone(), + payload, + }) + } +} + +impl + Debug, O: GiteratedObject + Debug> Debug + for GiteratedMessage +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("GiteratedMessage") + .field("object", &self.object) + .field("operation", &self.operation) + .field("payload", &self.payload) + .finish() + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(transparent)] +#[repr(transparent)] +pub struct NetworkAnyObject(pub String); + +impl GiteratedObject for NetworkAnyObject { + fn object_name() -> &'static str { + "any" + } + + fn from_object_str(object_str: &str) -> Result { + Ok(Self(object_str.to_string())) + } +} + +impl Display for NetworkAnyObject { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.0) + } +} + +impl FromStr for NetworkAnyObject { + type Err = Infallible; + + fn from_str(s: &str) -> Result { + Ok(Self(s.to_owned())) + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(transparent)] +#[repr(transparent)] +pub struct NetworkAnyOperation(pub Vec); + +impl GiteratedOperation for NetworkAnyOperation { + type Success = Vec; + + type Failure = Vec; +} diff --git a/giterated-protocol/src/substack.rs b/giterated-protocol/src/substack.rs index 1e1087e..8f66635 100644 --- a/giterated-protocol/src/substack.rs +++ b/giterated-protocol/src/substack.rs @@ -2,12 +2,14 @@ use std::{fmt::Display, str::FromStr, sync::Arc}; use giterated_stack::{ models::{Error, GiteratedObject, GiteratedOperation, IntoInternalError, OperationError}, - AnyFailure, AnyObject, AnyOperation, AnySuccess, GiteratedStack, ObjectOperationPair, - StackOperationState, SubstackBuilder, + AnyFailure, AnyObject, AnyOperation, AnySuccess, GiteratedStack, GiteratedStackInner, + ObjectOperationPair, OperationState, StackOperationState, SubstackBuilder, }; use serde::{Deserialize, Serialize}; use tracing::{trace, warn}; +use crate::NetworkOperationState; + /// A Giterated substack that attempts to resolve with a remote, networked Giterated Daemon. /// /// # Usage @@ -54,15 +56,24 @@ pub struct NetworkedSubstack { impl Default for NetworkedSubstack { fn default() -> Self { - todo!() + Self { home_uri: None } } } impl NetworkedSubstack { - pub fn into_substack(self) -> SubstackBuilder { + pub fn into_server_substack(self) -> SubstackBuilder { let mut stack = SubstackBuilder::new(self); - stack.operation(handle_network_operation); + stack.operation(handle_network_operation::); + + // TODO: optional + stack.dynamic_operation(try_handle_with_remote); + + stack + } + + pub fn into_client_substack(self) -> SubstackBuilder { + let mut stack = SubstackBuilder::new(self); // TODO: optional stack.dynamic_operation(try_handle_with_remote); @@ -71,17 +82,17 @@ impl NetworkedSubstack { } } -pub async fn handle_network_operation( +pub async fn handle_network_operation( object: NetworkedObject, operation: NetworkedOperation, _state: NetworkedSubstack, - operation_state: StackOperationState, - stack: Arc, + OperationState(operation_state): OperationState, + stack: GiteratedStack, ) -> Result, OperationError>> { trace!("Handle network operation"); let mut result = None; - for (_, object_meta) in &stack.metadata.objects { + for (_, object_meta) in &stack.inner.metadata.objects { if let Ok(object) = (object_meta.from_str)(&object.0) { // TODO: This is definitely going to resolve us result = Some((object, object_meta)); @@ -97,6 +108,7 @@ pub async fn handle_network_operation( ); let operation_meta = stack + .inner .metadata .operations .get(&ObjectOperationPair { @@ -204,7 +216,7 @@ pub async fn try_handle_with_remote( operation: AnyOperation, state: NetworkedSubstack, _operation_state: StackOperationState, - stack: Arc, + stack: Arc, ) -> Result> { trace!( "Try handling object operation {}::{} with remote", diff --git a/giterated-stack/src/dynamic.rs b/giterated-stack/src/dynamic.rs new file mode 100644 index 0000000..c686283 --- /dev/null +++ b/giterated-stack/src/dynamic.rs @@ -0,0 +1,220 @@ +use std::{any::Any, ops::Deref, sync::Arc}; + +use giterated_models::{ + object::GiteratedObject, operation::GiteratedOperation, settings::Setting, + value::GiteratedObjectValue, +}; + +use crate::{ObjectOperationPair, ObjectSettingPair, ObjectValuePair, ValueMeta}; + +#[derive(Clone)] +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 { + 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 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 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 AnySuccess(pub Arc); + +#[derive(Clone)] +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/handler/handler_impl.rs b/giterated-stack/src/handler/handler_impl.rs index 989f0e3..6029d3e 100644 --- a/giterated-stack/src/handler/handler_impl.rs +++ b/giterated-stack/src/handler/handler_impl.rs @@ -7,7 +7,7 @@ use crate::{HandlerResolvable, IntoGiteratedHandler}; impl IntoGiteratedHandler<(R1,), (), S, OS, Result>> for H where - H: FnMut(R1, S, OS) -> Fut + Clone, + H: FnMut(R1, S) -> Fut + Clone, Fut: Future>> + 'static, Success: 'static, Failure: 'static, @@ -21,10 +21,10 @@ where &self, parameters: (R1,), state: S, - operation_state: OS, + _operation_state: OS, ) -> Result> { let (r1,) = parameters; - (self.clone())(r1, state, operation_state).await + (self.clone())(r1, state).await } } @@ -32,7 +32,7 @@ where impl IntoGiteratedHandler<(R1,), (A1,), S, OS, Result>> for H where - H: FnMut(R1, S, OS, A1) -> Fut + Clone, + H: FnMut(R1, S, A1) -> Fut + Clone, Fut: Future>> + 'static, Success: 'static, Failure: 'static, @@ -54,7 +54,7 @@ where .await .map_err(|e| OperationError::Internal(e.into()))?; let (r1,) = parameters; - (self.clone())(r1, state, operation_state, a1).await + (self.clone())(r1, state, a1).await } } @@ -62,7 +62,7 @@ where impl IntoGiteratedHandler<(R1,), (A1, A2), S, OS, Result>> for H where - H: FnMut(R1, S, OS, A1, A2) -> Fut + Clone, + H: FnMut(R1, S, A1, A2) -> Fut + Clone, Fut: Future>> + 'static, Success: 'static, Failure: 'static, @@ -89,7 +89,7 @@ where .await .map_err(|e| OperationError::Internal(e.into()))?; let (r1,) = parameters; - (self.clone())(r1, state, operation_state, a1, a2).await + (self.clone())(r1, state, a1, a2).await } } @@ -97,7 +97,7 @@ where impl IntoGiteratedHandler<(R1,), (A1, A2, A3), S, OS, Result>> for H where - H: FnMut(R1, S, OS, A1, A2, A3) -> Fut + Clone, + H: FnMut(R1, S, A1, A2, A3) -> Fut + Clone, Fut: Future>> + 'static, Success: 'static, Failure: 'static, @@ -129,7 +129,7 @@ where .await .map_err(|e| OperationError::Internal(e.into()))?; let (r1,) = parameters; - (self.clone())(r1, state, operation_state, a1, a2, a3).await + (self.clone())(r1, state, a1, a2, a3).await } } @@ -137,7 +137,7 @@ where impl IntoGiteratedHandler<(R1, R2), (), S, OS, Result>> for H where - H: FnMut(R1, R2, S, OS) -> Fut + Clone, + H: FnMut(R1, R2, S) -> Fut + Clone, Fut: Future>> + 'static, Success: 'static, Failure: 'static, @@ -152,10 +152,10 @@ where &self, parameters: (R1, R2), state: S, - operation_state: OS, + _operation_state: OS, ) -> Result> { let (r1, r2) = parameters; - (self.clone())(r1, r2, state, operation_state).await + (self.clone())(r1, r2, state).await } } @@ -163,7 +163,7 @@ where impl IntoGiteratedHandler<(R1, R2), (A1,), S, OS, Result>> for H where - H: FnMut(R1, R2, S, OS, A1) -> Fut + Clone, + H: FnMut(R1, R2, S, A1) -> Fut + Clone, Fut: Future>> + 'static, Success: 'static, Failure: 'static, @@ -187,7 +187,7 @@ where .map_err(|e| OperationError::Internal(e.into()))?; let (r1, r2) = parameters; - (self.clone())(r1, r2, state, operation_state, a1).await + (self.clone())(r1, r2, state, a1).await } } @@ -195,7 +195,7 @@ where impl IntoGiteratedHandler<(R1, R2), (A1, A2), S, OS, Result>> for H where - H: FnMut(R1, R2, S, OS, A1, A2) -> Fut + Clone, + H: FnMut(R1, R2, S, A1, A2) -> Fut + Clone, Fut: Future>> + 'static, Success: 'static, Failure: 'static, @@ -224,7 +224,7 @@ where .map_err(|e| OperationError::Internal(e.into()))?; let (r1, r2) = parameters; - (self.clone())(r1, r2, state, operation_state, a1, a2).await + (self.clone())(r1, r2, state, a1, a2).await } } @@ -233,7 +233,7 @@ impl IntoGiteratedHandler<(R1, R2), (A1, A2, A3), S, OS, Result>> for H where - H: FnMut(R1, R2, S, OS, A1, A2, A3) -> Fut + Clone, + H: FnMut(R1, R2, S, A1, A2, A3) -> Fut + Clone, Fut: Future>> + 'static, Success: 'static, Failure: 'static, @@ -267,6 +267,6 @@ where .map_err(|e| OperationError::Internal(e.into()))?; let (r1, r2) = parameters; - (self.clone())(r1, r2, state, operation_state, a1, a2, a3).await + (self.clone())(r1, r2, state, a1, a2, a3).await } } diff --git a/giterated-stack/src/handler/mod.rs b/giterated-stack/src/handler/mod.rs index e811325..f6119b4 100644 --- a/giterated-stack/src/handler/mod.rs +++ b/giterated-stack/src/handler/mod.rs @@ -30,18 +30,17 @@ impl Default for HandlerTree { } } -impl<'fut: 'o + 'p, 'p, 'o, P, O, E> HandlerTree> +impl<'fut: 'o + 'p, 'p, 'o, P, O, E, OS> HandlerTree> where P: Clone, { - pub fn push(&mut self, handler: HandlerWrapper) { + pub fn push(&mut self, handler: HandlerWrapper) { self.elements.push(handler); } - pub async fn handle( - &self, - parameters: P, - operation_state: StackOperationState, - ) -> Result> { + pub async fn handle(&self, parameters: P, operation_state: OS) -> Result> + where + OS: Clone + 'static, + { for handler in self.elements.iter() { match handler .handle(parameters.clone(), operation_state.clone()) @@ -60,12 +59,12 @@ where } } -pub struct HandlerWrapper { +pub struct HandlerWrapper { func: Arc< dyn Fn( P, Arc, - StackOperationState, + OS, ) -> LocalBoxFuture<'static, Result>> + Send + Sync, @@ -73,17 +72,16 @@ pub struct HandlerWrapper { state: Arc, } -impl HandlerWrapper { +impl HandlerWrapper { pub fn new(state: S, handler: F) -> Self where - F: IntoGiteratedHandler>> - + Send - + Sync, + F: IntoGiteratedHandler>> + Send + Sync, S: Send + Sync + Clone + 'static, E: 'static, P: 'static + Clone, F: 'static, O: 'static, + OS: Clone, { let state = Arc::new(state); @@ -91,9 +89,7 @@ impl HandlerWrapper { let state_two = state.clone(); HandlerWrapper { func: Arc::new( - move |args: P, - state: Arc, - operation_state: StackOperationState| { + move |args: P, state: Arc, operation_state: OS| { let handler = handler_func.clone(); let operation_state = operation_state.clone(); let state = state.downcast_ref::().unwrap(); @@ -110,17 +106,13 @@ impl HandlerWrapper { } } - pub async fn handle( - &self, - required: P, - operation_state: StackOperationState, - ) -> Result> { + pub async fn handle(&self, required: P, operation_state: OS) -> Result> { (self.func)(required, self.state.clone(), operation_state).await } - pub fn map(self, predicate: F) -> HandlerWrapper + pub fn map(self, predicate: F) -> HandlerWrapper where - F: Fn(&N, &StackOperationState) -> Result> + Clone + Send + Sync, + F: Fn(&N, &OS) -> Result> + Clone + Send + Sync, R: std::fmt::Debug + 'static, E: Into> + 'static, OperationError: From> + 'static, @@ -128,17 +120,16 @@ impl HandlerWrapper { N: 'static, P: 'static, O: 'static, + OS: Clone, { let func = Arc::new(self.func); let predicate = Arc::new(predicate); HandlerWrapper { func: Arc::new( - move |args: N, - state: Arc, - operation_state: StackOperationState| { + move |args: N, state: Arc, operation_state: OS| { let predicate_output = predicate(&args, &operation_state); let func = func.clone(); - let operation_state: StackOperationState = operation_state.clone(); + let operation_state: OS = operation_state.clone(); async move { let predicate_output = predicate_output?; let operation_state = operation_state; @@ -154,9 +145,9 @@ impl HandlerWrapper { } } - pub fn map_return(self, predicate: F) -> HandlerWrapper + pub fn map_return(self, predicate: F) -> HandlerWrapper where - F: Fn(Result>, &StackOperationState) -> Result> + F: Fn(Result>, &OS) -> Result> + Clone + Send + Sync, @@ -164,14 +155,13 @@ impl HandlerWrapper { F: 'static, E: 'static, P: 'static, + OS: Clone, { let predicate = Arc::new(predicate); let func = self.func; HandlerWrapper { func: Arc::new( - move |args: P, - state: Arc, - operation_state: StackOperationState| { + move |args: P, state: Arc, operation_state: OS| { let clone = predicate.clone(); let func = func.clone(); let _statoperation_statee = operation_state.clone(); @@ -204,7 +194,7 @@ pub trait HandlerResolvable: Sized { } #[async_trait::async_trait(?Send)] -impl HandlerResolvable for Arc { +impl HandlerResolvable for GiteratedStack { type Error = MissingValue; async fn from_handler_state( diff --git a/giterated-stack/src/lib.rs b/giterated-stack/src/lib.rs index 439484c..12041c9 100644 --- a/giterated-stack/src/lib.rs +++ b/giterated-stack/src/lib.rs @@ -1,4 +1,6 @@ +mod dynamic; mod handler; +pub use dynamic::*; pub use handler::*; mod meta; pub use meta::*; @@ -9,18 +11,19 @@ mod substack; use serde::{de::DeserializeOwned, Deserialize, Serialize}; pub use stack::*; pub use substack::*; -pub mod state; pub mod update; // Temp pub use to figure out what's important pub mod models { pub use anyhow::Error; pub use giterated_models::error::{IntoInternalError, OperationError}; + pub use giterated_models::instance::Instance; pub use giterated_models::object::GiteratedObject; pub use giterated_models::operation::GiteratedOperation; + pub use giterated_models::user::User; } -use std::{any::Any, convert::Infallible, ops::Deref, sync::Arc}; +use std::{convert::Infallible, ops::Deref}; use core::fmt::Debug; use giterated_models::{ @@ -405,7 +408,7 @@ impl + Send + Sync> FromOperationState, + pub runtime: GiteratedStack, pub instance: Option, pub user: Option, } @@ -459,214 +462,16 @@ where type Failure = (); } -#[derive(Clone)] -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 { - 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 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 AnySetting { - inner: Arc, - kind: ObjectSettingPair<'static>, -} +pub struct OperationState(pub OS); -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 AnySuccess(pub Arc); - -#[derive(Clone)] -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 - } +#[async_trait::async_trait(?Send)] +impl HandlerResolvable for OperationState { + type Error = MissingValue; - fn meta() -> Option { + async fn from_handler_state( + _required_parameters: &P, + _operation_state: &OS, + ) -> Result { todo!() } } diff --git a/giterated-stack/src/meta/mod.rs b/giterated-stack/src/meta/mod.rs index eefa2c6..bcab915 100644 --- a/giterated-stack/src/meta/mod.rs +++ b/giterated-stack/src/meta/mod.rs @@ -1,4 +1,4 @@ -use std::{any::Any, collections::HashMap, str::FromStr, sync::Arc}; +use std::{any::Any, collections::HashMap, str::FromStr}; use futures_util::{future::LocalBoxFuture, FutureExt}; use giterated_models::{ @@ -288,7 +288,7 @@ pub struct SettingMeta { pub setting_updated: for<'fut> fn( AnyObject, AnySetting, - Arc, + GiteratedStack, &StackOperationState, ) -> LocalBoxFuture<'_, ()>, } @@ -300,7 +300,7 @@ pub trait IntoSettingMeta { fn setting_updated( object: AnyObject, setting: AnySetting, - stack: Arc, + stack: GiteratedStack, operation_state: &StackOperationState, ) -> LocalBoxFuture<'_, ()>; } @@ -321,7 +321,7 @@ impl IntoSettingMeta fn setting_updated( object: AnyObject, setting: AnySetting, - stack: Arc, + stack: GiteratedStack, operation_state: &StackOperationState, ) -> LocalBoxFuture<'_, ()> { async move { diff --git a/giterated-stack/src/stack.rs b/giterated-stack/src/stack.rs index b8bb016..5605eef 100644 --- a/giterated-stack/src/stack.rs +++ b/giterated-stack/src/stack.rs @@ -1,15 +1,12 @@ use std::any::Any; use std::fmt::Debug; +use std::marker::PhantomData; use std::ops::Deref; use std::{collections::HashMap, sync::Arc}; -use giterated_models::authenticated::AuthenticatedPayload; -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, SetSettingError, Setting}; +use giterated_models::error::IntoInternalError; +use giterated_models::settings::Setting; use giterated_models::value::GetValue; use giterated_models::{ error::OperationError, @@ -29,37 +26,78 @@ use crate::{ RuntimeMetadata, StackOperationState, SubstackBuilder, }; -pub type OperationHandler = HandlerWrapper<(AnyObject, AnyOperation), AnySuccess, AnyFailure>; +pub type OperationHandler = + HandlerWrapper<(AnyObject, AnyOperation), AnySuccess, AnyFailure, OS>; -pub type ValueGetter = HandlerWrapper<(AnyObject, String), AnyValue, AnyFailure>; +pub type ValueGetter = HandlerWrapper<(AnyObject, String), AnyValue, AnyFailure, OS>; -pub type SettingGetter = HandlerWrapper<(AnyObject,), AnySetting, AnyFailure>; +pub type SettingGetter = HandlerWrapper<(AnyObject,), AnySetting, AnyFailure, OS>; -pub type ValueChange = HandlerWrapper<(AnyObject, AnyValue), (), anyhow::Error>; +pub type ValueChange = HandlerWrapper<(AnyObject, AnyValue), (), anyhow::Error, OS>; -pub type SettingChange = HandlerWrapper<(AnyObject, AnySetting), (), anyhow::Error>; +pub type SettingChange = HandlerWrapper<(AnyObject, AnySetting), (), anyhow::Error, OS>; -#[derive(Default)] -pub struct GiteratedStack { - operation_handlers: HashMap, HandlerTree>, - value_getters: HashMap, ValueGetter>, - setting_getters: HashMap<&'static str, SettingGetter>, - value_change: HashMap, ValueChange>, - setting_change: HashMap, SettingChange>, +#[derive(Default, Clone)] +pub struct GiteratedStack { + pub inner: Arc>, +} + +impl Deref for GiteratedStack { + type Target = GiteratedStackInner; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +pub struct GiteratedStackInner { + operation_handlers: HashMap, HandlerTree>>, + value_getters: HashMap, ValueGetter>, + setting_getters: HashMap<&'static str, SettingGetter>, + value_change: HashMap, ValueChange>, + setting_change: HashMap, SettingChange>, metadata_providers: Vec>, pub metadata: RuntimeMetadata, + _marker: PhantomData, } -impl Debug for GiteratedStack { +impl Default for GiteratedStackInner { + fn default() -> Self { + Self { + operation_handlers: Default::default(), + value_getters: Default::default(), + setting_getters: Default::default(), + value_change: Default::default(), + setting_change: Default::default(), + metadata_providers: Default::default(), + metadata: Default::default(), + _marker: Default::default(), + } + } +} + +impl Debug for GiteratedStack { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("GiteratedStack").finish() } } -impl GiteratedStack { +pub struct GiteratedStackBuilder { + inner: GiteratedStackInner, +} + +impl Default for GiteratedStackBuilder { + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} + +impl GiteratedStackBuilder { pub fn merge_builder( &mut self, - mut builder: SubstackBuilder, + mut builder: SubstackBuilder, ) -> &mut Self { for (target, handler) in builder.operation_handlers { let tree = self.get_or_create_tree(&target); @@ -68,35 +106,55 @@ impl GiteratedStack { } for (target, handler) in builder.value_getters { - assert!(self.value_getters.insert(target, handler).is_none()); + assert!(self.inner.value_getters.insert(target, handler).is_none()); } for (target, handler) in builder.setting_getters { - assert!(self.setting_getters.insert(target, handler).is_none()); + assert!(self.inner.setting_getters.insert(target, handler).is_none()); } for (target, handler) in builder.value_change { - self.value_change.insert(target, handler); + self.inner.value_change.insert(target, handler); } for (target, handler) in builder.setting_change { - self.setting_change.insert(target, handler); + self.inner.setting_change.insert(target, handler); } - self.metadata_providers + self.inner + .metadata_providers .append(&mut builder.metadata_providers); - self.metadata.append(builder.metadata); + self.inner.metadata.append(builder.metadata); self } - pub async fn value_update( - &self, - object: O, - new_value: AnyValue, - operation_state: &StackOperationState, - ) where + fn get_or_create_tree( + &mut self, + target: &ObjectOperationPair<'static>, + ) -> &mut HandlerTree> { + if self.inner.operation_handlers.contains_key(target) { + self.inner.operation_handlers.get_mut(target).unwrap() + } else { + self.inner + .operation_handlers + .insert(target.clone(), HandlerTree::default()); + + self.inner.operation_handlers.get_mut(target).unwrap() + } + } + + pub fn finish(self) -> GiteratedStack { + GiteratedStack { + inner: Arc::new(self.inner), + } + } +} + +impl GiteratedStack { + pub async fn value_update(&self, object: O, new_value: AnyValue, operation_state: &OS) + where O: GiteratedObject + 'static, { trace!( @@ -107,7 +165,7 @@ impl GiteratedStack { let object = AnyObject::new(object); // First, resolve a handler for the exact object value pair - if let Some(handler) = self.value_change.get(&new_value.kind()) { + if let Some(handler) = self.inner.value_change.get(&new_value.kind()) { // TODO let _ = handler .handle((object.clone(), new_value.clone()), operation_state.clone()) @@ -119,7 +177,7 @@ impl GiteratedStack { object_kind: "any", value_kind: new_value.kind().value_kind, }; - if let Some(handler) = self.value_change.get(&target) { + if let Some(handler) = self.inner.value_change.get(&target) { // TODO let _ = handler .handle((object.clone(), new_value.clone()), operation_state.clone()) @@ -130,7 +188,7 @@ impl GiteratedStack { object_kind: O::object_name(), value_kind: "any", }; - if let Some(handler) = self.value_change.get(&target) { + if let Some(handler) = self.inner.value_change.get(&target) { // TODO let _ = handler .handle((object.clone(), new_value.clone()), operation_state.clone()) @@ -143,7 +201,7 @@ impl GiteratedStack { object_kind: "any", value_kind: "any", }; - if let Some(handler) = self.value_change.get(&target) { + if let Some(handler) = self.inner.value_change.get(&target) { // TODO let _ = handler .handle((object.clone(), new_value.clone()), operation_state.clone()) @@ -151,19 +209,15 @@ impl GiteratedStack { } } - pub async fn setting_update( - &self, - object: O, - new_setting: S, - operation_state: &StackOperationState, - ) where + pub async fn setting_update(&self, object: O, new_setting: S, operation_state: &OS) + where O: GiteratedObject + 'static, S: Setting + 'static, { trace!("setting updated {}::{}", O::object_name(), S::name()); let target = ObjectSettingPair::from_types::(); - if let Some(handler) = self.setting_change.get(&target) { + if let Some(handler) = self.inner.setting_change.get(&target) { let _ = handler .handle( (AnyObject::new(object), AnySetting::new::(new_setting)), @@ -190,15 +244,17 @@ impl GiteratedStack { O: GiteratedObject + 'static + Clone, S: Setting + 'static + Clone, { - for provider in self.metadata_providers.iter() { + for provider in self.inner.metadata_providers.iter() { if provider.provides_for(object as &dyn Any) { let setting_meta = self + .inner .metadata .settings .get(&ObjectSettingPair::from_types::()) .ok_or_else(|| OperationError::Unhandled)?; let object_meta = self + .inner .metadata .objects .get(O::object_name()) @@ -227,7 +283,7 @@ impl GiteratedStack { O: GiteratedObject + 'static + Clone, S: Setting + 'static, { - for provider in self.metadata_providers.iter() { + for provider in self.inner.metadata_providers.iter() { if provider.provides_for(object as &dyn Any) { trace!( "Resolving setting {} for object {} from provider.", @@ -236,12 +292,14 @@ impl GiteratedStack { ); let setting_meta = self + .inner .metadata .settings .get(&ObjectSettingPair::from_types::()) .ok_or_else(|| OperationError::Unhandled)?; let object_meta = self + .inner .metadata .objects .get(O::object_name()) @@ -264,465 +322,15 @@ impl GiteratedStack { Err(OperationError::Unhandled) } - - fn get_or_create_tree( - &mut self, - target: &ObjectOperationPair<'static>, - ) -> &mut HandlerTree { - if self.operation_handlers.contains_key(target) { - self.operation_handlers.get_mut(target).unwrap() - } else { - self.operation_handlers - .insert(target.clone(), HandlerTree::default()); - - self.operation_handlers.get_mut(target).unwrap() - } - } } -impl GiteratedStack { - /// Handles a giterated network message, returning either a raw success - /// payload or a serialized error payload. - pub async fn handle_network_message( - &self, - message: AuthenticatedPayload, - operation_state: &StackOperationState, - ) -> Result, OperationError>> { - let message: GiteratedMessage = - message.into_message(); - - // Deserialize the object, also getting the object type's name - let (object_type, object) = { - let mut result = None; - - for (object_type, object_meta) in self.metadata.objects.iter() { - if let Ok(object) = (object_meta.from_str)(&message.object.0) { - result = Some((object_type.clone(), object)); - break; - } - } - - result - } - .ok_or_else(|| OperationError::Unhandled)?; - - trace!( - "Handling network message {}::<{}>", - message.operation, - object_type - ); - - if message.operation == "get_value" { - // Special case - let operation: GetValue = serde_json::from_slice(&message.payload.0).unwrap(); - - let result = self - .network_get_value( - object, - object_type.clone(), - operation.clone(), - operation_state, - ) - .await; - - // In the case of internal errors, attach context - let result = result.map_err(|err| match err { - OperationError::Operation(operation) => OperationError::Operation(operation), - OperationError::Internal(internal) => { - OperationError::Internal(internal.context(format!( - "{}::get_value::<{}> outcome", - object_type, operation.value_name - ))) - } - OperationError::Unhandled => OperationError::Unhandled, - }); - - let result = result.map(|r| serde_json::to_vec(&r).unwrap()); - - return result; - } else if message.operation == "get_setting" { - let operation: GetSetting = serde_json::from_slice(&message.payload.0).unwrap(); - let setting_meta = self - .metadata - .settings - .get(&ObjectSettingPair { - object_kind: &object_type, - setting_name: &operation.setting_name, - }) - .ok_or_else(|| OperationError::Unhandled)?; - let raw_result = self - .get_setting( - object, - object_type.clone(), - operation.clone(), - operation_state, - ) - .await; - return match raw_result { - Ok(success) => { - // Success is the setting type, serialize it - let serialized = (setting_meta.serialize)(success).unwrap(); - - Ok(serde_json::to_vec(&serialized).unwrap()) - } - Err(err) => Err(match err { - OperationError::Operation(failure) => { - // We know how to resolve this type - let failure: GetSettingError = *failure.downcast().unwrap(); - - OperationError::Operation(serde_json::to_vec(&failure).unwrap()) - } - OperationError::Internal(internal) => { - OperationError::Internal(internal.context(format!( - "{}::get_setting::<{}> handler outcome", - object_type, setting_meta.name - ))) - } - OperationError::Unhandled => OperationError::Unhandled, - }), - }; - } else if message.operation == "set_setting" { - let operation: SetSetting = serde_json::from_slice(&message.payload.0).unwrap(); - - trace!( - "Handling network {}::set_setting for {}", - object_type, - operation.setting_name - ); - - let setting_meta = self - .metadata - .settings - .get(&ObjectSettingPair { - object_kind: &object_type, - 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()?, - ))?; - - let setting = (setting_meta.deserialize)(operation.value) - .as_internal_error_with_context(format!( - "deserializing setting {} for object {}", - operation.setting_name, object_type - ))?; - - trace!( - "Deserialized setting {} for object {}", - operation.setting_name, - object_type, - ); - - for provider in self.metadata_providers.iter() { - if provider.provides_for(object.deref()) { - trace!( - "Resolved setting provider for setting {} for object {}", - operation.setting_name, - object_type, - ); - - let object_meta = self - .metadata - .objects - .get(&object_type) - .ok_or_else(|| OperationError::Unhandled)?; - - let raw_result = provider - .write(object.clone(), object_meta, setting.clone(), setting_meta) - .await; - - return match raw_result { - Ok(_) => { - (setting_meta.setting_updated)( - object, - setting, - operation_state.runtime.clone(), - operation_state, - ) - .await; - - Ok(serde_json::to_vec(&()).unwrap()) - } - Err(e) => Err(OperationError::Internal(e.context(format!( - "writing object {} setting {}", - object_type, operation.setting_name - )))), - }; - } - - trace!( - "Failed to resolve setting provider for setting {} for object {}", - operation.setting_name, - object_type, - ); - } - } - - let target = ObjectOperationPair { - object_name: &object_type, - operation_name: &message.operation, - }; - - // Resolve the target operations from the handlers table - let handler = self - .operation_handlers - .get(&target) - .ok_or_else(|| OperationError::Unhandled)?; - - trace!( - "Resolved operation handler for network message {}::<{}>", - message.operation, - object_type - ); - - // Deserialize the operation - let meta = self - .metadata - .operations - .get(&target) - .ok_or_else(|| OperationError::Unhandled)?; - - let operation = - (meta.deserialize)(&message.payload.0).as_internal_error_with_context(format!( - "deserializing operation {}::{}", - target.object_name, target.operation_name - ))?; - - trace!( - "Deserialized operation for network message {}::<{}>", - message.operation, - object_type - ); - - trace!( - "Calling handler for network message {}::<{}>", - message.operation, - object_type - ); - - // Get the raw result of the operation, where the return values are boxed. - let raw_result = handler - .handle((object.clone(), operation.clone()), operation_state.clone()) - .await; - - trace!( - "Finished handling network message {}::<{}>", - message.operation, - object_type - ); - - // Deserialize the raw result for the network - match raw_result { - Ok(success) => Ok((meta.serialize_success)(success).as_internal_error()?), - Err(err) => Err(match err { - OperationError::Operation(failure) => { - OperationError::Operation((meta.serialize_error)(failure).as_internal_error()?) - } - OperationError::Internal(internal) => { - OperationError::Internal(internal.context(format!( - "operation {}::{} handler outcome", - target.object_name, target.operation_name - ))) - } - OperationError::Unhandled => OperationError::Unhandled, - }), - } - } - - pub async fn network_get_value( - &self, - object: AnyObject, - object_kind: String, - operation: GetValue, - operation_state: &StackOperationState, - ) -> Result, OperationError>> { - trace!("Handling network get_value for {}", operation.value_name); - - // 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)?; - - 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)?; - - 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: &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 - } - } - } - } - } - - Err(OperationError::Unhandled) - } - +impl GiteratedStack { pub async fn get_setting( &self, object: AnyObject, object_kind: String, operation: GetSetting, - _operation_state: &StackOperationState, + _operation_state: &OS, ) -> Result>> { trace!( "Handling network {}::get_setting for {}", @@ -730,9 +338,10 @@ impl GiteratedStack { operation.setting_name ); - for provider in self.metadata_providers.iter() { + for provider in self.inner.metadata_providers.iter() { if provider.provides_for(object.deref()) { let setting_meta = self + .inner .metadata .settings .get(&ObjectSettingPair { @@ -742,6 +351,7 @@ impl GiteratedStack { .ok_or_else(|| OperationError::Unhandled)?; let object_meta = self + .inner .metadata .objects .get(&object_kind) @@ -766,70 +376,16 @@ impl GiteratedStack { Err(OperationError::Unhandled) } - - pub async fn network_set_setting( - &self, - object: AnyObject, - object_kind: String, - operation: SetSetting, - operation_state: &StackOperationState, - ) -> Result, OperationError>> { - trace!( - "Handling network {}::set_setting for {}", - object_kind, - operation.setting_name - ); - - let target = ObjectSettingPair { - object_kind: &object_kind, - setting_name: &operation.setting_name, - }; - - let handler = self.setting_change.get(&target).unwrap(); - - let setting_meta = self - .metadata - .settings - .get(&ObjectSettingPair { - object_kind: &object_kind, - setting_name: &operation.setting_name, - }) - .ok_or_else(|| OperationError::Unhandled)?; - - let setting = - (setting_meta.deserialize)(operation.value).as_internal_error_with_context(format!( - "deserializing setting {} for object {}", - operation.setting_name, object_kind - ))?; - - let raw_result = handler - .handle((object, setting.clone()), operation_state.clone()) - .await; - - match raw_result { - Ok(_) => { - // Serialize success, which is the value type itself - let serialized = serde_json::to_vec(&()).as_internal_error()?; - - Ok(serialized) - } - Err(err) => Err(match err { - OperationError::Operation(operation) => OperationError::Internal(operation), - OperationError::Internal(internal) => OperationError::Internal(internal), - OperationError::Unhandled => OperationError::Unhandled, - }), - } - } } #[async_trait::async_trait(?Send)] -impl ObjectBackend for Arc { +impl ObjectBackend for GiteratedStack { async fn object_operation( &self, in_object: O, operation_name: &str, payload: D, - operation_state: &StackOperationState, + operation_state: &OS, ) -> Result> where O: GiteratedObject + Debug + 'static, @@ -848,6 +404,7 @@ impl ObjectBackend for Arc { .ok_or_else(|| OperationError::Unhandled)?; let value_meta = self + .inner .metadata .values .get(&ObjectValuePair { @@ -863,7 +420,7 @@ impl ObjectBackend for Arc { value_name ); - if let Some(handler) = self.value_getters.get(&ObjectValuePair { + if let Some(handler) = self.inner.value_getters.get(&ObjectValuePair { object_kind: "any", value_kind: &get_value.value_name, }) { @@ -906,7 +463,7 @@ impl ObjectBackend for Arc { } } - if let Some(handler) = self.value_getters.get(&ObjectValuePair { + if let Some(handler) = self.inner.value_getters.get(&ObjectValuePair { object_kind: O::object_name(), value_kind: "any", }) { @@ -949,7 +506,7 @@ impl ObjectBackend for Arc { } } - if let Some(handler) = self.value_getters.get(&ObjectValuePair { + if let Some(handler) = self.inner.value_getters.get(&ObjectValuePair { object_kind: "any", value_kind: "any", }) { @@ -992,7 +549,7 @@ impl ObjectBackend for Arc { } } - if let Some(handler) = self.value_getters.get(&ObjectValuePair { + if let Some(handler) = self.inner.value_getters.get(&ObjectValuePair { object_kind: O::object_name(), value_kind: &get_value.value_name, }) { @@ -1080,7 +637,7 @@ impl ObjectBackend for Arc { let operation_type = { let mut operation_type = None; - for (target, operation_meta) in self.metadata.operations.iter() { + for (target, operation_meta) in self.inner.metadata.operations.iter() { // Skip elements that we know will not match if target.object_name != O::object_name() { continue; @@ -1102,6 +659,7 @@ impl ObjectBackend for Arc { // Resolve the handler from our handler tree let handler_tree = self + .inner .operation_handlers .get(&operation_type) .ok_or_else(|| OperationError::Unhandled)?; @@ -1131,13 +689,13 @@ impl ObjectBackend for Arc { async fn get_object( &self, object_str: &str, - _operation_state: &StackOperationState, - ) -> Result, OperationError> + _operation_state: &OS, + ) -> Result, OperationError> where O: GiteratedObject + Debug + 'static, { // TODO: Authorization? - for (_object_name, object_meta) in self.metadata.objects.iter() { + for (_object_name, object_meta) in self.inner.metadata.objects.iter() { if let Ok(object) = (object_meta.from_str)(object_str) { return Ok(unsafe { Object::new_unchecked(object.downcast_ref::().unwrap().clone(), self.clone()) @@ -1150,12 +708,12 @@ impl ObjectBackend for Arc { } // Placeholder -impl GiteratedStack { +impl GiteratedStack { pub async fn new_operation_func( &self, _object: AnyObject, _operation: AnyOperation, - _operation_state: StackOperationState, + _operation_state: OS, ) -> Result> { todo!() } diff --git a/giterated-stack/src/state.rs b/giterated-stack/src/state.rs deleted file mode 100644 index 07f25a0..0000000 --- a/giterated-stack/src/state.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::any::Any; - -/// A type which can be passed into a stateful handler. -/// -/// # Trait Bounds -/// This trait is bound on `Send + Sync`, as well as `Clone`. Handler states are -/// cloned many times, and should be inexpensive to clone. -/// -/// # Blanket Impl -/// This trait is blanket-impl'd on any type that meets the requirements. You do not need -/// to manually mark your state types with it. -pub trait HandlerState: Any + Send + Sync + Clone + 'static {} - -impl HandlerState for T where T: Send + Sync + Clone + 'static {} diff --git a/giterated-stack/src/substack.rs b/giterated-stack/src/substack.rs index d0c44ee..3d914fe 100644 --- a/giterated-stack/src/substack.rs +++ b/giterated-stack/src/substack.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, sync::Arc}; +use std::{collections::HashMap, marker::PhantomData, sync::Arc}; use futures_util::FutureExt; use giterated_models::{ @@ -15,23 +15,24 @@ use crate::{ handler::HandlerWrapper, provider::MetadataProvider, AnyFailure, AnyObject, AnyOperation, AnySetting, AnySuccess, AnyValue, GiteratedStack, GiteratedStackState, IntoGiteratedHandler, MaybeDynamicObject, MaybeDynamicValue, ObjectOperationPair, ObjectSettingPair, ObjectValuePair, - OperationHandler, RuntimeMetadata, SettingChange, SettingGetter, StackOperationState, - ValueChange, ValueGetter, + OperationHandler, OperationState, RuntimeMetadata, SettingChange, SettingGetter, + StackOperationState, ValueChange, ValueGetter, }; -pub struct SubstackBuilder { - pub(crate) operation_handlers: HashMap, OperationHandler>, - pub(crate) value_getters: HashMap, ValueGetter>, - pub(crate) setting_getters: HashMap<&'static str, SettingGetter>, +pub struct SubstackBuilder { + pub(crate) operation_handlers: HashMap, OperationHandler>, + pub(crate) value_getters: HashMap, ValueGetter>, + pub(crate) setting_getters: HashMap<&'static str, SettingGetter>, pub(crate) metadata: RuntimeMetadata, - pub(crate) value_change: HashMap, ValueChange>, + pub(crate) value_change: HashMap, ValueChange>, pub(crate) metadata_providers: Vec>, - pub(crate) setting_change: HashMap, SettingChange>, + pub(crate) setting_change: HashMap, SettingChange>, pub(crate) state: S, + _marker: PhantomData, } -impl SubstackBuilder { +impl SubstackBuilder { pub fn new(state: S) -> Self { Self { operation_handlers: Default::default(), @@ -42,11 +43,12 @@ impl SubstackBuilder { metadata_providers: Default::default(), setting_change: Default::default(), state, + _marker: PhantomData::default(), } } } -impl SubstackBuilder { +impl SubstackBuilder { /// Insert an operation handler into the runtime builder. /// /// # Type Registration @@ -56,25 +58,20 @@ impl SubstackBuilder { where O: GiteratedObject + Clone, D: GiteratedOperation + Clone, - H: IntoGiteratedHandler< - (O, D), - A, - S, - StackOperationState, - Result>, - > + Send + H: IntoGiteratedHandler<(O, D), A, S, OS, Result>> + + Send + Sync + 'static, O: 'static, D: 'static, D::Failure: std::fmt::Debug + 'static, D::Success: 'static, + OS: Clone, { let wrapped = HandlerWrapper::new(self.state.clone(), handler); let wrapped = wrapped.map( - |(any_object, any_operation): &(AnyObject, AnyOperation), - _state: &StackOperationState| { + |(any_object, any_operation): &(AnyObject, AnyOperation), _state: &OS| { Ok(( any_object.downcast_ref::().unwrap().clone(), any_operation.downcast_ref::().unwrap().clone(), @@ -102,6 +99,94 @@ impl SubstackBuilder { self } + /// Register a [`GiteratedObjectValue`] type with the runtime, providing + /// its associated handler for [`GetValue`]. + /// + /// # 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 dynamic_value(&mut self, handler: F) -> &mut Self + where + O: MaybeDynamicObject + 'static, + F: IntoGiteratedHandler< + (O, String), + A, + S, + OS, + Result>, + > + Send + + Sync, + F: 'static, + { + let wrapped = HandlerWrapper::new(self.state.clone(), handler); + + let wrapped = wrapped.map(|(any_object, name): &(AnyObject, String), _state: &OS| { + Ok((O::from_any(any_object), name.clone())) + }); + + let wrapped = wrapped.map_return(|ret_val, _state| match ret_val { + Ok(success) => Ok(success.into_any()), + Err(err) => Err(match err { + OperationError::Operation(failure) => OperationError::Internal(failure.into()), + OperationError::Internal(err) => OperationError::Internal(err), + OperationError::Unhandled => OperationError::Unhandled, + }), + }); + + assert!(self + .value_getters + .insert( + ObjectValuePair { + object_kind: O::object_name(), + value_kind: "any" + }, + wrapped + ) + .is_none()); + + self + } + + pub fn value_change(&mut self, handler: F) -> &mut Self + where + F: IntoGiteratedHandler<(O, V), A, S, OS, Result<(), OperationError>> + + Send + + Sync, + V: MaybeDynamicValue + Clone + 'static, + O: 'static + MaybeDynamicObject, + V: 'static, + F: 'static, + { + let wrapped = HandlerWrapper::new(self.state.clone(), handler); + + let wrapped = wrapped.map( + |(any_object, any_value): &(AnyObject, AnyValue), _state: &OS| { + Ok((O::from_any(any_object), V::from_any(any_value))) + }, + ); + + assert!(self + .value_change + .insert( + ObjectValuePair { + object_kind: O::object_name(), + value_kind: V::value_name() + }, + wrapped + ) + .is_none()); + + self + } + + pub fn object_metadata_provider(&mut self, provider: Box) -> &mut Self { + self.metadata_providers.push(provider); + + self + } +} + +impl SubstackBuilder { /// Register a [`GiteratedObject`] type with the runtime. /// /// # Type Registration @@ -115,11 +200,10 @@ impl SubstackBuilder { move |_object: Instance, operation: ObjectRequest, _state: S, - _operation_state: StackOperationState, - stack: Arc| { + stack: GiteratedStack| { let operation = operation.clone(); async move { - for (_object_name, object_meta) in stack.metadata.objects.iter() { + for (_object_name, object_meta) in stack.inner.metadata.objects.iter() { if (object_meta.from_str)(&operation.0).is_ok() { return Ok(ObjectResponse(operation.0.clone())); } @@ -163,9 +247,9 @@ impl SubstackBuilder { (), move |object: AnyObject, setting: AnySetting, - _state: (), - operation_state: StackOperationState, - stack: Arc| { + _state: _, + OperationState(operation_state): OperationState, + stack: GiteratedStack| { trace!( "value setting updated {}::{}", O::object_name(), @@ -194,8 +278,7 @@ impl SubstackBuilder { |object: AnyObject, _name: String, _state: _, - _operation_state: StackOperationState, - stack: Arc| { + stack: GiteratedStack| { info!("a setting handler called"); let object = object.clone(); async move { @@ -218,105 +301,14 @@ impl SubstackBuilder { self } - - /// Register a [`GiteratedObjectValue`] type with the runtime, providing - /// its associated handler for [`GetValue`]. - /// - /// # 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 dynamic_value(&mut self, handler: F) -> &mut Self - where - O: MaybeDynamicObject + 'static, - F: IntoGiteratedHandler< - (O, String), - A, - S, - StackOperationState, - Result>, - > + Send - + Sync, - F: 'static, - { - let wrapped = HandlerWrapper::new(self.state.clone(), handler); - - let wrapped = wrapped.map( - |(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(success.into_any()), - Err(err) => Err(match err { - OperationError::Operation(failure) => OperationError::Internal(failure.into()), - OperationError::Internal(err) => OperationError::Internal(err), - OperationError::Unhandled => OperationError::Unhandled, - }), - }); - - assert!(self - .value_getters - .insert( - ObjectValuePair { - object_kind: O::object_name(), - value_kind: "any" - }, - wrapped - ) - .is_none()); - - self - } - - pub fn value_change(&mut self, handler: F) -> &mut Self - where - F: IntoGiteratedHandler< - (O, V), - A, - S, - StackOperationState, - Result<(), OperationError>, - > + Send - + Sync, - V: MaybeDynamicValue + Clone + 'static, - O: 'static + MaybeDynamicObject, - V: 'static, - F: 'static, - { - let wrapped = HandlerWrapper::new(self.state.clone(), handler); - - let wrapped = wrapped.map( - |(any_object, any_value): &(AnyObject, AnyValue), _state: &StackOperationState| { - Ok((O::from_any(any_object), V::from_any(any_value))) - }, - ); - - assert!(self - .value_change - .insert( - ObjectValuePair { - object_kind: O::object_name(), - value_kind: V::value_name() - }, - wrapped - ) - .is_none()); - - self - } - - pub fn object_metadata_provider(&mut self, provider: Box) -> &mut Self { - self.metadata_providers.push(provider); - - self - } } // Placeholder -impl SubstackBuilder { +impl SubstackBuilder { pub fn dynamic_operation(&mut self, _handler: H) -> &mut Self { - todo!() + tracing::error!("Dynamic unimplemented"); + + self } } #[derive(Debug, Clone, thiserror::Error)]