Update Conversation handles over FFI (#46)

* Remove convo handles

* Remove convo_handle from docs
This commit is contained in:
Jazz Turner-Baggs 2026-02-06 23:58:23 +07:00 committed by GitHub
parent 1ce196e5ec
commit 135347cdd0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 37 additions and 49 deletions

View File

@ -12,7 +12,7 @@ pub enum ErrorCode {
UnknownError = -6,
}
use crate::context::{Context, ConvoHandle, Introduction};
use crate::context::{Context, Introduction};
/// Opaque wrapper for Context
#[derive_ReprC]
@ -74,13 +74,13 @@ pub fn create_new_private_convo(
let Ok(intro) = Introduction::try_from(bundle.as_slice()) else {
return NewConvoResult {
error_code: ErrorCode::BadIntro as i32,
convo_id: 0,
convo_id: "".into(),
payloads: Vec::new().into(),
};
};
// Create conversation
let (convo_handle, payloads) = ctx.0.create_private_convo(&intro, &content);
let (convo_id, payloads) = ctx.0.create_private_convo(&intro, &content);
// Convert payloads to FFI-compatible vector
let ffi_payloads: Vec<Payload> = payloads
@ -93,7 +93,7 @@ pub fn create_new_private_convo(
NewConvoResult {
error_code: 0,
convo_id: convo_handle,
convo_id: convo_id.to_string().into(),
payloads: ffi_payloads.into(),
}
}
@ -106,10 +106,10 @@ pub fn create_new_private_convo(
#[ffi_export]
pub fn send_content(
ctx: &mut ContextHandle,
convo_handle: ConvoHandle,
convo_id: repr_c::String,
content: c_slice::Ref<'_, u8>,
) -> PayloadResult {
let payloads = match ctx.0.send_content(convo_handle, &content) {
let payloads = match ctx.0.send_content(&convo_id, &content) {
Ok(p) => p,
Err(_) => {
return PayloadResult {
@ -203,7 +203,7 @@ pub fn destroy_payload_result(result: PayloadResult) {
#[repr(C)]
pub struct NewConvoResult {
pub error_code: i32,
pub convo_id: u32,
pub convo_id: repr_c::String,
pub payloads: repr_c::Vec<Payload>,
}

View File

@ -1,4 +1,4 @@
use std::{collections::HashMap, rc::Rc, sync::Arc};
use std::rc::Rc;
use crate::{
conversation::{ConversationId, ConversationStore, Convo, Id},
@ -9,22 +9,15 @@ use crate::{
types::{AddressedEnvelope, ContentData},
};
pub use crate::conversation::ConversationIdOwned;
pub use crate::inbox::Introduction;
//Offset handles to make debuging easier
const INITIAL_CONVO_HANDLE: u32 = 0xF5000001;
/// Used to identify a conversation on the othersize of the FFI.
pub type ConvoHandle = u32;
// This is the main entry point to the conversations api.
// Ctx manages lifetimes of objects to process and generate payloads.
pub struct Context {
_identity: Rc<Identity>,
store: ConversationStore,
inbox: Inbox,
convo_handle_map: HashMap<u32, Arc<str>>,
next_convo_handle: ConvoHandle,
}
impl Context {
@ -35,8 +28,6 @@ impl Context {
_identity: identity,
store: ConversationStore::new(),
inbox,
convo_handle_map: HashMap::new(),
next_convo_handle: INITIAL_CONVO_HANDLE,
}
}
@ -44,7 +35,7 @@ impl Context {
&mut self,
remote_bundle: &Introduction,
content: &[u8],
) -> (ConvoHandle, Vec<AddressedEnvelope>) {
) -> (ConversationIdOwned, Vec<AddressedEnvelope>) {
let (convo, payloads) = self
.inbox
.invite_to_private_convo(remote_bundle, content)
@ -55,17 +46,17 @@ impl Context {
.map(|p| p.to_envelope(convo.id().to_string()))
.collect();
let convo_handle = self.add_convo(Box::new(convo));
(convo_handle, payload_bytes)
let convo_id = self.add_convo(Box::new(convo));
(convo_id, payload_bytes)
}
pub fn send_content(
&mut self,
convo_handle: ConvoHandle,
convo_id: ConversationId,
content: &[u8],
) -> Result<Vec<AddressedEnvelope>, ChatError> {
// Lookup convo from handle
let convo = self.get_convo_mut(convo_handle)?;
// Lookup convo by id
let convo = self.get_convo_mut(convo_id)?;
// Generate encrypted payloads
let payloads = convo.send_message(content)?;
@ -91,7 +82,7 @@ impl Context {
match convo_id {
c if c == self.inbox.id() => self.dispatch_to_inbox(enc),
c if self.store.has(&c) => self.dispatch_to_convo(&c, enc),
_ => Err(ChatError::NoConvo(0)), // TODO: Remove ConvoHandle type
_ => Err(ChatError::NoConvo(convo_id)),
}
}
@ -123,26 +114,17 @@ impl Context {
Ok(Introduction::from(pkb).into())
}
fn add_convo(&mut self, convo: Box<dyn Convo>) -> ConvoHandle {
let handle = self.next_convo_handle;
self.next_convo_handle += 1;
fn add_convo(&mut self, convo: Box<dyn Convo>) -> ConversationIdOwned {
let convo_id = self.store.insert_convo(convo);
self.convo_handle_map.insert(handle, convo_id);
handle
convo_id
}
// Returns a mutable reference to a Convo for a given ConvoHandle
fn get_convo_mut(&mut self, handle: ConvoHandle) -> Result<&mut dyn Convo, ChatError> {
let convo_id = self
.convo_handle_map
.get(&handle)
.ok_or_else(|| ChatError::NoConvo(handle))?
.clone();
// Returns a mutable reference to a Convo for a given ConvoId
fn get_convo_mut(&mut self, convo_id: ConversationId) -> Result<&mut dyn Convo, ChatError> {
self.store
.get_mut(&convo_id)
.ok_or_else(|| ChatError::NoConvo(handle))
.ok_or_else(|| ChatError::NoConvo(convo_id.into()))
}
}

View File

@ -18,8 +18,8 @@ pub enum ChatError {
InvalidKeyLength,
#[error("bytes provided to {0} failed")]
BadParsing(&'static str),
#[error("convo with handle: {0} was not found")]
NoConvo(u32),
#[error("convo with id: {0} was not found")]
NoConvo(String),
}
#[derive(Error, Debug)]

View File

@ -24,7 +24,7 @@ proc pingpong() =
echo "Raya's Intro Bundle: ",intro
var (convo_sr, payloads) = saro.createNewPrivateConvo(intro, encode("Hey Raya")).expect("[Saro] Couldn't create convo")
echo "ConvoHandle:: ", convo_sr
echo "ConvoId:: ", convo_sr
echo "Payload:: ", payloads
## Send Payloads to Raya

View File

@ -36,7 +36,6 @@ const
# Opaque handle type for Context
type ContextHandle* = pointer
type ConvoHandle* = uint32
type
## Slice for passing byte arrays to safer_ffi functions
@ -77,7 +76,7 @@ type
## error_code is 0 on success, negative on error (see ErrorCode)
NewConvoResult* = object
error_code*: int32
convo_id*: uint32
convo_id*: ReprCString
payloads*: VecPayload
# FFI function imports
@ -112,7 +111,7 @@ proc create_new_private_convo*(
## The result must be freed with destroy_payload_result()
proc send_content*(
ctx: ContextHandle,
convo_handle: ConvoHandle,
convo_id: SliceUint8,
content: SliceUint8,
): PayloadResult {.importc, dynlib: CONVERSATIONS_LIB.}
@ -173,3 +172,10 @@ proc `[]`*(v: VecPayload, i: int): Payload =
## Get length of VecPayload
proc len*(v: VecPayload): int =
int(v.len)
## Convert a string to seq[byte]
proc toBytes*(s: string): seq[byte] =
if s.len == 0:
return @[]
result = newSeq[byte](s.len)
copyMem(addr result[0], unsafeAddr s[0], s.len)

View File

@ -46,7 +46,7 @@ proc createIntroductionBundle*(ctx: LibChat): Result[string, string] =
return ok(cast[string](buffer))
## Create a Private Convo
proc createNewPrivateConvo*(ctx: LibChat, bundle: string, content: seq[byte]): Result[(ConvoHandle, seq[PayloadResult]), string] =
proc createNewPrivateConvo*(ctx: LibChat, bundle: string, content: seq[byte]): Result[(string, seq[PayloadResult]), string] =
if ctx.handle == nil:
return err("Context handle is nil")
@ -75,7 +75,7 @@ proc createNewPrivateConvo*(ctx: LibChat, bundle: string, content: seq[byte]): R
data: p.data.toSeq()
)
let convoId = res.convo_id
let convoId = $res.convo_id
# Free the result
destroy_convo_result(res)
@ -83,7 +83,7 @@ proc createNewPrivateConvo*(ctx: LibChat, bundle: string, content: seq[byte]): R
return ok((convoId, payloads))
## Send content to an existing conversation
proc sendContent*(ctx: LibChat, convoHandle: ConvoHandle, content: seq[byte]): Result[seq[PayloadResult], string] =
proc sendContent*(ctx: LibChat, convoId: string, content: seq[byte]): Result[seq[PayloadResult], string] =
if ctx.handle == nil:
return err("Context handle is nil")
@ -92,7 +92,7 @@ proc sendContent*(ctx: LibChat, convoHandle: ConvoHandle, content: seq[byte]): R
let res = bindings.send_content(
ctx.handle,
convoHandle,
convoId.toSlice(),
content.toSlice()
)