mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-02-10 17:03:12 +00:00
Implement handle_payload
This commit is contained in:
parent
97a1cf150a
commit
2fc2f15a04
@ -148,7 +148,7 @@ pub fn handle_payload(
|
|||||||
mut content_out: c_slice::Mut<'_, u8>,
|
mut content_out: c_slice::Mut<'_, u8>,
|
||||||
) -> i32 {
|
) -> i32 {
|
||||||
match ctx.0.handle_payload(&payload) {
|
match ctx.0.handle_payload(&payload) {
|
||||||
Some(content) => {
|
Ok(Some(content)) => {
|
||||||
let convo_id_bytes = content.conversation_id.as_bytes();
|
let convo_id_bytes = content.conversation_id.as_bytes();
|
||||||
|
|
||||||
if conversation_id_out.len() < convo_id_bytes.len() {
|
if conversation_id_out.len() < convo_id_bytes.len() {
|
||||||
@ -165,7 +165,7 @@ pub fn handle_payload(
|
|||||||
|
|
||||||
content.data.len() as i32
|
content.data.len() as i32
|
||||||
}
|
}
|
||||||
None => 0,
|
_ => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use crate::{
|
|||||||
errors::ChatError,
|
errors::ChatError,
|
||||||
identity::Identity,
|
identity::Identity,
|
||||||
inbox::Inbox,
|
inbox::Inbox,
|
||||||
|
proto::{EncryptedPayload, EnvelopeV1, Message},
|
||||||
types::{AddressedEnvelope, ContentData},
|
types::{AddressedEnvelope, ContentData},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ impl Context {
|
|||||||
.map(|p| p.to_envelope(convo.id().to_string()))
|
.map(|p| p.to_envelope(convo.id().to_string()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let convo_handle = self.add_convo(convo);
|
let convo_handle = self.add_convo(Box::new(convo));
|
||||||
(convo_handle, payload_bytes)
|
(convo_handle, payload_bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,12 +77,30 @@ impl Context {
|
|||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_payload(&mut self, _payload: &[u8]) -> Option<ContentData> {
|
// Decode bytes and send to protocol for processing.
|
||||||
// !TODO Replace Mock
|
pub fn handle_payload(&mut self, payload: &[u8]) -> Result<Option<ContentData>, ChatError> {
|
||||||
Some(ContentData {
|
let env = match EnvelopeV1::decode(payload) {
|
||||||
conversation_id: "convo_id".into(),
|
Ok(v) => v,
|
||||||
data: vec![1, 2, 3, 4, 5, 6],
|
Err(e) => return Err(e.into()),
|
||||||
})
|
};
|
||||||
|
|
||||||
|
// TODO: Impl Conversation hinting
|
||||||
|
let convo_id = env.conversation_hint;
|
||||||
|
let enc = EncryptedPayload::decode(payload)?;
|
||||||
|
|
||||||
|
// Call handle_payload on the appropriate protocol.
|
||||||
|
if convo_id == self.inbox.id() {
|
||||||
|
let (convo, content) = self.inbox.handle_frame(enc)?;
|
||||||
|
self.add_convo(convo);
|
||||||
|
|
||||||
|
Ok(content)
|
||||||
|
} else {
|
||||||
|
let Some(convo) = self.store.get_mut(&convo_id) else {
|
||||||
|
return Err(ChatError::NoConvo(0)); // TODO: Remove ConvoHandle type
|
||||||
|
};
|
||||||
|
|
||||||
|
convo.handle_frame(enc)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_intro_bundle(&mut self) -> Result<Vec<u8>, ChatError> {
|
pub fn create_intro_bundle(&mut self) -> Result<Vec<u8>, ChatError> {
|
||||||
@ -89,7 +108,7 @@ impl Context {
|
|||||||
Ok(Introduction::from(pkb).into())
|
Ok(Introduction::from(pkb).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_convo(&mut self, convo: impl Convo + Id + 'static) -> ConvoHandle {
|
fn add_convo(&mut self, convo: Box<dyn Convo>) -> ConvoHandle {
|
||||||
let handle = self.next_convo_handle;
|
let handle = self.next_convo_handle;
|
||||||
self.next_convo_handle += 1;
|
self.next_convo_handle += 1;
|
||||||
let convo_id = self.store.insert_convo(convo);
|
let convo_id = self.store.insert_convo(convo);
|
||||||
@ -123,7 +142,7 @@ mod tests {
|
|||||||
let mut store: ConversationStore = ConversationStore::new();
|
let mut store: ConversationStore = ConversationStore::new();
|
||||||
|
|
||||||
let new_convo = GroupTestConvo::new();
|
let new_convo = GroupTestConvo::new();
|
||||||
let convo_id = store.insert_convo(new_convo);
|
let convo_id = store.insert_convo(Box::new(new_convo));
|
||||||
|
|
||||||
let convo = store.get_mut(&convo_id).ok_or_else(|| 0);
|
let convo = store.get_mut(&convo_id).ok_or_else(|| 0);
|
||||||
convo.unwrap();
|
convo.unwrap();
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use std::fmt::Debug;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub use crate::errors::ChatError;
|
pub use crate::errors::ChatError;
|
||||||
use crate::types::AddressedEncryptedPayload;
|
use crate::types::{AddressedEncryptedPayload, ContentData};
|
||||||
|
|
||||||
pub type ConversationId<'a> = &'a str;
|
pub type ConversationId<'a> = &'a str;
|
||||||
pub type ConversationIdOwned = Arc<str>;
|
pub type ConversationIdOwned = Arc<str>;
|
||||||
@ -16,6 +16,16 @@ pub trait Convo: Id + Debug {
|
|||||||
fn send_message(&mut self, content: &[u8])
|
fn send_message(&mut self, content: &[u8])
|
||||||
-> Result<Vec<AddressedEncryptedPayload>, ChatError>;
|
-> Result<Vec<AddressedEncryptedPayload>, ChatError>;
|
||||||
|
|
||||||
|
/// Decrypts and processes an incoming encrypted frame.
|
||||||
|
///
|
||||||
|
/// Returns `Ok(Some(ContentData))` if the frame contains user content,
|
||||||
|
/// `Ok(None)` for protocol frames (e.g., placeholders), or an error if
|
||||||
|
/// decryption or frame parsing fails.
|
||||||
|
fn handle_frame(
|
||||||
|
&mut self,
|
||||||
|
enc_payload: EncryptedPayload,
|
||||||
|
) -> Result<Option<ContentData>, ChatError>;
|
||||||
|
|
||||||
fn remote_id(&self) -> String;
|
fn remote_id(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,10 +40,9 @@ impl ConversationStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_convo(&mut self, conversation: impl Convo + Id + 'static) -> ConversationIdOwned {
|
pub fn insert_convo(&mut self, conversation: Box<dyn Convo>) -> ConversationIdOwned {
|
||||||
let key: ConversationIdOwned = Arc::from(conversation.id());
|
let key: ConversationIdOwned = Arc::from(conversation.id());
|
||||||
self.conversations
|
self.conversations.insert(key.clone(), conversation);
|
||||||
.insert(key.clone(), Box::new(conversation));
|
|
||||||
key
|
key
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,5 +62,6 @@ impl ConversationStore {
|
|||||||
mod group_test;
|
mod group_test;
|
||||||
mod privatev1;
|
mod privatev1;
|
||||||
|
|
||||||
|
use chat_proto::logoschat::encryption::EncryptedPayload;
|
||||||
pub use group_test::GroupTestConvo;
|
pub use group_test::GroupTestConvo;
|
||||||
pub use privatev1::PrivateV1Convo;
|
pub use privatev1::PrivateV1Convo;
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
conversation::{ChatError, ConversationId, Convo, Id},
|
conversation::{ChatError, ConversationId, Convo, Id},
|
||||||
types::AddressedEncryptedPayload,
|
proto::EncryptedPayload,
|
||||||
|
types::{AddressedEncryptedPayload, ContentData},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -27,6 +28,13 @@ impl Convo for GroupTestConvo {
|
|||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_frame(
|
||||||
|
&mut self,
|
||||||
|
_encoded_payload: EncryptedPayload,
|
||||||
|
) -> Result<Option<ContentData>, ChatError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
fn remote_id(&self) -> String {
|
fn remote_id(&self) -> String {
|
||||||
self.id().to_string()
|
self.id().to_string()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ use crate::{
|
|||||||
conversation::{ChatError, ConversationId, Convo, Id},
|
conversation::{ChatError, ConversationId, Convo, Id},
|
||||||
errors::EncryptionError,
|
errors::EncryptionError,
|
||||||
proto,
|
proto,
|
||||||
types::AddressedEncryptedPayload,
|
types::{AddressedEncryptedPayload, ContentData},
|
||||||
utils::timestamp_millis,
|
utils::timestamp_millis,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -89,6 +89,15 @@ impl PrivateV1Convo {
|
|||||||
.map_err(|e| EncryptionError::Decryption(e.to_string()))?;
|
.map_err(|e| EncryptionError::Decryption(e.to_string()))?;
|
||||||
Ok(PrivateV1Frame::decode(content_bytes.as_slice()).unwrap())
|
Ok(PrivateV1Frame::decode(content_bytes.as_slice()).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handler for application content
|
||||||
|
fn handle_content(&self, data: Vec<u8>) -> Option<ContentData> {
|
||||||
|
Some(ContentData {
|
||||||
|
conversation_id: self.id().into(),
|
||||||
|
data,
|
||||||
|
is_new_convo: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Id for PrivateV1Convo {
|
impl Id for PrivateV1Convo {
|
||||||
@ -118,6 +127,28 @@ impl Convo for PrivateV1Convo {
|
|||||||
}])
|
}])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_frame(
|
||||||
|
&mut self,
|
||||||
|
encoded_payload: EncryptedPayload,
|
||||||
|
) -> Result<Option<ContentData>, ChatError> {
|
||||||
|
// Extract expected frame
|
||||||
|
let frame = self
|
||||||
|
.decrypt(encoded_payload)
|
||||||
|
.map_err(|_| ChatError::Protocol("decryption".into()))?;
|
||||||
|
|
||||||
|
let Some(frame_type) = frame.frame_type else {
|
||||||
|
return Err(ChatError::ProtocolExpectation("None", "Some".into()));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle FrameTypes
|
||||||
|
let output = match frame_type {
|
||||||
|
FrameType::Content(bytes) => self.handle_content(bytes.into()),
|
||||||
|
FrameType::Placeholder(_) => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
|
||||||
fn remote_id(&self) -> String {
|
fn remote_id(&self) -> String {
|
||||||
//TODO: Implement as per spec
|
//TODO: Implement as per spec
|
||||||
self.id().into()
|
self.id().into()
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use chat_proto::logoschat::encryption::EncryptedPayload;
|
||||||
use hex;
|
use hex;
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use prost::bytes::Bytes;
|
use prost::bytes::Bytes;
|
||||||
@ -119,15 +120,11 @@ impl Inbox {
|
|||||||
Ok((convo, payloads))
|
Ok((convo, payloads))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_frame(
|
pub fn handle_frame(
|
||||||
&mut self,
|
&mut self,
|
||||||
message: &[u8],
|
enc_payload: EncryptedPayload,
|
||||||
) -> Result<(Box<dyn Convo>, Vec<ContentData>), ChatError> {
|
) -> Result<(Box<dyn Convo>, Vec<ContentData>), ChatError> {
|
||||||
if message.len() == 0 {
|
let handshake = Self::extract_payload(enc_payload)?;
|
||||||
return Err(ChatError::Protocol("Example error".into()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let handshake = Self::extract_payload(proto::EncryptedPayload::decode(message)?)?;
|
|
||||||
|
|
||||||
let header = handshake
|
let header = handshake
|
||||||
.header
|
.header
|
||||||
@ -240,19 +237,14 @@ mod tests {
|
|||||||
let mut raya_inbox = Inbox::new(raya_ident.into());
|
let mut raya_inbox = Inbox::new(raya_ident.into());
|
||||||
|
|
||||||
let bundle = raya_inbox.create_bundle();
|
let bundle = raya_inbox.create_bundle();
|
||||||
let (_, payloads) = saro_inbox
|
let (_, mut payloads) = saro_inbox
|
||||||
.invite_to_private_convo(&bundle.into(), "hello".as_bytes())
|
.invite_to_private_convo(&bundle.into(), "hello".as_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let payload = payloads
|
let payload = payloads.remove(0);
|
||||||
.get(0)
|
|
||||||
.expect("RemoteInbox::invite_to_private_convo did not generate any payloads");
|
|
||||||
|
|
||||||
let mut buf = Vec::new();
|
|
||||||
payload.data.encode(&mut buf).unwrap();
|
|
||||||
|
|
||||||
// Test handle_frame with valid payload
|
// Test handle_frame with valid payload
|
||||||
let result = raya_inbox.handle_frame(&buf);
|
let result = raya_inbox.handle_frame(payload.data);
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
result.is_ok(),
|
result.is_ok(),
|
||||||
|
|||||||
@ -14,6 +14,7 @@ pub struct AddressedEnvelope {
|
|||||||
pub struct ContentData {
|
pub struct ContentData {
|
||||||
pub conversation_id: String,
|
pub conversation_id: String,
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
|
pub is_new_convo: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal type Definitions
|
// Internal type Definitions
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user