nim-chat-poc/library/liblogoschat.nim
2026-02-11 10:46:31 -08:00

99 lines
3.1 KiB
Nim

## liblogoschat - C bindings for the Chat SDK
## Main entry point for the shared library
##
## This library exposes the Chat SDK functionality through a C-compatible FFI interface.
## It uses nim-ffi for thread-safe async request handling.
import std/[json, options]
import chronicles, chronos, ffi
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
logScope:
topics = "chat ffi"
################################################################################
## Include different APIs, i.e. all procs with {.ffi.} pragma
include
./api/client_api,
./api/conversation_api,
./api/identity_api
################################################################################
proc chat_new(
configJson: cstring, callback: FFICallBack, userData: pointer
): pointer {.dynlib, exportc, cdecl.} =
initializeLibrary()
## Creates a new instance of the ChatClient.
if isNil(callback):
echo "error: missing callback in chat_new"
return nil
## Create the Chat thread that will keep waiting for req from the main thread.
var ctx = ffi.createFFIContext[ChatClient]().valueOr:
let msg = "Error in createFFIContext: " & $error
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)), userData)
return nil
ctx.userData = userData
proc onNewMessage(ctx: ptr FFIContext[ChatClient]): MessageCallback =
return proc(conversation: Conversation, msg: ReceivedMessage): Future[void] {.async.} =
callEventCallback(ctx, "onNewMessage"):
$newJsonMessageEvent(
conversation.id(),
"",
msg.content.toHex(),
msg.timestamp
)
proc onNewConversation(ctx: ptr FFIContext[ChatClient]): NewConvoCallback =
return proc(conversation: Conversation): Future[void] {.async.} =
callEventCallback(ctx, "onNewConversation"):
$newJsonConversationEvent(conversation.id(), "private")
proc onDeliveryAck(ctx: ptr FFIContext[ChatClient]): DeliveryAckCallback =
return proc(conversation: Conversation, msgId: MessageId): Future[void] {.async.} =
callEventCallback(ctx, "onDeliveryAck"):
$newJsonDeliveryAckEvent(conversation.id(), msgId)
let chatCallbacks = ChatCallbacks(
onNewMessage: onNewMessage(ctx),
onNewConversation: onNewConversation(ctx),
onDeliveryAck: onDeliveryAck(ctx),
)
ffi.sendRequestToFFIThread(
ctx, CreateClientRequest.ffiNewReq(callback, userData, configJson, chatCallbacks)
).isOkOr:
let msg = "error in sendRequestToFFIThread: " & $error
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)), userData)
return nil
return ctx
proc chat_destroy(
ctx: ptr FFIContext[ChatClient], callback: FFICallBack, userData: pointer
): cint {.dynlib, exportc, cdecl.} =
initializeLibrary()
checkParams(ctx, callback, userData)
ffi.destroyFFIContext(ctx).isOkOr:
let msg = "liblogoschat error: " & $error
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)), userData)
return RET_ERR
callback(RET_OK, nil, 0, userData)
return RET_OK