From 6c54bbd79de5393dc479c323c4b0f041844485e6 Mon Sep 17 00:00:00 2001 From: kaichaosun Date: Tue, 3 Feb 2026 12:39:10 +0800 Subject: [PATCH 1/7] chore: refactor conversations --- conversations/src/context.rs | 10 +++--- .../common.rs} | 19 +++++------ conversations/src/conversation/group_test.rs | 33 ------------------- conversations/src/conversation/mod.rs | 2 ++ conversations/src/conversation/privatev1.rs | 5 +-- conversations/src/inbox/inbox.rs | 7 ++-- 6 files changed, 24 insertions(+), 52 deletions(-) rename conversations/src/{conversation.rs => conversation/common.rs} (85%) delete mode 100644 conversations/src/conversation/group_test.rs create mode 100644 conversations/src/conversation/mod.rs diff --git a/conversations/src/context.rs b/conversations/src/context.rs index f709a09..d3e4d8e 100644 --- a/conversations/src/context.rs +++ b/conversations/src/context.rs @@ -1,7 +1,8 @@ use std::{collections::HashMap, rc::Rc, sync::Arc}; use crate::{ - conversation::{ConversationStore, Convo, Id}, + // conversation::{ConversationStore, Convo, Id}, + conversation::common::{ConversationStore, Convo, HasConversationId}, errors::ChatError, identity::Identity, inbox::Inbox, @@ -99,7 +100,7 @@ impl Context { Ok(Introduction::from(pkb).into()) } - fn add_convo(&mut self, convo: impl Convo + Id + 'static) -> ConvoHandle { + fn add_convo(&mut self, convo: impl Convo + HasConversationId + 'static) -> ConvoHandle { let handle = self.next_convo_handle; self.next_convo_handle += 1; let convo_id = self.store.insert_convo(convo); @@ -125,14 +126,15 @@ impl Context { #[cfg(test)] mod tests { + use crate::conversation::privatev1::PrivateV1Convo; + use super::*; - use crate::conversation::GroupTestConvo; #[test] fn convo_store_get() { let mut store: ConversationStore = ConversationStore::new(); - let new_convo = GroupTestConvo::new(); + let new_convo = PrivateV1Convo::new([0; 32].into()); let convo_id = store.insert_convo(new_convo); let convo = store.get_mut(&convo_id).ok_or_else(|| 0); diff --git a/conversations/src/conversation.rs b/conversations/src/conversation/common.rs similarity index 85% rename from conversations/src/conversation.rs rename to conversations/src/conversation/common.rs index 61a5d79..24c7c12 100644 --- a/conversations/src/conversation.rs +++ b/conversations/src/conversation/common.rs @@ -8,18 +8,18 @@ use crate::types::{AddressedEncryptedPayload, ContentData}; pub type ConversationId<'a> = &'a str; pub type ConversationIdOwned = Arc; -pub trait Id: Debug { +pub trait HasConversationId: Debug { fn id(&self) -> ConversationId; } -pub trait ConvoFactory: Id + Debug { +pub trait ConvoFactory: HasConversationId + Debug { fn handle_frame( &mut self, encoded_payload: &[u8], ) -> Result<(Box, Vec), ChatError>; } -pub trait Convo: Id + Debug { +pub trait Convo: HasConversationId + Debug { fn send_message(&mut self, content: &[u8]) -> Result, ChatError>; @@ -39,7 +39,10 @@ impl ConversationStore { } } - pub fn insert_convo(&mut self, conversation: impl Convo + Id + 'static) -> ConversationIdOwned { + pub fn insert_convo( + &mut self, + conversation: impl Convo + HasConversationId + 'static, + ) -> ConversationIdOwned { let key: ConversationIdOwned = Arc::from(conversation.id()); self.conversations .insert(key.clone(), Box::new(conversation)); @@ -48,7 +51,7 @@ impl ConversationStore { pub fn register_factory( &mut self, - handler: impl ConvoFactory + Id + 'static, + handler: impl ConvoFactory + HasConversationId + 'static, ) -> ConversationIdOwned { let key: ConversationIdOwned = Arc::from(handler.id()); self.factories.insert(key.clone(), Box::new(handler)); @@ -75,9 +78,3 @@ impl ConversationStore { self.factories.keys().cloned() } } - -mod group_test; -mod privatev1; - -pub use group_test::GroupTestConvo; -pub use privatev1::PrivateV1Convo; diff --git a/conversations/src/conversation/group_test.rs b/conversations/src/conversation/group_test.rs deleted file mode 100644 index 934ab1c..0000000 --- a/conversations/src/conversation/group_test.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::{ - conversation::{ChatError, ConversationId, Convo, Id}, - types::AddressedEncryptedPayload, -}; - -#[derive(Debug)] -pub struct GroupTestConvo {} - -impl GroupTestConvo { - pub fn new() -> Self { - Self {} - } -} - -impl Id for GroupTestConvo { - fn id(&self) -> ConversationId { - // implementation - "grouptest" - } -} - -impl Convo for GroupTestConvo { - fn send_message( - &mut self, - _content: &[u8], - ) -> Result, ChatError> { - Ok(vec![]) - } - - fn remote_id(&self) -> String { - self.id().to_string() - } -} diff --git a/conversations/src/conversation/mod.rs b/conversations/src/conversation/mod.rs new file mode 100644 index 0000000..a2c5e4b --- /dev/null +++ b/conversations/src/conversation/mod.rs @@ -0,0 +1,2 @@ +pub mod common; +pub mod privatev1; diff --git a/conversations/src/conversation/privatev1.rs b/conversations/src/conversation/privatev1.rs index c40c18e..2bf45db 100644 --- a/conversations/src/conversation/privatev1.rs +++ b/conversations/src/conversation/privatev1.rs @@ -6,7 +6,8 @@ use crypto::SecretKey; use prost::{Message, bytes::Bytes}; use crate::{ - conversation::{ChatError, ConversationId, Convo, Id}, + conversation::common::{ConversationId, Convo, HasConversationId}, + errors::ChatError, types::AddressedEncryptedPayload, utils::timestamp_millis, }; @@ -34,7 +35,7 @@ impl PrivateV1Convo { } } -impl Id for PrivateV1Convo { +impl HasConversationId for PrivateV1Convo { fn id(&self) -> ConversationId { // TODO: implementation "private_v1_convo_id" diff --git a/conversations/src/inbox/inbox.rs b/conversations/src/inbox/inbox.rs index f117a3c..a6f0ccb 100644 --- a/conversations/src/inbox/inbox.rs +++ b/conversations/src/inbox/inbox.rs @@ -8,8 +8,11 @@ use std::rc::Rc; use crypto::{PrekeyBundle, SecretKey}; use crate::context::Introduction; -use crate::conversation::{ChatError, ConversationId, Convo, ConvoFactory, Id, PrivateV1Convo}; +use crate::conversation::common::{ConversationId, Convo, ConvoFactory, HasConversationId}; +use crate::conversation::privatev1::PrivateV1Convo; +// use crate::conversation::{ChatError, ConversationId, Convo, ConvoFactory, Id, PrivateV1Convo}; use crate::crypto::{Blake2b128, CopyBytes, Digest, PublicKey, StaticSecret}; +use crate::errors::ChatError; use crate::identity::Identity; use crate::inbox::handshake::InboxHandshake; use crate::proto; @@ -200,7 +203,7 @@ impl Inbox { } } -impl Id for Inbox { +impl HasConversationId for Inbox { fn id(&self) -> ConversationId { &self.local_convo_id } From 2a9fe1c8e5be1c316bd6960b4f3617f2c758c3dc Mon Sep 17 00:00:00 2001 From: kaichaosun Date: Tue, 3 Feb 2026 13:01:26 +0800 Subject: [PATCH 2/7] chore: use inbound and outbound for session --- conversations/src/context.rs | 26 +++++--- conversations/src/conversation/common.rs | 68 +++++++++++---------- conversations/src/conversation/privatev1.rs | 6 +- conversations/src/inbox/inbox.rs | 18 +++--- 4 files changed, 61 insertions(+), 57 deletions(-) diff --git a/conversations/src/context.rs b/conversations/src/context.rs index d3e4d8e..97f70c9 100644 --- a/conversations/src/context.rs +++ b/conversations/src/context.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, rc::Rc, sync::Arc}; use crate::{ // conversation::{ConversationStore, Convo, Id}, - conversation::common::{ConversationStore, Convo, HasConversationId}, + conversation::common::{HasConversationId, OutboundSession, SessionRegistry}, errors::ChatError, identity::Identity, inbox::Inbox, @@ -21,7 +21,7 @@ pub type ConvoHandle = u32; // Ctx manages lifetimes of objects to process and generate payloads. pub struct Context { _identity: Rc, - store: ConversationStore, + store: SessionRegistry, inbox: Inbox, buf_size: usize, convo_handle_map: HashMap>, @@ -34,7 +34,7 @@ impl Context { let inbox = Inbox::new(Rc::clone(&identity)); // Self { _identity: identity, - store: ConversationStore::new(), + store: SessionRegistry::new(), inbox, buf_size: 0, convo_handle_map: HashMap::new(), @@ -100,17 +100,23 @@ impl Context { Ok(Introduction::from(pkb).into()) } - fn add_convo(&mut self, convo: impl Convo + HasConversationId + 'static) -> ConvoHandle { + fn add_convo( + &mut self, + convo: impl OutboundSession + HasConversationId + 'static, + ) -> ConvoHandle { let handle = self.next_convo_handle; self.next_convo_handle += 1; - let convo_id = self.store.insert_convo(convo); + let convo_id = self.store.insert_session(convo); self.convo_handle_map.insert(handle, convo_id); handle } // Returns a mutable reference to a Convo for a given ConvoHandle - fn get_convo_mut(&mut self, handle: ConvoHandle) -> Result<&mut dyn Convo, ChatError> { + fn get_convo_mut( + &mut self, + handle: ConvoHandle, + ) -> Result<&mut dyn OutboundSession, ChatError> { let convo_id = self .convo_handle_map .get(&handle) @@ -118,7 +124,7 @@ impl Context { .clone(); self.store - .get_mut(&convo_id) + .get_mut_session(&convo_id) .ok_or_else(|| ChatError::NoConvo(handle)) } } @@ -132,12 +138,12 @@ mod tests { #[test] fn convo_store_get() { - let mut store: ConversationStore = ConversationStore::new(); + let mut store: SessionRegistry = SessionRegistry::new(); let new_convo = PrivateV1Convo::new([0; 32].into()); - let convo_id = store.insert_convo(new_convo); + let convo_id = store.insert_session(new_convo); - let convo = store.get_mut(&convo_id).ok_or_else(|| 0); + let convo = store.get_mut_session(&convo_id).ok_or_else(|| 0); convo.unwrap(); } } diff --git a/conversations/src/conversation/common.rs b/conversations/src/conversation/common.rs index 24c7c12..3bc698e 100644 --- a/conversations/src/conversation/common.rs +++ b/conversations/src/conversation/common.rs @@ -5,76 +5,78 @@ use std::sync::Arc; pub use crate::errors::ChatError; use crate::types::{AddressedEncryptedPayload, ContentData}; -pub type ConversationId<'a> = &'a str; -pub type ConversationIdOwned = Arc; +pub type SessionId<'a> = &'a str; +pub type SessionIdOwned = Arc; pub trait HasConversationId: Debug { - fn id(&self) -> ConversationId; + fn id(&self) -> SessionId<'_>; } -pub trait ConvoFactory: HasConversationId + Debug { +#[allow(dead_code)] +pub trait InboundSessionHandler: HasConversationId + Debug { fn handle_frame( &mut self, encoded_payload: &[u8], - ) -> Result<(Box, Vec), ChatError>; + ) -> Result<(Box, Vec), ChatError>; } -pub trait Convo: HasConversationId + Debug { +pub trait OutboundSession: HasConversationId + Debug { fn send_message(&mut self, content: &[u8]) -> Result, ChatError>; fn remote_id(&self) -> String; } -pub struct ConversationStore { - conversations: HashMap, Box>, - factories: HashMap, Box>, +#[allow(dead_code)] +pub struct SessionRegistry { + sessions: HashMap, Box>, + handlers: HashMap, Box>, } -impl ConversationStore { +#[allow(dead_code)] +impl SessionRegistry { pub fn new() -> Self { Self { - conversations: HashMap::new(), - factories: HashMap::new(), + sessions: HashMap::new(), + handlers: HashMap::new(), } } - pub fn insert_convo( + pub fn insert_session( &mut self, - conversation: impl Convo + HasConversationId + 'static, - ) -> ConversationIdOwned { - let key: ConversationIdOwned = Arc::from(conversation.id()); - self.conversations - .insert(key.clone(), Box::new(conversation)); + conversation: impl OutboundSession + HasConversationId + 'static, + ) -> SessionIdOwned { + let key: SessionIdOwned = Arc::from(conversation.id()); + self.sessions.insert(key.clone(), Box::new(conversation)); key } - pub fn register_factory( + pub fn register_handler( &mut self, - handler: impl ConvoFactory + HasConversationId + 'static, - ) -> ConversationIdOwned { - let key: ConversationIdOwned = Arc::from(handler.id()); - self.factories.insert(key.clone(), Box::new(handler)); + handler: impl InboundSessionHandler + HasConversationId + 'static, + ) -> SessionIdOwned { + let key: SessionIdOwned = Arc::from(handler.id()); + self.handlers.insert(key.clone(), Box::new(handler)); key } - pub fn get(&self, id: ConversationId) -> Option<&(dyn Convo + '_)> { - self.conversations.get(id).map(|c| c.as_ref()) + pub fn get_session(&self, id: SessionId) -> Option<&(dyn OutboundSession + '_)> { + self.sessions.get(id).map(|c| c.as_ref()) } - pub fn get_mut(&mut self, id: &str) -> Option<&mut (dyn Convo + '_)> { - Some(self.conversations.get_mut(id)?.as_mut()) + pub fn get_mut_session(&mut self, id: &str) -> Option<&mut (dyn OutboundSession + '_)> { + Some(self.sessions.get_mut(id)?.as_mut()) } - pub fn get_factory(&mut self, id: ConversationId) -> Option<&mut (dyn ConvoFactory + '_)> { - Some(self.factories.get_mut(id)?.as_mut()) + pub fn get_handler(&mut self, id: SessionId) -> Option<&mut (dyn InboundSessionHandler + '_)> { + Some(self.handlers.get_mut(id)?.as_mut()) } - pub fn conversation_ids(&self) -> impl Iterator + '_ { - self.conversations.keys().cloned() + pub fn session_ids(&self) -> impl Iterator + '_ { + self.sessions.keys().cloned() } - pub fn factory_ids(&self) -> impl Iterator + '_ { - self.factories.keys().cloned() + pub fn handler_ids(&self) -> impl Iterator + '_ { + self.handlers.keys().cloned() } } diff --git a/conversations/src/conversation/privatev1.rs b/conversations/src/conversation/privatev1.rs index 2bf45db..2950629 100644 --- a/conversations/src/conversation/privatev1.rs +++ b/conversations/src/conversation/privatev1.rs @@ -6,7 +6,7 @@ use crypto::SecretKey; use prost::{Message, bytes::Bytes}; use crate::{ - conversation::common::{ConversationId, Convo, HasConversationId}, + conversation::common::{HasConversationId, OutboundSession, SessionId}, errors::ChatError, types::AddressedEncryptedPayload, utils::timestamp_millis, @@ -36,13 +36,13 @@ impl PrivateV1Convo { } impl HasConversationId for PrivateV1Convo { - fn id(&self) -> ConversationId { + fn id(&self) -> SessionId<'_> { // TODO: implementation "private_v1_convo_id" } } -impl Convo for PrivateV1Convo { +impl OutboundSession for PrivateV1Convo { fn send_message( &mut self, content: &[u8], diff --git a/conversations/src/inbox/inbox.rs b/conversations/src/inbox/inbox.rs index a6f0ccb..44c07d8 100644 --- a/conversations/src/inbox/inbox.rs +++ b/conversations/src/inbox/inbox.rs @@ -8,10 +8,11 @@ use std::rc::Rc; use crypto::{PrekeyBundle, SecretKey}; use crate::context::Introduction; -use crate::conversation::common::{ConversationId, Convo, ConvoFactory, HasConversationId}; +use crate::conversation::common::{ + HasConversationId, InboundSessionHandler, OutboundSession, SessionId, +}; use crate::conversation::privatev1::PrivateV1Convo; -// use crate::conversation::{ChatError, ConversationId, Convo, ConvoFactory, Id, PrivateV1Convo}; -use crate::crypto::{Blake2b128, CopyBytes, Digest, PublicKey, StaticSecret}; +use crate::crypto::{CopyBytes, PublicKey, StaticSecret}; use crate::errors::ChatError; use crate::identity::Identity; use crate::inbox::handshake::InboxHandshake; @@ -53,11 +54,6 @@ impl Inbox { } } - fn compute_local_convo_id(addr: &str) -> String { - let hash = Blake2b128::digest(format!("{}:{}:{}", "logoschat", "inboxV1", addr)); - hex::encode(hash) - } - pub fn create_bundle(&mut self) -> PrekeyBundle { let ephemeral = StaticSecret::random(); @@ -204,16 +200,16 @@ impl Inbox { } impl HasConversationId for Inbox { - fn id(&self) -> ConversationId { + fn id(&self) -> SessionId<'_> { &self.local_convo_id } } -impl ConvoFactory for Inbox { +impl InboundSessionHandler for Inbox { fn handle_frame( &mut self, message: &[u8], - ) -> Result<(Box, Vec), ChatError> { + ) -> Result<(Box, Vec), ChatError> { if message.len() == 0 { return Err(ChatError::Protocol("Example error".into())); } From 572ae6d9543a222032dc88e7b09aa17abdf1ad20 Mon Sep 17 00:00:00 2001 From: kaichaosun Date: Tue, 3 Feb 2026 13:21:50 +0800 Subject: [PATCH 3/7] chore: fix dead code --- conversations/src/context.rs | 10 ---------- conversations/src/conversation/common.rs | 3 --- conversations/src/crypto.rs | 5 ----- conversations/src/inbox/inbox.rs | 11 ++++------- conversations/src/lib.rs | 6 ++++-- conversations/src/types.rs | 2 +- 6 files changed, 9 insertions(+), 28 deletions(-) diff --git a/conversations/src/context.rs b/conversations/src/context.rs index 97f70c9..3aceeb9 100644 --- a/conversations/src/context.rs +++ b/conversations/src/context.rs @@ -23,7 +23,6 @@ pub struct Context { _identity: Rc, store: SessionRegistry, inbox: Inbox, - buf_size: usize, convo_handle_map: HashMap>, next_convo_handle: ConvoHandle, } @@ -36,20 +35,11 @@ impl Context { _identity: identity, store: SessionRegistry::new(), inbox, - buf_size: 0, convo_handle_map: HashMap::new(), next_convo_handle: INITIAL_CONVO_HANDLE, } } - pub fn buffer_size(&self) -> usize { - self.buf_size - } - - pub fn set_buffer_size(&mut self, size: usize) { - self.buf_size = size - } - pub fn create_private_convo( &mut self, remote_bundle: &Introduction, diff --git a/conversations/src/conversation/common.rs b/conversations/src/conversation/common.rs index 3bc698e..0b1d9ca 100644 --- a/conversations/src/conversation/common.rs +++ b/conversations/src/conversation/common.rs @@ -12,7 +12,6 @@ pub trait HasConversationId: Debug { fn id(&self) -> SessionId<'_>; } -#[allow(dead_code)] pub trait InboundSessionHandler: HasConversationId + Debug { fn handle_frame( &mut self, @@ -27,13 +26,11 @@ pub trait OutboundSession: HasConversationId + Debug { fn remote_id(&self) -> String; } -#[allow(dead_code)] pub struct SessionRegistry { sessions: HashMap, Box>, handlers: HashMap, Box>, } -#[allow(dead_code)] impl SessionRegistry { pub fn new() -> Self { Self { diff --git a/conversations/src/crypto.rs b/conversations/src/crypto.rs index ecf0d11..ff9531f 100644 --- a/conversations/src/crypto.rs +++ b/conversations/src/crypto.rs @@ -1,5 +1,3 @@ -pub use blake2::Digest; -use blake2::{Blake2b, digest}; use prost::bytes::Bytes; pub use x25519_dalek::{PublicKey, StaticSecret}; @@ -12,6 +10,3 @@ impl CopyBytes for PublicKey { Bytes::copy_from_slice(self.as_bytes()) } } - -#[allow(dead_code)] -pub type Blake2b128 = Blake2b; diff --git a/conversations/src/inbox/inbox.rs b/conversations/src/inbox/inbox.rs index 44c07d8..690878a 100644 --- a/conversations/src/inbox/inbox.rs +++ b/conversations/src/inbox/inbox.rs @@ -141,6 +141,7 @@ impl Inbox { payload: proto::EncryptedPayload, ) -> Result<(SecretKey, proto::InboxV1Frame), ChatError> { let handshake = Self::extract_payload(payload)?; + let payload_bytes = handshake.payload.clone(); let header = handshake .header .ok_or(ChatError::UnexpectedPayload("InboxV1Header".into()))?; @@ -166,8 +167,7 @@ impl Inbox { &initator_ephemeral, ); - // TODO: Decrypt Content - let frame = proto::InboxV1Frame::decode(handshake.payload)?; + let frame = Self::decrypt_frame(payload_bytes)?; Ok((seed_key, frame)) } @@ -183,12 +183,9 @@ impl Inbox { Ok(handshake) } - fn decrypt_frame( - enc_payload: proto::InboxHandshakeV1, - ) -> Result { - let frame_bytes = enc_payload.payload; + fn decrypt_frame(payload_bytes: prost::bytes::Bytes) -> Result { // TODO: decrypt payload - let frame = proto::InboxV1Frame::decode(frame_bytes)?; + let frame = proto::InboxV1Frame::decode(payload_bytes)?; Ok(frame) } diff --git a/conversations/src/lib.rs b/conversations/src/lib.rs index 91aab32..43ecfb6 100644 --- a/conversations/src/lib.rs +++ b/conversations/src/lib.rs @@ -1,15 +1,17 @@ mod api; mod context; -mod conversation; +pub mod conversation; mod crypto; mod errors; mod identity; -mod inbox; +pub mod inbox; mod proto; mod types; mod utils; pub use api::*; +pub use conversation::common::{HasConversationId, InboundSessionHandler, OutboundSession}; +pub use inbox::Inbox; #[cfg(test)] mod tests { diff --git a/conversations/src/types.rs b/conversations/src/types.rs index 254ab9e..8d12f40 100644 --- a/conversations/src/types.rs +++ b/conversations/src/types.rs @@ -19,7 +19,7 @@ pub struct ContentData { // Internal type Definitions // Used by Conversations to attach addresses to outbound encrypted payloads -pub(crate) struct AddressedEncryptedPayload { +pub struct AddressedEncryptedPayload { pub delivery_address: String, pub data: proto::EncryptedPayload, } From 2e48e49a9adce3b24457377d4294434501ab0a92 Mon Sep 17 00:00:00 2001 From: kaichaosun Date: Tue, 3 Feb 2026 14:42:10 +0800 Subject: [PATCH 4/7] chore: remove crypto for identity --- conversations/src/context.rs | 5 ++--- conversations/src/crypto.rs | 12 ------------ conversations/src/{conversation => dm}/common.rs | 0 conversations/src/{conversation => dm}/mod.rs | 0 conversations/src/{conversation => dm}/privatev1.rs | 2 +- conversations/src/group/mod.rs | 1 + conversations/src/identity.rs | 3 +-- conversations/src/inbox/handshake.rs | 2 +- conversations/src/inbox/inbox.rs | 10 ++++------ conversations/src/{inbox.rs => inbox/mod.rs} | 0 conversations/src/lib.rs | 6 ++---- conversations/src/proto.rs | 11 +++++++++++ 12 files changed, 23 insertions(+), 29 deletions(-) delete mode 100644 conversations/src/crypto.rs rename conversations/src/{conversation => dm}/common.rs (100%) rename conversations/src/{conversation => dm}/mod.rs (100%) rename conversations/src/{conversation => dm}/privatev1.rs (95%) create mode 100644 conversations/src/group/mod.rs rename conversations/src/{inbox.rs => inbox/mod.rs} (100%) diff --git a/conversations/src/context.rs b/conversations/src/context.rs index 3aceeb9..313f6b7 100644 --- a/conversations/src/context.rs +++ b/conversations/src/context.rs @@ -1,8 +1,7 @@ use std::{collections::HashMap, rc::Rc, sync::Arc}; use crate::{ - // conversation::{ConversationStore, Convo, Id}, - conversation::common::{HasConversationId, OutboundSession, SessionRegistry}, + dm::common::{HasConversationId, OutboundSession, SessionRegistry}, errors::ChatError, identity::Identity, inbox::Inbox, @@ -122,7 +121,7 @@ impl Context { #[cfg(test)] mod tests { - use crate::conversation::privatev1::PrivateV1Convo; + use crate::dm::privatev1::PrivateV1Convo; use super::*; diff --git a/conversations/src/crypto.rs b/conversations/src/crypto.rs deleted file mode 100644 index ff9531f..0000000 --- a/conversations/src/crypto.rs +++ /dev/null @@ -1,12 +0,0 @@ -use prost::bytes::Bytes; -pub use x25519_dalek::{PublicKey, StaticSecret}; - -pub trait CopyBytes { - fn copy_to_bytes(&self) -> Bytes; -} - -impl CopyBytes for PublicKey { - fn copy_to_bytes(&self) -> Bytes { - Bytes::copy_from_slice(self.as_bytes()) - } -} diff --git a/conversations/src/conversation/common.rs b/conversations/src/dm/common.rs similarity index 100% rename from conversations/src/conversation/common.rs rename to conversations/src/dm/common.rs diff --git a/conversations/src/conversation/mod.rs b/conversations/src/dm/mod.rs similarity index 100% rename from conversations/src/conversation/mod.rs rename to conversations/src/dm/mod.rs diff --git a/conversations/src/conversation/privatev1.rs b/conversations/src/dm/privatev1.rs similarity index 95% rename from conversations/src/conversation/privatev1.rs rename to conversations/src/dm/privatev1.rs index 2950629..87ad551 100644 --- a/conversations/src/conversation/privatev1.rs +++ b/conversations/src/dm/privatev1.rs @@ -6,7 +6,7 @@ use crypto::SecretKey; use prost::{Message, bytes::Bytes}; use crate::{ - conversation::common::{HasConversationId, OutboundSession, SessionId}, + dm::common::{HasConversationId, OutboundSession, SessionId}, errors::ChatError, types::AddressedEncryptedPayload, utils::timestamp_millis, diff --git a/conversations/src/group/mod.rs b/conversations/src/group/mod.rs new file mode 100644 index 0000000..dc53af3 --- /dev/null +++ b/conversations/src/group/mod.rs @@ -0,0 +1 @@ +// Group chat module diff --git a/conversations/src/identity.rs b/conversations/src/identity.rs index c5646a7..42316f7 100644 --- a/conversations/src/identity.rs +++ b/conversations/src/identity.rs @@ -1,7 +1,6 @@ use blake2::{Blake2b512, Digest}; use std::fmt; - -use crate::crypto::{PublicKey, StaticSecret}; +pub use x25519_dalek::{PublicKey, StaticSecret}; pub struct Identity { secret: StaticSecret, diff --git a/conversations/src/inbox/handshake.rs b/conversations/src/inbox/handshake.rs index bbcb088..7216afa 100644 --- a/conversations/src/inbox/handshake.rs +++ b/conversations/src/inbox/handshake.rs @@ -5,7 +5,7 @@ use blake2::{ use crypto::{DomainSeparator, PrekeyBundle, SecretKey, X3Handshake}; use rand_core::{CryptoRng, RngCore}; -use crate::crypto::{PublicKey, StaticSecret}; +use crate::identity::{PublicKey, StaticSecret}; type Blake2bMac256 = Blake2bMac; diff --git a/conversations/src/inbox/inbox.rs b/conversations/src/inbox/inbox.rs index 690878a..041e651 100644 --- a/conversations/src/inbox/inbox.rs +++ b/conversations/src/inbox/inbox.rs @@ -8,15 +8,13 @@ use std::rc::Rc; use crypto::{PrekeyBundle, SecretKey}; use crate::context::Introduction; -use crate::conversation::common::{ - HasConversationId, InboundSessionHandler, OutboundSession, SessionId, -}; -use crate::conversation::privatev1::PrivateV1Convo; -use crate::crypto::{CopyBytes, PublicKey, StaticSecret}; +use crate::dm::common::{HasConversationId, InboundSessionHandler, OutboundSession, SessionId}; +use crate::dm::privatev1::PrivateV1Convo; use crate::errors::ChatError; use crate::identity::Identity; +use crate::identity::{PublicKey, StaticSecret}; use crate::inbox::handshake::InboxHandshake; -use crate::proto; +use crate::proto::{self, CopyBytes}; use crate::types::{AddressedEncryptedPayload, ContentData}; /// Compute the deterministic Delivery_address for an installation diff --git a/conversations/src/inbox.rs b/conversations/src/inbox/mod.rs similarity index 100% rename from conversations/src/inbox.rs rename to conversations/src/inbox/mod.rs diff --git a/conversations/src/lib.rs b/conversations/src/lib.rs index 43ecfb6..f220b21 100644 --- a/conversations/src/lib.rs +++ b/conversations/src/lib.rs @@ -1,8 +1,8 @@ mod api; mod context; -pub mod conversation; -mod crypto; +pub mod dm; mod errors; +mod group; mod identity; pub mod inbox; mod proto; @@ -10,8 +10,6 @@ mod types; mod utils; pub use api::*; -pub use conversation::common::{HasConversationId, InboundSessionHandler, OutboundSession}; -pub use inbox::Inbox; #[cfg(test)] mod tests { diff --git a/conversations/src/proto.rs b/conversations/src/proto.rs index 1697de5..cd43973 100644 --- a/conversations/src/proto.rs +++ b/conversations/src/proto.rs @@ -7,3 +7,14 @@ pub use chat_proto::logoschat::invite::InvitePrivateV1; pub use prost::Message; pub use prost::bytes::Bytes; +use x25519_dalek::PublicKey; + +pub trait CopyBytes { + fn copy_to_bytes(&self) -> Bytes; +} + +impl CopyBytes for PublicKey { + fn copy_to_bytes(&self) -> Bytes { + Bytes::copy_from_slice(self.as_bytes()) + } +} From 0ca0bb9548ca78dfc65cf7190b98a8aa4f0ef2db Mon Sep 17 00:00:00 2001 From: kaichaosun Date: Tue, 3 Feb 2026 14:53:55 +0800 Subject: [PATCH 5/7] chore: isolate ffi functions --- conversations/src/{dm => }/common.rs | 0 conversations/src/context.rs | 2 +- conversations/src/dm/mod.rs | 1 - conversations/src/dm/privatev1.rs | 2 +- conversations/src/{ => ffi}/api.rs | 0 conversations/src/ffi/mod.rs | 1 + conversations/src/inbox/inbox.rs | 2 +- conversations/src/lib.rs | 17 ++++++++++------- conversations/src/types.rs | 2 -- 9 files changed, 14 insertions(+), 13 deletions(-) rename conversations/src/{dm => }/common.rs (100%) rename conversations/src/{ => ffi}/api.rs (100%) create mode 100644 conversations/src/ffi/mod.rs diff --git a/conversations/src/dm/common.rs b/conversations/src/common.rs similarity index 100% rename from conversations/src/dm/common.rs rename to conversations/src/common.rs diff --git a/conversations/src/context.rs b/conversations/src/context.rs index 313f6b7..e21ba1b 100644 --- a/conversations/src/context.rs +++ b/conversations/src/context.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, rc::Rc, sync::Arc}; use crate::{ - dm::common::{HasConversationId, OutboundSession, SessionRegistry}, + common::{HasConversationId, OutboundSession, SessionRegistry}, errors::ChatError, identity::Identity, inbox::Inbox, diff --git a/conversations/src/dm/mod.rs b/conversations/src/dm/mod.rs index a2c5e4b..646c64c 100644 --- a/conversations/src/dm/mod.rs +++ b/conversations/src/dm/mod.rs @@ -1,2 +1 @@ -pub mod common; pub mod privatev1; diff --git a/conversations/src/dm/privatev1.rs b/conversations/src/dm/privatev1.rs index 87ad551..4175d1f 100644 --- a/conversations/src/dm/privatev1.rs +++ b/conversations/src/dm/privatev1.rs @@ -6,7 +6,7 @@ use crypto::SecretKey; use prost::{Message, bytes::Bytes}; use crate::{ - dm::common::{HasConversationId, OutboundSession, SessionId}, + common::{HasConversationId, OutboundSession, SessionId}, errors::ChatError, types::AddressedEncryptedPayload, utils::timestamp_millis, diff --git a/conversations/src/api.rs b/conversations/src/ffi/api.rs similarity index 100% rename from conversations/src/api.rs rename to conversations/src/ffi/api.rs diff --git a/conversations/src/ffi/mod.rs b/conversations/src/ffi/mod.rs new file mode 100644 index 0000000..e5fdf85 --- /dev/null +++ b/conversations/src/ffi/mod.rs @@ -0,0 +1 @@ +pub mod api; diff --git a/conversations/src/inbox/inbox.rs b/conversations/src/inbox/inbox.rs index 041e651..108b1d2 100644 --- a/conversations/src/inbox/inbox.rs +++ b/conversations/src/inbox/inbox.rs @@ -7,8 +7,8 @@ use std::rc::Rc; use crypto::{PrekeyBundle, SecretKey}; +use crate::common::{HasConversationId, InboundSessionHandler, OutboundSession, SessionId}; use crate::context::Introduction; -use crate::dm::common::{HasConversationId, InboundSessionHandler, OutboundSession, SessionId}; use crate::dm::privatev1::PrivateV1Convo; use crate::errors::ChatError; use crate::identity::Identity; diff --git a/conversations/src/lib.rs b/conversations/src/lib.rs index f220b21..c40aaa0 100644 --- a/conversations/src/lib.rs +++ b/conversations/src/lib.rs @@ -1,20 +1,23 @@ -mod api; -mod context; +pub mod common; pub mod dm; +pub mod ffi; +pub mod group; +pub mod inbox; + +mod context; mod errors; -mod group; mod identity; -pub mod inbox; mod proto; mod types; mod utils; -pub use api::*; - #[cfg(test)] mod tests { - use super::*; + use crate::ffi::api::{ + create_context, create_intro_bundle, create_new_private_convo, destroy_context, + handle_payload, + }; use std::str::FromStr; #[test] diff --git a/conversations/src/types.rs b/conversations/src/types.rs index 8d12f40..da44f38 100644 --- a/conversations/src/types.rs +++ b/conversations/src/types.rs @@ -1,7 +1,5 @@ use crate::proto::{self, Message}; -// FFI Type definitions - // This struct represents Outbound data. // It wraps an encoded payload with a delivery address, so it can be handled by the delivery service. pub struct AddressedEnvelope { From cc6988d8ac1c7746c8bfd1e4edaadfee76c7743d Mon Sep 17 00:00:00 2001 From: kaichaosun Date: Wed, 4 Feb 2026 10:22:00 +0800 Subject: [PATCH 6/7] chore: change signature of decrypt_frame back and allow dead code for it. --- conversations/src/inbox/inbox.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/conversations/src/inbox/inbox.rs b/conversations/src/inbox/inbox.rs index 108b1d2..599d90b 100644 --- a/conversations/src/inbox/inbox.rs +++ b/conversations/src/inbox/inbox.rs @@ -139,7 +139,6 @@ impl Inbox { payload: proto::EncryptedPayload, ) -> Result<(SecretKey, proto::InboxV1Frame), ChatError> { let handshake = Self::extract_payload(payload)?; - let payload_bytes = handshake.payload.clone(); let header = handshake .header .ok_or(ChatError::UnexpectedPayload("InboxV1Header".into()))?; @@ -165,7 +164,8 @@ impl Inbox { &initator_ephemeral, ); - let frame = Self::decrypt_frame(payload_bytes)?; + // TODO: Decrypt Content + let frame = proto::InboxV1Frame::decode(handshake.payload)?; Ok((seed_key, frame)) } @@ -181,9 +181,13 @@ impl Inbox { Ok(handshake) } - fn decrypt_frame(payload_bytes: prost::bytes::Bytes) -> Result { + #[allow(dead_code)] + fn decrypt_frame( + enc_payload: proto::InboxHandshakeV1, + ) -> Result { + let frame_bytes = enc_payload.payload; // TODO: decrypt payload - let frame = proto::InboxV1Frame::decode(payload_bytes)?; + let frame = proto::InboxV1Frame::decode(frame_bytes)?; Ok(frame) } From 0ddfd3f3f303a26975d5840336f1343b78d99d9d Mon Sep 17 00:00:00 2001 From: kaichaosun Date: Wed, 4 Feb 2026 12:17:36 +0800 Subject: [PATCH 7/7] chore: reanme session to chat --- conversations/src/common.rs | 55 +++++++++++++++---------------- conversations/src/context.rs | 26 ++++++--------- conversations/src/dm/privatev1.rs | 8 ++--- conversations/src/inbox/inbox.rs | 10 +++--- 4 files changed, 45 insertions(+), 54 deletions(-) diff --git a/conversations/src/common.rs b/conversations/src/common.rs index 0b1d9ca..55916f0 100644 --- a/conversations/src/common.rs +++ b/conversations/src/common.rs @@ -5,75 +5,72 @@ use std::sync::Arc; pub use crate::errors::ChatError; use crate::types::{AddressedEncryptedPayload, ContentData}; -pub type SessionId<'a> = &'a str; -pub type SessionIdOwned = Arc; +pub type ChatId<'a> = &'a str; +pub type ChatIdOwned = Arc; -pub trait HasConversationId: Debug { - fn id(&self) -> SessionId<'_>; +pub trait HasChatId: Debug { + fn id(&self) -> ChatId<'_>; } -pub trait InboundSessionHandler: HasConversationId + Debug { +pub trait InboundMessageHandler { fn handle_frame( &mut self, encoded_payload: &[u8], - ) -> Result<(Box, Vec), ChatError>; + ) -> Result<(Box, Vec), ChatError>; } -pub trait OutboundSession: HasConversationId + Debug { +pub trait Chat: HasChatId + Debug { fn send_message(&mut self, content: &[u8]) -> Result, ChatError>; fn remote_id(&self) -> String; } -pub struct SessionRegistry { - sessions: HashMap, Box>, - handlers: HashMap, Box>, +pub struct ChatStore { + chats: HashMap, Box>, + handlers: HashMap, Box>, } -impl SessionRegistry { +impl ChatStore { pub fn new() -> Self { Self { - sessions: HashMap::new(), + chats: HashMap::new(), handlers: HashMap::new(), } } - pub fn insert_session( - &mut self, - conversation: impl OutboundSession + HasConversationId + 'static, - ) -> SessionIdOwned { - let key: SessionIdOwned = Arc::from(conversation.id()); - self.sessions.insert(key.clone(), Box::new(conversation)); + pub fn insert_chat(&mut self, conversation: impl Chat + HasChatId + 'static) -> ChatIdOwned { + let key: ChatIdOwned = Arc::from(conversation.id()); + self.chats.insert(key.clone(), Box::new(conversation)); key } pub fn register_handler( &mut self, - handler: impl InboundSessionHandler + HasConversationId + 'static, - ) -> SessionIdOwned { - let key: SessionIdOwned = Arc::from(handler.id()); + handler: impl InboundMessageHandler + HasChatId + 'static, + ) -> ChatIdOwned { + let key: ChatIdOwned = Arc::from(handler.id()); self.handlers.insert(key.clone(), Box::new(handler)); key } - pub fn get_session(&self, id: SessionId) -> Option<&(dyn OutboundSession + '_)> { - self.sessions.get(id).map(|c| c.as_ref()) + pub fn get_chat(&self, id: ChatId) -> Option<&(dyn Chat + '_)> { + self.chats.get(id).map(|c| c.as_ref()) } - pub fn get_mut_session(&mut self, id: &str) -> Option<&mut (dyn OutboundSession + '_)> { - Some(self.sessions.get_mut(id)?.as_mut()) + pub fn get_mut_chat(&mut self, id: &str) -> Option<&mut (dyn Chat + '_)> { + Some(self.chats.get_mut(id)?.as_mut()) } - pub fn get_handler(&mut self, id: SessionId) -> Option<&mut (dyn InboundSessionHandler + '_)> { + pub fn get_handler(&mut self, id: ChatId) -> Option<&mut (dyn InboundMessageHandler + '_)> { Some(self.handlers.get_mut(id)?.as_mut()) } - pub fn session_ids(&self) -> impl Iterator + '_ { - self.sessions.keys().cloned() + pub fn chat_ids(&self) -> impl Iterator + '_ { + self.chats.keys().cloned() } - pub fn handler_ids(&self) -> impl Iterator + '_ { + pub fn handler_ids(&self) -> impl Iterator + '_ { self.handlers.keys().cloned() } } diff --git a/conversations/src/context.rs b/conversations/src/context.rs index e21ba1b..7323c01 100644 --- a/conversations/src/context.rs +++ b/conversations/src/context.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, rc::Rc, sync::Arc}; use crate::{ - common::{HasConversationId, OutboundSession, SessionRegistry}, + common::{Chat, ChatStore, HasChatId}, errors::ChatError, identity::Identity, inbox::Inbox, @@ -20,7 +20,7 @@ pub type ConvoHandle = u32; // Ctx manages lifetimes of objects to process and generate payloads. pub struct Context { _identity: Rc, - store: SessionRegistry, + store: ChatStore, inbox: Inbox, convo_handle_map: HashMap>, next_convo_handle: ConvoHandle, @@ -32,7 +32,7 @@ impl Context { let inbox = Inbox::new(Rc::clone(&identity)); // Self { _identity: identity, - store: SessionRegistry::new(), + store: ChatStore::new(), inbox, convo_handle_map: HashMap::new(), next_convo_handle: INITIAL_CONVO_HANDLE, @@ -89,23 +89,17 @@ impl Context { Ok(Introduction::from(pkb).into()) } - fn add_convo( - &mut self, - convo: impl OutboundSession + HasConversationId + 'static, - ) -> ConvoHandle { + fn add_convo(&mut self, convo: impl Chat + HasChatId + 'static) -> ConvoHandle { let handle = self.next_convo_handle; self.next_convo_handle += 1; - let convo_id = self.store.insert_session(convo); + let convo_id = self.store.insert_chat(convo); self.convo_handle_map.insert(handle, convo_id); handle } // Returns a mutable reference to a Convo for a given ConvoHandle - fn get_convo_mut( - &mut self, - handle: ConvoHandle, - ) -> Result<&mut dyn OutboundSession, ChatError> { + fn get_convo_mut(&mut self, handle: ConvoHandle) -> Result<&mut dyn Chat, ChatError> { let convo_id = self .convo_handle_map .get(&handle) @@ -113,7 +107,7 @@ impl Context { .clone(); self.store - .get_mut_session(&convo_id) + .get_mut_chat(&convo_id) .ok_or_else(|| ChatError::NoConvo(handle)) } } @@ -127,12 +121,12 @@ mod tests { #[test] fn convo_store_get() { - let mut store: SessionRegistry = SessionRegistry::new(); + let mut store: ChatStore = ChatStore::new(); let new_convo = PrivateV1Convo::new([0; 32].into()); - let convo_id = store.insert_session(new_convo); + let convo_id = store.insert_chat(new_convo); - let convo = store.get_mut_session(&convo_id).ok_or_else(|| 0); + let convo = store.get_mut_chat(&convo_id).ok_or_else(|| 0); convo.unwrap(); } } diff --git a/conversations/src/dm/privatev1.rs b/conversations/src/dm/privatev1.rs index 4175d1f..8810a9c 100644 --- a/conversations/src/dm/privatev1.rs +++ b/conversations/src/dm/privatev1.rs @@ -6,7 +6,7 @@ use crypto::SecretKey; use prost::{Message, bytes::Bytes}; use crate::{ - common::{HasConversationId, OutboundSession, SessionId}, + common::{ChatId, HasChatId, Chat}, errors::ChatError, types::AddressedEncryptedPayload, utils::timestamp_millis, @@ -35,14 +35,14 @@ impl PrivateV1Convo { } } -impl HasConversationId for PrivateV1Convo { - fn id(&self) -> SessionId<'_> { +impl HasChatId for PrivateV1Convo { + fn id(&self) -> ChatId<'_> { // TODO: implementation "private_v1_convo_id" } } -impl OutboundSession for PrivateV1Convo { +impl Chat for PrivateV1Convo { fn send_message( &mut self, content: &[u8], diff --git a/conversations/src/inbox/inbox.rs b/conversations/src/inbox/inbox.rs index 599d90b..b6af232 100644 --- a/conversations/src/inbox/inbox.rs +++ b/conversations/src/inbox/inbox.rs @@ -7,7 +7,7 @@ use std::rc::Rc; use crypto::{PrekeyBundle, SecretKey}; -use crate::common::{HasConversationId, InboundSessionHandler, OutboundSession, SessionId}; +use crate::common::{Chat, ChatId, HasChatId, InboundMessageHandler}; use crate::context::Introduction; use crate::dm::privatev1::PrivateV1Convo; use crate::errors::ChatError; @@ -198,17 +198,17 @@ impl Inbox { } } -impl HasConversationId for Inbox { - fn id(&self) -> SessionId<'_> { +impl HasChatId for Inbox { + fn id(&self) -> ChatId<'_> { &self.local_convo_id } } -impl InboundSessionHandler for Inbox { +impl InboundMessageHandler for Inbox { fn handle_frame( &mut self, message: &[u8], - ) -> Result<(Box, Vec), ChatError> { + ) -> Result<(Box, Vec), ChatError> { if message.len() == 0 { return Err(ChatError::Protocol("Example error".into())); }