From 5189bcf8721b373d6e9f5665d579dbb2ecf90dff Mon Sep 17 00:00:00 2001 From: osmaczko <33099791+osmaczko@users.noreply.github.com> Date: Thu, 26 Mar 2026 21:47:00 +0100 Subject: [PATCH] wip --- crates/client/src/delivery.rs | 18 ----------------- crates/client/src/lib.rs | 5 ++++- crates/client/src/platform.rs | 8 ++++++++ crates/client/src/platforms/mod.rs | 1 + crates/client/src/platforms/test/delivery.rs | 21 ++++++++++++++++++++ crates/client/src/platforms/test/mod.rs | 21 ++++++++++++++++++++ crates/client/tests/alice_and_bob.rs | 21 +++++++++++--------- 7 files changed, 67 insertions(+), 28 deletions(-) create mode 100644 crates/client/src/platform.rs create mode 100644 crates/client/src/platforms/mod.rs create mode 100644 crates/client/src/platforms/test/delivery.rs create mode 100644 crates/client/src/platforms/test/mod.rs diff --git a/crates/client/src/delivery.rs b/crates/client/src/delivery.rs index b93a367..4a61d62 100644 --- a/crates/client/src/delivery.rs +++ b/crates/client/src/delivery.rs @@ -1,24 +1,6 @@ -use std::collections::VecDeque; - use libchat::AddressedEnvelope; pub trait DeliveryService { type Error: std::fmt::Debug; fn deliver(&mut self, envelope: AddressedEnvelope) -> Result<(), Self::Error>; } - -/// In-memory delivery for tests. Envelopes are pushed to `inbox`; tests pop -/// them and feed bytes to the peer's `receive()`. -#[derive(Default)] -pub struct InMemoryDelivery { - pub inbox: VecDeque>, -} - -impl DeliveryService for InMemoryDelivery { - type Error = std::convert::Infallible; - - fn deliver(&mut self, envelope: AddressedEnvelope) -> Result<(), Self::Error> { - self.inbox.push_back(envelope.data); - Ok(()) - } -} diff --git a/crates/client/src/lib.rs b/crates/client/src/lib.rs index e3c6186..6693f49 100644 --- a/crates/client/src/lib.rs +++ b/crates/client/src/lib.rs @@ -1,10 +1,13 @@ mod client; mod delivery; mod errors; +mod platform; +pub mod platforms; pub use client::ChatClient; -pub use delivery::{DeliveryService, InMemoryDelivery}; +pub use delivery::DeliveryService; pub use errors::ClientError; +pub use platform::Platform; // Re-export types callers need to interact with ChatClient pub use libchat::{ContentData, ConversationIdOwned, StorageConfig}; diff --git a/crates/client/src/platform.rs b/crates/client/src/platform.rs new file mode 100644 index 0000000..f1b8344 --- /dev/null +++ b/crates/client/src/platform.rs @@ -0,0 +1,8 @@ +use crate::{client::ChatClient, delivery::DeliveryService}; + +pub trait Platform { + type Delivery: DeliveryService; + type Error: std::fmt::Debug; + + fn into_client(self, name: impl Into) -> Result, Self::Error>; +} diff --git a/crates/client/src/platforms/mod.rs b/crates/client/src/platforms/mod.rs new file mode 100644 index 0000000..7b788c2 --- /dev/null +++ b/crates/client/src/platforms/mod.rs @@ -0,0 +1 @@ +pub mod test; diff --git a/crates/client/src/platforms/test/delivery.rs b/crates/client/src/platforms/test/delivery.rs new file mode 100644 index 0000000..3215811 --- /dev/null +++ b/crates/client/src/platforms/test/delivery.rs @@ -0,0 +1,21 @@ +use std::collections::VecDeque; + +use libchat::AddressedEnvelope; + +use crate::delivery::DeliveryService; + +/// Mock delivery for TestPlatform. Envelopes are pushed to `inbox`; tests pop +/// them manually and feed bytes into the peer's `receive()`. +#[derive(Default)] +pub struct MockDelivery { + pub inbox: VecDeque>, +} + +impl DeliveryService for MockDelivery { + type Error = std::convert::Infallible; + + fn deliver(&mut self, envelope: AddressedEnvelope) -> Result<(), Self::Error> { + self.inbox.push_back(envelope.data); + Ok(()) + } +} diff --git a/crates/client/src/platforms/test/mod.rs b/crates/client/src/platforms/test/mod.rs new file mode 100644 index 0000000..a1131b0 --- /dev/null +++ b/crates/client/src/platforms/test/mod.rs @@ -0,0 +1,21 @@ +mod delivery; + +pub use delivery::MockDelivery; + +use crate::{client::ChatClient, platform::Platform}; + +/// TestEngine platform: ephemeral identity, in-memory persistence, mock delivery. +/// +/// Suitable for unit/integration tests and local experimentation. +/// Maps to the "Platform: TestEngine" box in the architecture diagram. +pub struct TestPlatform; + +impl Platform for TestPlatform { + type Delivery = MockDelivery; + type Error = std::convert::Infallible; + + fn into_client(self, name: impl Into) -> Result, Self::Error> { + // ChatClient::new uses Context::new_with_name → in-memory storage + ephemeral identity + Ok(ChatClient::new(name, MockDelivery::default())) + } +} diff --git a/crates/client/tests/alice_and_bob.rs b/crates/client/tests/alice_and_bob.rs index b4ce971..145dc79 100644 --- a/crates/client/tests/alice_and_bob.rs +++ b/crates/client/tests/alice_and_bob.rs @@ -1,9 +1,14 @@ -use client::{ChatClient, ContentData, ConversationIdOwned, InMemoryDelivery}; +use client::platforms::test::{MockDelivery, TestPlatform}; +use client::{ChatClient, ContentData, ConversationIdOwned, Platform, StorageConfig}; use std::sync::Arc; +fn new_client(name: &str) -> ChatClient { + TestPlatform.into_client(name).unwrap() +} + fn pop_and_receive( - sender: &mut ChatClient, - receiver: &mut ChatClient, + sender: &mut ChatClient, + receiver: &mut ChatClient, ) -> Option { let raw = sender.delivery_mut().inbox.pop_front().expect("expected envelope"); receiver.receive(&raw).expect("receive failed") @@ -11,8 +16,8 @@ fn pop_and_receive( #[test] fn alice_bob_message_exchange() { - let mut alice = ChatClient::new("alice", InMemoryDelivery::default()); - let mut bob = ChatClient::new("bob", InMemoryDelivery::default()); + let mut alice = new_client("alice"); + let mut bob = new_client("bob"); // Exchange intro bundles out-of-band let bob_bundle = bob.create_intro_bundle().unwrap(); @@ -55,17 +60,15 @@ fn alice_bob_message_exchange() { #[test] fn open_persistent_client() { - use client::StorageConfig; - let dir = tempfile::tempdir().unwrap(); let db_path = dir.path().join("test.db").to_string_lossy().to_string(); let config = StorageConfig::File(db_path); - let client1 = ChatClient::open("alice", config.clone(), InMemoryDelivery::default()).unwrap(); + let client1 = ChatClient::open("alice", config.clone(), MockDelivery::default()).unwrap(); let name1 = client1.installation_name().to_string(); drop(client1); - let client2 = ChatClient::open("alice", config, InMemoryDelivery::default()).unwrap(); + let client2 = ChatClient::open("alice", config, MockDelivery::default()).unwrap(); let name2 = client2.installation_name().to_string(); assert_eq!(name1, name2, "installation name should persist across restarts");