diff --git a/.gitignore b/.gitignore index 9f434af..8ce8ef7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ target/ Cargo.lock .vscode/ -**/*.rs.bk \ No newline at end of file +**/*.rs.bk +.Ds_Store \ No newline at end of file diff --git a/core/examples/hello-world.rs b/core/examples/hello-world.rs new file mode 100644 index 0000000..7d1b771 --- /dev/null +++ b/core/examples/hello-world.rs @@ -0,0 +1,23 @@ +// use async_std::main; +// use serde::{Deserialize, Serialize}; +// use virto_sdk::StateMachine; + +// #[derive(VApp)] +// #[vapp( +// name = "Hello-world", +// description = "a simple app to count" +// version = "0.0.1", +// )] +// struct HelloWorld { +// count: i32 +// } + +// #[vctrl] +// impl HelloWorld { +// pub fn sum(&mut self, units: i32) { +// self.count += 1; +// } +// } +fn main() { + () +} diff --git a/core/src/backend/matrix/mod.rs b/core/src/backend/matrix/mod.rs index efee8d6..0e7f8ad 100644 --- a/core/src/backend/matrix/mod.rs +++ b/core/src/backend/matrix/mod.rs @@ -4,18 +4,16 @@ mod types; pub use registry::*; pub mod prelude { - pub use super::types::*; - pub use matrix_sdk::{ - ruma::{ - api::client::room::{create_room::v3::Request as CreateRoomRequest, Visibility}, - events::{ - macros::EventContent, room::encryption::RoomEncryptionEventContent, InitialStateEvent, + pub use super::types::*; + pub use matrix_sdk::{ + ruma::{ + api::client::room::{create_room::v3::Request as CreateRoomRequest, Visibility}, + events::{ + macros::EventContent, room::encryption::RoomEncryptionEventContent, + InitialStateEvent, + }, + serde::Raw, }, - serde::Raw, - }, - Client, Room, - }; - - + Client, Room, + }; } - diff --git a/core/src/backend/matrix/registry.rs b/core/src/backend/matrix/registry.rs index f20e713..494ead1 100644 --- a/core/src/backend/matrix/registry.rs +++ b/core/src/backend/matrix/registry.rs @@ -1,4 +1,6 @@ -use crate::base::{AppInfo, AppRegistryError, Registry, RegistryResult, RegistryState, AppMetadata }; +use crate::base::{ + AppInfo, AppMetadata, AppRegistryError, Registry, RegistryResult, RegistryState, +}; use super::prelude::*; use crate::utils::prelude::*; @@ -80,7 +82,6 @@ impl MatrixRegistry { } } - impl Registry for MatrixRegistry { async fn add(&self, info: &AppInfo) -> RegistryResult { if self.is_registered(info).await? { diff --git a/core/src/backend/matrix/types.rs b/core/src/backend/matrix/types.rs index f7b6f07..447d01f 100644 --- a/core/src/backend/matrix/types.rs +++ b/core/src/backend/matrix/types.rs @@ -1,6 +1,6 @@ -use crate::utils::prelude::*; -use crate::base::RegistryState; use super::prelude::*; +use crate::base::RegistryState; +use crate::utils::prelude::*; #[derive(Serialize, Clone, Debug, Default, Deserialize, EventContent)] #[ruma_event(type = "m.virto.apps", kind = GlobalAccountData)] diff --git a/core/src/base/app/app.rs b/core/src/base/app/app.rs index fc4bdae..9954ab5 100644 --- a/core/src/base/app/app.rs +++ b/core/src/base/app/app.rs @@ -1,101 +1,138 @@ use super::types::{ - Aggregate, AppInfo, AppRunnable, CbEventEmmiter, CommandSerializedEvelope, - EventEvelope, DomainEvent + AppInfo, AppRunnable, DomainEvent, EventEnvelope, SerializedCommandEnvelope, StateMachine, }; -use crate::{prelude::*, EventCommitedEvelope}; -use crate::{ - to_serialized_event_evelope, - RunnableError -}; +use crate::{prelude::*, CommittedEventEnvelope, ConstructableService, SerializedEventEnvelope}; +use crate::{to_serialized_event_envelope, RunnableError}; -pub struct App +struct AppBuilder where - A: Aggregate, + S: StateMachine, + S::Services: ConstructableService, + Args: Clone, { + args: Args, app_info: AppInfo, - services: A::Services, - aggregate: A + state_machine: PhantomData, +} + +impl AppBuilder +where + S: StateMachine, + S::Services: ConstructableService, + Args: Clone, +{ + fn new(app_info: AppInfo, args: Args) -> Self { + Self { + app_info, + args, + state_machine: Default::default(), + } + } + + fn run(&self, initial_state: Option) -> impl AppRunnable + '_ { + let state_machine: S = match (initial_state) { + Some(value) => serde_json::from_value(value).expect("Can not serialize State"), + None => S::default(), + }; + + let service = S::Services::new(self.args.clone()); + + App::new(&self.app_info, state_machine, service) + } +} + +pub struct App<'a, S> +where + S: StateMachine, +{ + app_info: &'a AppInfo, + services: S::Services, + state_machine: S, } -impl App where A: Aggregate { - // fn create(info: AppInfo) +impl<'a, S: StateMachine> App<'a, S> { + fn new(app_info: &'a AppInfo, state: S, services: S::Services) -> Self { + Self { + app_info, + services, + state_machine: state, + } + } } -impl AppRunnable for App +impl<'a, S> AppRunnable for App<'a, S> where - A: Aggregate, + S: StateMachine, { + fn snap_shot(&self) -> Value { + serde_json::to_value(&self.state_machine).expect("It must be a serializable state_machine") + } fn get_app_info(&self) -> &AppInfo { &self.app_info } - async fn apply(&mut self, event: EventCommitedEvelope) -> Result<(), RunnableError> { - let event: A::Event = serde_json::from_value(event.payload).map_err(|_| RunnableError::Unknown)?; - self.aggregate_mut().apply(event); + async fn apply(&mut self, event: CommittedEventEnvelope) -> Result<(), RunnableError> { + let event: S::Event = + serde_json::from_value(event.payload).map_err(|_| RunnableError::Unknown)?; + println!("{:?}", event); + + self.state_machine.apply(event); Ok(()) } async fn run_command( &self, - command: CommandSerializedEvelope, - ) -> Result<(), RunnableError> { - let mut cmd_obj: Map = Map::new(); - cmd_obj.insert(command.cmd_name.to_string(), command.cmd_payload); - println!("OBJ {:?}", cmd_obj); - let cmd: A::Command = serde_json::from_value(Value::Object(cmd_obj)).map_err(|_| RunnableError::Unknown)?; - println!("DONE {:?}", cmd); + command: SerializedCommandEnvelope, + ) -> Result, RunnableError> { + let cmd: S::Command = + serde_json::from_value(command.cmd_payload).map_err(|_| RunnableError::Unknown)?; + let events = self - .aggregate() + .state_machine .handle(cmd, &self.services) .await .map_err(|x| RunnableError::Unknown)?; - - let serialized_events: Vec = events - .iter() + Ok(events + .into_iter() .map(|e| { - to_serialized_event_evelope::( + to_serialized_event_envelope::( &self.app_info.id, &command.aggregate_id, &e, &command.metadata, ) }) - .collect(); - - Ok(serialized_events) + .collect()) } } - mod app_test { use std::process::Command; + use crate::{to_serialized_command_envelope, AppPermission, DomainCommand}; use async_std::test; - use crate::AppPermission; use super::*; - #[derive(Deserialize, Serialize, Debug)] enum TestCmd { A, - B + B, } #[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] enum TestEvent { A, - B(usize) + B(usize), } - #[derive(Debug)] enum TestError { A, - B + B, } impl core::fmt::Display for TestError { @@ -113,7 +150,7 @@ mod app_test { fn event_type(&self) -> String { match self { TestEvent::A => "A".into(), - TestEvent::B(_) => "B".into() + TestEvent::B(_) => "B".into(), } } @@ -122,26 +159,49 @@ mod app_test { } } + impl DomainCommand for TestCmd { + fn command_name(&self) -> String { + match self { + TestCmd::A => "A".into(), + TestCmd::B => "B".into(), + } + } + + fn command_payload(&self) -> Value { + serde_json::to_value(self).expect("Can not Seralize command") + } + } + #[derive(Serialize, Deserialize)] struct TestAggregate { - pub sum: usize + pub sum: usize, } impl Default for TestAggregate { fn default() -> Self { - Self { - sum: 0 - } + Self { sum: 0 } } } trait TestService { - #[virto(Http)] fn sign(&self) -> usize; } + #[derive(Deserialize, Clone)] + struct ServiceConfig { + url: String, + } + #[derive(Default)] - struct Service {} + struct Service { + url: String, + } + + impl Service { + fn new(args: ServiceConfig) -> Self { + Service { url: args.url } + } + } impl TestService for Service { fn sign(&self) -> usize { @@ -149,69 +209,92 @@ mod app_test { } } - fn to_evelop_cmd() -> CommandSerializedEvelope { - CommandSerializedEvelope { - aggregate_id: "test".into(), - app_id: "app_id".into(), - cmd_name: "A".into(), - cmd_payload: Value::Object(Map::new()), - metadata: HashMap::new() + fn to_envelop_cmd(cmd: TestCmd) -> SerializedCommandEnvelope { + to_serialized_command_envelope("0.0.1", "david", cmd, HashMap::new()) + } + + impl ConstructableService for Box { + type Args = ServiceConfig; + type Service = Box; + + fn new(args: Self::Args) -> Self::Service { + Box::new(Service { url: args.url }) } } - impl Aggregate for TestAggregate { + impl StateMachine for TestAggregate { type Command = TestCmd; type Event = TestEvent; type Error = TestError; type Services = Box; async fn handle( - &self, - command: Self::Command, - ctx: &Self::Services, - ) -> Result, Self::Error> { - + &self, + command: Self::Command, + ctx: &Self::Services, + ) -> Result, Self::Error> { match command { - TestCmd::A => Ok(vec![ - TestEvent::A, - ]), - TestCmd::B => Ok(vec![ - TestEvent::A, - TestEvent::B(service.sign()), - ]) + TestCmd::A => Ok(vec![TestEvent::A]), + TestCmd::B => Ok(vec![TestEvent::A, TestEvent::B(ctx.sign())]), } - } - // COMMIT - fn apply(&mut self, event: Self::Event) { match event { TestEvent::A => { - self.sum+=1; - }, + self.sum += 1; + } TestEvent::B(u) => { self.sum += u; } } } } - + fn mock_app_info() -> AppInfo { AppInfo { author: "foo".into(), description: "foo".into(), id: "foo".into(), - name: "helloo".into(), + name: "hello".into(), permissions: vec![], - version: "0.0.1".into() + version: "0.0.1".into(), + } + } + + fn to_committed_event( + sequence: usize, + event: SerializedEventEnvelope, + ) -> CommittedEventEnvelope { + CommittedEventEnvelope { + aggregate_id: event.aggregate_id, + app_id: event.app_id, + event_type: event.event_type, + event_version: event.event_version, + metadata: event.metadata, + payload: event.payload, + sequence, } } #[async_std::test] async fn setup_app() { - let wallet = TestAggregate::default(); let info = mock_app_info(); - let mut app = App::::new(info, Box::new(Service::default())); + let appSpawner = AppBuilder::::new( + info, + ServiceConfig { url: "http".into() }, + ); + let mut app = appSpawner.run(None); + + let events = app + .run_command(to_envelop_cmd(TestCmd::A)) + .await + .expect("hello"); + + for (seq, e) in events.into_iter().enumerate() { + app.apply(to_committed_event(seq, e)).await; + } + + println!("{:?}", app.snap_shot()); } -} \ No newline at end of file +} diff --git a/core/src/base/app/mod.rs b/core/src/base/app/mod.rs index 849c772..fc93621 100644 --- a/core/src/base/app/mod.rs +++ b/core/src/base/app/mod.rs @@ -1,7 +1,7 @@ mod app; mod query; -pub mod types; pub mod test; +pub mod types; pub use app::*; pub use query::*; diff --git a/core/src/base/app/query.rs b/core/src/base/app/query.rs index 9a034e9..e0061c4 100644 --- a/core/src/base/app/query.rs +++ b/core/src/base/app/query.rs @@ -1,4 +1,4 @@ -use super::types::{Aggregate, DomainEvent, EventEnvelope}; +use super::types::{DomainEvent, EventEnvelope, StateMachine}; use crate::utils::prelude::*; pub trait Query: Send + Sync @@ -7,4 +7,3 @@ where { async fn dispatch(&self, aggregate_id: &str, events: &[EventEnvelope]); } - diff --git a/core/src/base/app/test/executor.rs b/core/src/base/app/test/executor.rs index 2c4af9e..80a5e2d 100644 --- a/core/src/base/app/test/executor.rs +++ b/core/src/base/app/test/executor.rs @@ -1,54 +1,59 @@ -use super::super::types::Aggregate; -use super::validator::AggregateResultValidator; +use crate::ConstructableService; + +use super::super::types::StateMachine; +use super::validator::StateMachineResultValidator; use tokio::main; -pub struct AggregateTestExecutor +pub struct StateMachineTestExecutor where - A: Aggregate, + A: StateMachine, { events: Vec, service: A::Services, } -impl AggregateTestExecutor +impl StateMachineTestExecutor where - A: Aggregate, + S: StateMachine, { - pub fn when(self, command: A::Command) -> AggregateResultValidator { - let result = when::(self.events, command, self.service); - AggregateResultValidator::new(result) + pub fn when(self, command: S::Command) -> StateMachineResultValidator { + let result = when::(self.events, command, self.service); + StateMachineResultValidator::new(result) } - pub async fn when_async(self, command: A::Command) -> AggregateResultValidator { - let mut aggregate = A::default(); + pub async fn when_async(self, command: S::Command) -> StateMachineResultValidator { + let mut aggregate = S::default(); for event in self.events { aggregate.apply(event); } - let result = aggregate.handle(command, &self.service).await; - AggregateResultValidator::new(result) + let result = aggregate + .handle(command, &self.service) + .await + .map(|x| x.into_iter().collect()); + StateMachineResultValidator::::new(result) } #[must_use] - pub fn and(self, new_events: Vec) -> Self { + pub fn and(self, new_events: Vec) -> Self { let mut events = self.events; events.extend(new_events); let service = self.service; - AggregateTestExecutor { events, service } + StateMachineTestExecutor { events, service } } - pub(crate) fn new(events: Vec, service: A::Services) -> Self { + pub(crate) fn new(events: Vec, service: S::Services) -> Self { Self { events, service } } } #[tokio::main(flavor = "current_thread")] -async fn when( - events: Vec, - command: A::Command, - service: A::Services, -) -> Result, A::Error> { - let mut aggregate = A::default(); +async fn when( + events: Vec, + command: S::Command, + service: S::Services, +) -> Result, S::Error> { + let mut aggregate = S::default(); for event in events { aggregate.apply(event); } diff --git a/core/src/base/app/test/framework.rs b/core/src/base/app/test/framework.rs index e75b5bf..feb65cf 100644 --- a/core/src/base/app/test/framework.rs +++ b/core/src/base/app/test/framework.rs @@ -1,32 +1,36 @@ +use std::env::Args; + use async_trait::async_trait; -use super::super::types::Aggregate; -use super::executor::AggregateTestExecutor; +use crate::ConstructableService; + +use super::super::types::StateMachine; +use super::executor::StateMachineTestExecutor; /// A framework for rigorously testing the aggregate logic, one of the *most important* /// parts of any DDD system. -pub struct TestFramework { - service: A::Services, +pub struct TestFramework { + service: S::Services, } -impl TestFramework { +impl TestFramework { /// Create a test framework using the provided service. - pub fn with(service: A::Services) -> Self { + pub fn with(service: S::Services) -> Self { Self { service } } } -impl TestFramework +impl TestFramework where - A: Aggregate, + S: StateMachine, { #[must_use] - pub fn given_no_previous_events(self) -> AggregateTestExecutor { - AggregateTestExecutor::new(Vec::new(), self.service) + pub fn given_no_previous_events(self) -> StateMachineTestExecutor { + StateMachineTestExecutor::new(Vec::new(), self.service) } #[must_use] - pub fn given(self, events: Vec) -> AggregateTestExecutor { - AggregateTestExecutor::new(events, self.service) + pub fn given(self, events: Vec) -> StateMachineTestExecutor { + StateMachineTestExecutor::new(events, self.service) } } diff --git a/core/src/base/app/test/validator.rs b/core/src/base/app/test/validator.rs index ce691ba..da8ccce 100644 --- a/core/src/base/app/test/validator.rs +++ b/core/src/base/app/test/validator.rs @@ -1,14 +1,16 @@ -use super::super::types::Aggregate; +use crate::ConstructableService; -pub struct AggregateResultValidator +use super::super::types::StateMachine; + +pub struct StateMachineResultValidator where - A: Aggregate, + S: StateMachine, { - result: Result, A::Error>, + result: Result, S::Error>, } -impl AggregateResultValidator { - pub fn then_expect_events(self, expected_events: Vec) { +impl StateMachineResultValidator { + pub fn then_expect_events(self, expected_events: Vec) { let events = match self.result { Ok(expected_events) => expected_events, Err(err) => { @@ -27,17 +29,17 @@ impl AggregateResultValidator { }; } - pub fn inspect_result(self) -> Result, A::Error> { + pub fn inspect_result(self) -> Result, S::Error> { self.result } - pub(crate) fn new(result: Result, A::Error>) -> Self { + pub(crate) fn new(result: Result, S::Error>) -> Self { Self { result } } } -impl AggregateResultValidator +impl StateMachineResultValidator where - A: Aggregate, + A: StateMachine, A::Error: PartialEq, { pub fn then_expect_error(self, expected_error: A::Error) { diff --git a/core/src/base/app/types.rs b/core/src/base/app/types.rs index 5fec933..8cef51e 100644 --- a/core/src/base/app/types.rs +++ b/core/src/base/app/types.rs @@ -1,14 +1,31 @@ use crate::utils::prelude::*; -pub trait DomainEvent: - Serialize + DeserializeOwned + Clone + Debug + Send -{ +pub trait DomainEvent: Serialize + DeserializeOwned + Clone + Debug + Send { fn event_type(&self) -> String; fn event_version(&self) -> String; } +pub trait DomainCommand { + fn command_name(&self) -> String; + fn command_payload(&self) -> Value; +} + +pub trait ConstructableService { + type Args: DeserializeOwned + Clone; + type Service; + + fn new(args: Self::Args) -> Self::Service; +} + +// impl ConstructableService for Box where T: ConstructableService{ +// type Args = T::Args; -pub trait Aggregate: Default + Serialize + DeserializeOwned + Send { +// fn new(args: Self::Args) -> Self { +// Box::new(T::new(args)) +// } +// } + +pub trait StateMachine: Default + Serialize + DeserializeOwned + Send { type Command: DeserializeOwned + Send + Debug + Serialize; type Event: DomainEvent + Send + PartialEq; @@ -21,14 +38,13 @@ pub trait Aggregate: Default + Serialize + DeserializeOwned + Send { &self, command: Self::Command, service: &Self::Services, - ) -> Result, Self::Error>; // chante IntoInter + ) -> Result, Self::Error>; fn apply(&mut self, event: Self::Event); } - #[derive(Serialize, Deserialize)] -pub struct CommandSerializedEvelope { +pub struct SerializedCommandEnvelope { pub app_id: String, // app-id pub aggregate_id: String, pub metadata: HashMap, // { who, req_id } @@ -36,7 +52,6 @@ pub struct CommandSerializedEvelope { pub cmd_payload: Value, } - #[derive(Debug)] pub struct EventEnvelope where @@ -64,43 +79,57 @@ impl Clone for EventEnvelope { } #[derive(Clone, Debug, PartialEq, Eq)] -pub struct EventEvelope { +pub struct CommittedEventEnvelope { pub app_id: String, pub aggregate_id: String, pub event_type: String, pub event_version: String, + pub sequence: usize, // after commit we know the squence for that event pub payload: Value, pub metadata: Value, } - #[derive(Clone, Debug, PartialEq, Eq)] -pub struct EventCommitedEvelope { +pub struct SerializedEventEnvelope { pub app_id: String, pub aggregate_id: String, pub event_type: String, pub event_version: String, - pub sequence: usize, // after commit we know the squence for that event pub payload: Value, pub metadata: Value, } -pub fn to_serialized_event_evelope( +pub fn to_serialized_event_envelope( app_id: impl Into, aggregate_id: impl Into, event: &E, metadata: &HashMap, -) -> EventEvelope { - EventEvelope { +) -> SerializedEventEnvelope { + SerializedEventEnvelope { app_id: app_id.into(), aggregate_id: aggregate_id.into(), - metadata: serde_json::to_value(metadata).expect("invalid metadata"), // exploted - payload: serde_json::to_value(event).expect("invalid metadata"), // exploted + metadata: serde_json::to_value(metadata).expect("invalid metadata"), + payload: serde_json::to_value(event).expect("invalid metadata"), event_type: event.event_type(), event_version: event.event_version(), } } +pub fn to_serialized_command_envelope( + app_id: impl Into, + aggregate_id: impl Into, + command: C, + metadata: HashMap, +) -> SerializedCommandEnvelope { + SerializedCommandEnvelope { + aggregate_id: aggregate_id.into(), + app_id: app_id.into(), + cmd_name: command.command_name(), + cmd_payload: command.command_payload(), + metadata, + } +} + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct AppPermission { pub name: String, @@ -110,7 +139,6 @@ pub struct AppPermission { pub events: Vec, } - #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct AppInfo { pub id: String, @@ -129,9 +157,12 @@ pub enum RunnableError { pub trait AppRunnable { fn get_app_info(&self) -> &AppInfo; - async fn apply(&mut self, event: EventCommitedEvelope) -> Result<(), RunnableError>; + fn snap_shot(&self) -> Value; - async fn run_command(&self, command: CommandSerializedEvelope) - -> Result, RunnableError>; -} + async fn apply(&mut self, event: CommittedEventEnvelope) -> Result<(), RunnableError>; + async fn run_command( + &self, + command: SerializedCommandEnvelope, + ) -> Result, RunnableError>; +} diff --git a/core/src/sdk.rs b/core/src/sdk.rs index 3827d44..fda2b6b 100644 --- a/core/src/sdk.rs +++ b/core/src/sdk.rs @@ -1,6 +1,5 @@ use crate::{backend::matrix::MatrixRegistry, utils::prelude::*}; - #[derive(Debug)] pub enum AuthError { WrongCredentials, @@ -193,10 +192,11 @@ mod client_store_test { use super::*; use crate::utils::prelude::*; - use crate::std::wallet; use crate::base::app::AppInfo; use crate::base::AppRunnable; - use crate::std::wallet::{WalletApi, WalletResult, WalletServices, Wallet}; + use crate::std::wallet; + use crate::std::wallet::{Wallet, WalletApi, WalletResult}; + use crate::ConstructableService; use libwallet::Message; use tokio::test; @@ -206,7 +206,11 @@ mod client_store_test { #[async_trait::async_trait] impl AuthenticatorBuilder for AuthConnectorMock { - async fn auth(&self, _: String, client: Box) -> Result, AuthError> { + async fn auth( + &self, + _: String, + client: Box, + ) -> Result, AuthError> { Ok(client) } } @@ -234,7 +238,7 @@ mod client_store_test { .expect("error at building"); } - type WalletAggregate = Wallet; + type WalletAggregate = Wallet; #[tokio::test] async fn craft_app() { @@ -269,6 +273,15 @@ mod client_store_test { #[derive(Default)] struct MockWalletService; + impl ConstructableService for MockWalletService { + type Args = (); + type Service = MockWalletService; + + fn new(args: Self::Args) -> Self::Service { + MockWalletService + } + } + #[async_trait] impl WalletApi for MockWalletService { async fn sign<'p>(&self, payload: &'p [u8]) -> WalletResult { diff --git a/core/src/std/wallet/aggregate.rs b/core/src/std/wallet/aggregate.rs index 2cc37ba..846bf6a 100644 --- a/core/src/std/wallet/aggregate.rs +++ b/core/src/std/wallet/aggregate.rs @@ -1,22 +1,18 @@ -use super::{ - Message, WalletApi, WalletCommand, WalletError, WalletEvent, WalletResult, WalletServices, -}; -use crate::app::Aggregate; +use super::{Message, WalletApi, WalletCommand, WalletError, WalletEvent, WalletResult}; +use crate::app::StateMachine; use crate::utils::prelude::*; #[derive(Deserialize, Serialize, Debug)] -pub struct Wallet { +pub struct Wallet { device_id: Option, pending_messages: Vec, - #[serde(skip_serializing)] - phantom: PhantomData, } -impl Aggregate for Wallet { +impl StateMachine for Wallet { type Command = WalletCommand; type Event = WalletEvent; type Error = WalletError; - type Services = WalletServices; + type Services = Box; fn apply(&mut self, event: Self::Event) { match event { @@ -40,33 +36,29 @@ impl Aggregate for Wallet { } WalletCommand::Sign() => { if self.pending_messages.len() == 0 { - return Err(WalletError::NoMesssagesToSign); + return Err(WalletError::NoMessagesToSign); } - let messagess_signatures = + let messages_signatures = future::try_join_all(self.pending_messages.iter().map(|m: &Message| async { Ok(( - svc.services - .sign(m) - .await - .map_err(|_| WalletError::Unknown)?, + svc.sign(m).await.map_err(|_| WalletError::Unknown)?, m.to_owned(), )) })) .await?; - Ok(vec![WalletEvent::Signed(messagess_signatures)]) + Ok(vec![WalletEvent::Signed(messages_signatures)]) } } } } -impl Default for Wallet { +impl Default for Wallet { fn default() -> Self { Self { device_id: None, pending_messages: vec![], - phantom: PhantomData, } } } @@ -77,33 +69,37 @@ mod wallet_test { use crate::base::app::test::TestFramework; use crate::utils::prelude::*; - type WalletService = TestFramework>; + struct SimpleWalletArgs { + pass: String, + } + + type WalletService = TestFramework; #[test] fn add_pending_tx() { let message = Message::try_from([0u8, 1u8, 2u8].as_slice()).expect("can not convert"); - WalletService::with(WalletServices::new(MockWalletService::default())) + WalletService::with(Box::new(MockWalletService::default())) .given_no_previous_events() .when(WalletCommand::AddMessageToSign(message.clone())) .then_expect_events(vec![WalletEvent::AddedMessageToSign(message)]); } #[async_std::test] - async fn no_messsages_to_sign() { + async fn no_messages_to_sign() { let message = Message::try_from([0u8, 1u8, 2u8].as_slice()).expect("can not convert"); - let executor = WalletService::with(WalletServices::new(MockWalletService::default())) + let executor = WalletService::with(Box::new(MockWalletService::default())) .given_no_previous_events() .when(WalletCommand::Sign()) - .then_expect_error(WalletError::NoMesssagesToSign); + .then_expect_error(WalletError::NoMessagesToSign); } #[async_std::test] async fn sign_tx_queues() { let message = Message::try_from([0u8, 1u8, 2u8].as_slice()).expect("can not convert"); - let executor = WalletService::with(WalletServices::new(MockWalletService::default())) + let executor = WalletService::with(Box::new(MockWalletService::default())) .given(vec![WalletEvent::AddedMessageToSign(message.clone())]); let validator = executor.when_async(WalletCommand::Sign()).await; diff --git a/core/src/std/wallet/events.rs b/core/src/std/wallet/events.rs index 98e690e..e05edd7 100644 --- a/core/src/std/wallet/events.rs +++ b/core/src/std/wallet/events.rs @@ -1,4 +1,4 @@ -use super::{Message, WalletApiSignedPayloadBounds}; +use super::Message; use crate::app::DomainEvent; use crate::utils::prelude::*; @@ -8,18 +8,17 @@ pub enum WalletEvent { Signed(Vec<(Message, Message)>), } - #[derive(Deserialize, Clone, Debug, PartialEq)] pub enum WalletError { Unknown, - NoMesssagesToSign, + NoMessagesToSign, } impl core::fmt::Display for WalletError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Unknown => write!(f, "Unknown"), - Self::NoMesssagesToSign => write!(f, "NoMesssagesToSign"), + Self::NoMessagesToSign => write!(f, "NoMessagesToSign"), } } } diff --git a/core/src/std/wallet/mod.rs b/core/src/std/wallet/mod.rs index 5b00b32..a194cd0 100644 --- a/core/src/std/wallet/mod.rs +++ b/core/src/std/wallet/mod.rs @@ -1,9 +1,8 @@ mod aggregate; mod commands; mod events; -mod types; mod services; - +mod types; pub use aggregate::*; pub use commands::*; diff --git a/core/src/std/wallet/services.rs b/core/src/std/wallet/services.rs index 4d409ed..7c198c2 100644 --- a/core/src/std/wallet/services.rs +++ b/core/src/std/wallet/services.rs @@ -1,8 +1,10 @@ use async_trait::async_trait; -use libwallet::Message; use core::fmt::Debug; +use libwallet::Message; use serde::{de::DeserializeOwned, Serialize}; +use crate::ConstructableService; + pub enum SignerError { Unknown, WrongCredentials, @@ -10,21 +12,12 @@ pub enum SignerError { } pub type WalletResult = Result; -pub trait WalletApiSignedPayloadBounds = - Sync + Send + DeserializeOwned + Serialize + PartialEq + Clone + Debug; -trait WA = WalletApi; - -pub struct WalletServices { - pub services: A, -} - -impl WalletServices { - pub fn new(services: A) -> Self { - Self { services } - } -} #[async_trait] pub trait WalletApi { async fn sign<'p>(&self, payload: &'p [u8]) -> WalletResult; } + +pub struct WalletCreation { + vault: String, +} diff --git a/core/src/utils.rs b/core/src/utils.rs index 535f820..6be862d 100644 --- a/core/src/utils.rs +++ b/core/src/utils.rs @@ -5,9 +5,9 @@ pub mod prelude { pub use matrix_sdk::{config::SyncSettings as MatrixSyncSettings, Client as MatrixClient}; pub use serde::{de::DeserializeOwned, Deserialize, Serialize}; - pub use serde_json::{ Value, Map }; + pub use serde_json::{Map, Value}; pub use url::Url; // special type; - pub use std::collections::HashMap; pub use core::fmt::Debug; + pub use std::collections::HashMap; } diff --git a/core/.DS_Store b/libwallet/.DS_Store similarity index 94% rename from core/.DS_Store rename to libwallet/.DS_Store index b994cc1..106ba4f 100644 Binary files a/core/.DS_Store and b/libwallet/.DS_Store differ diff --git a/.DS_Store b/sube/.DS_Store similarity index 87% rename from .DS_Store rename to sube/.DS_Store index 6ce5fc3..5f01162 100644 Binary files a/.DS_Store and b/sube/.DS_Store differ