fix: update library bindings for libchat integration (#69)

This commit is contained in:
osmaczko 2026-02-18 20:18:43 +01:00 committed by GitHub
parent aa70144b26
commit 3121b2c801
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 29 additions and 71 deletions

View File

@ -2,7 +2,7 @@
CC = gcc
CFLAGS = -Wall -Wextra -I../../library -pthread
LDFLAGS = -L../../build -lchat -lncurses -Wl,-rpath,../../build
LDFLAGS = -L../../build -llogoschat -lncurses -Wl,-rpath,../../build
BUILD_DIR = ../../build
TARGET = $(BUILD_DIR)/cbindings_chat_tui

View File

@ -30,9 +30,7 @@ static const size_t MAX_INPUT_LEN = 2048;
// Application state structures
typedef struct {
char current_convo[128];
char inbox_id[128];
char my_name[64];
char my_address[128];
void *ctx;
} ChatState;
@ -442,23 +440,13 @@ static void bundle_callback(int ret, const char *msg, size_t len, void *userData
static void identity_callback(int ret, const char *msg, size_t len, void *userData) {
(void)userData; (void)len;
if (ret == RET_OK) {
const char *keys[] = {"name", "address"};
char *values[] = {g_app.chat.my_name, g_app.chat.my_address};
size_t sizes[] = {sizeof(g_app.chat.my_name), sizeof(g_app.chat.my_address)};
json_extract(msg, keys, values, sizes, 2);
char buf[256];
snprintf(buf, sizeof(buf), "Identity: %s (%.24s...)", g_app.chat.my_name, g_app.chat.my_address);
add_log(buf);
}
}
const char *keys[] = {"name"};
char *values[] = {g_app.chat.my_name};
size_t sizes[] = {sizeof(g_app.chat.my_name)};
json_extract(msg, keys, values, sizes, 1);
static void inbox_callback(int ret, const char *msg, size_t len, void *userData) {
(void)userData;
if (ret == RET_OK && len > 0) {
snprintf(g_app.chat.inbox_id, sizeof(g_app.chat.inbox_id), "%.*s", (int)len, msg);
char buf[256];
snprintf(buf, sizeof(buf), "Inbox: %.24s...", g_app.chat.inbox_id);
snprintf(buf, sizeof(buf), "Identity: %s", g_app.chat.my_name);
add_log(buf);
}
}
@ -713,7 +701,6 @@ int main(int argc, char *argv[]) {
add_log("Starting client...");
chat_start(g_app.chat.ctx, general_callback, NULL);
chat_get_identity(g_app.chat.ctx, identity_callback, NULL);
chat_get_default_inbox_id(g_app.chat.ctx, inbox_callback, NULL);
add_message("Welcome to Chat TUI!");
add_message("Type /help for commands, /quit to exit");

View File

@ -7,7 +7,6 @@ import chronos
import ffi
import src/chat
import src/chat/proto_types
import src/chat/delivery/waku_client
import src/chat/identity
import library/utils
@ -119,15 +118,6 @@ proc chat_get_id(
let clientId = ctx.myLib[].getId()
return ok(clientId)
proc chat_get_default_inbox_id(
ctx: ptr FFIContext[ChatClient],
callback: FFICallBack,
userData: pointer
) {.ffi.} =
## Get the default inbox conversation ID
let inboxId = ctx.myLib[].defaultInboxConversationId()
return ok(inboxId)
#################################################
# Conversation List Operations
#################################################

View File

@ -1,14 +1,13 @@
## Conversation API - FFI bindings for conversation operations
## Uses the {.ffi.} pragma for async request handling
import std/[json, options]
import std/options
import chronicles
import chronos
import ffi
import stew/byteutils
import src/chat
import src/chat/proto_types
import library/utils
logScope:
@ -22,32 +21,24 @@ proc chat_new_private_conversation(
ctx: ptr FFIContext[ChatClient],
callback: FFICallBack,
userData: pointer,
introBundleJson: cstring,
introBundleStr: cstring,
contentHex: cstring
) {.ffi.} =
## Create a new private conversation with the given IntroBundle
## introBundleJson: JSON string with {"ident": "hex...", "ephemeral": "hex..."}
## introBundleStr: Intro bundle ASCII string as returned by chat_create_intro_bundle
## contentHex: Initial message content as hex-encoded string
try:
let bundleJson = parseJson($introBundleJson)
# Parse IntroBundle from JSON
let identBytes = hexToSeqByte(bundleJson["ident"].getStr())
let ephemeralBytes = hexToSeqByte(bundleJson["ephemeral"].getStr())
let introBundle = IntroBundle(
ident: identBytes,
ephemeral: ephemeralBytes
)
# Convert bundle string to seq[byte]
let bundle = toBytes($introBundleStr)
# Convert hex content to bytes
let content = hexToSeqByte($contentHex)
# Create the conversation
let errOpt = await ctx.myLib[].newPrivateConversation(introBundle, content)
let errOpt = await ctx.myLib[].newPrivateConversation(bundle, content)
if errOpt.isSome():
return err("failed to create conversation: " & $errOpt.get())
return ok("")
except CatchableError as e:
error "chat_new_private_conversation failed", error = e.msg

View File

@ -8,8 +8,6 @@ import ffi
import stew/byteutils
import src/chat
import src/chat/crypto
import src/chat/proto_types
import library/utils
logScope:
@ -25,12 +23,9 @@ proc chat_get_identity(
userData: pointer
) {.ffi.} =
## Get the client identity
## Returns JSON string: {"name": "...", "address": "...", "pubkey": "hex..."}
let ident = ctx.myLib[].identity()
## Returns JSON string: {"name": "..."}
let identJson = %*{
"name": ident.getName(),
"address": ident.getAddr(),
"pubkey": ident.getPubkey().toHex()
"name": ctx.myLib[].getId()
}
return ok($identJson)
@ -44,11 +39,7 @@ proc chat_create_intro_bundle(
userData: pointer
) {.ffi.} =
## Create an IntroBundle for initiating private conversations
## Returns JSON string: {"ident": "hex...", "ephemeral": "hex..."}
## Returns the intro bundle as an ASCII string (format: logos_chatintro_<version>_<base64url payload>)
let bundle = ctx.myLib[].createIntroBundle()
let bundleJson = %*{
"ident": bundle.ident.toHex(),
"ephemeral": bundle.ephemeral.toHex()
}
return ok($bundleJson)
return ok(string.fromBytes(bundle))

View File

@ -58,9 +58,6 @@ void set_event_callback(void *ctx, FFICallBack callback, void *userData);
// Get the client's identifier
int chat_get_id(void *ctx, FFICallBack callback, void *userData);
// Get the default inbox conversation ID
int chat_get_default_inbox_id(void *ctx, FFICallBack callback, void *userData);
//////////////////////////////////////////////////////////////////////////////
// Conversation Operations
//////////////////////////////////////////////////////////////////////////////
@ -75,10 +72,10 @@ int chat_get_conversation(void *ctx, FFICallBack callback, void *userData,
const char *convoId);
// Create a new private conversation with the given IntroBundle
// introBundleJson: JSON string with {"ident": "hex...", "ephemeral": "hex..."}
// introBundleStr: Intro bundle ASCII string as returned by chat_create_intro_bundle
// contentHex: Initial message content as hex-encoded string
int chat_new_private_conversation(void *ctx, FFICallBack callback,
void *userData, const char *introBundleJson,
void *userData, const char *introBundleStr,
const char *contentHex);
// Send a message to a conversation
@ -93,11 +90,11 @@ int chat_send_message(void *ctx, FFICallBack callback, void *userData,
//////////////////////////////////////////////////////////////////////////////
// Get the client identity
// Returns JSON: {"name": "...", "address": "...", "pubkey": "hex..."}
// Returns JSON: {"name": "..."}
int chat_get_identity(void *ctx, FFICallBack callback, void *userData);
// Create an IntroBundle for initiating private conversations
// Returns JSON: {"ident": "hex...", "ephemeral": "hex..."}
// Returns the intro bundle as an ASCII string (format: logos_chatintro_<version>_<base64url payload>)
int chat_create_intro_bundle(void *ctx, FFICallBack callback, void *userData);
#ifdef __cplusplus

View File

@ -10,10 +10,8 @@ import stew/byteutils
import
src/chat/client,
src/chat/conversations,
src/chat/identity,
src/chat/delivery/waku_client,
src/chat/proto_types,
library/declare_lib,
library/utils

View File

@ -139,7 +139,7 @@ proc notifyDeliveryAck(client: ChatClient, convo: Conversation,
# Functional
#################################################
proc createIntroBundle*(self: var ChatClient): seq[byte] =
proc createIntroBundle*(self: ChatClient): seq[byte] =
## Generates an IntroBundle for the client, which includes
## the required information to send a message.
result = self.libchatCtx.createIntroductionBundle().valueOr:
@ -198,6 +198,10 @@ proc parseMessage(client: ChatClient, msg: ChatPayload) {.raises: [ValueError].}
if opt_content.isSome():
let content = opt_content.get()
let convo = client.getConversation(content.conversationId)
if content.isNewConvo:
client.notifyNewConversation(convo)
# TODO: (P1) Add sender information from LibChat.
let msg = ReceivedMessage(timestamp:getCurrentTimestamp(),content: content.data )
client.notifyNewMessage(convo, msg)

2
vendor/libchat vendored

@ -1 +1 @@
Subproject commit d903eac011f31b9db83c0860235341d4340cf5f0
Subproject commit a9ca4ffb7de90ea4cd269350c189c19fb78a2589