mirror of
https://github.com/logos-messaging/nim-chat-poc.git
synced 2026-07-05 07:59:32 +00:00
Wires the existing mix_lez_chat simulation to drive the gifter's EIP-191 allowlist auth path end-to-end: * bumps vendor/nwaku and vendor/logos-lez-rln (and, transitively, logos-delivery-module and its bundled logos-delivery copy) to pick up the auth plugin, the auto-registering client's EIP-191 signing, and the new --mix-gifter-allowlist / --mix-gifter-auth-key CLI flags. * adds a `gifterAuthKey` knob on WakuConfig + the JSON config bridge in client_api so chat sender/receiver instances sign their gifter requests too. * commits 5 fixed test secp256k1 keys (one per non-gifter mix node and per chat client) under simulations/mix_lez_chat/fixtures/gifter_auth/ along with their derived addresses. * run_simulation.sh sources keys.env+addresses.env, sets `mixGifterAllowlist` on mix node 0, and threads the matching `mixGifterAuthKey` / `gifterAuthKey` into nodes 1-3 and the receiver/sender configs. Test fixtures only — keys must never be reused outside this sim.
183 lines
5.4 KiB
Nim
183 lines
5.4 KiB
Nim
## Client API - FFI bindings for Client lifecycle and operations
|
|
## Uses the {.ffi.} pragma for async request handling
|
|
|
|
import std/json
|
|
import chronicles
|
|
import chronos
|
|
import ffi
|
|
|
|
import src/chat
|
|
import src/chat/delivery/waku_client
|
|
import library/utils
|
|
|
|
logScope:
|
|
topics = "chat ffi client"
|
|
|
|
#################################################
|
|
# Client Creation Request (for chat_new)
|
|
#################################################
|
|
|
|
type ChatCallbacks* = object
|
|
onNewMessage*: MessageCallback
|
|
onNewConversation*: NewConvoCallback
|
|
onDeliveryAck*: DeliveryAckCallback
|
|
|
|
proc createChatClient(
|
|
configJson: cstring, chatCallbacks: ChatCallbacks
|
|
): Future[Result[ChatClient, string]] {.async.} =
|
|
try:
|
|
let config = parseJson($configJson)
|
|
|
|
# Parse identity name
|
|
let name = config.getOrDefault("name").getStr("anonymous")
|
|
|
|
# Parse Waku configuration or use defaults
|
|
var wakuCfg = DefaultConfig()
|
|
|
|
if config.hasKey("port"):
|
|
wakuCfg.port = config["port"].getInt().uint16
|
|
|
|
if config.hasKey("clusterId"):
|
|
wakuCfg.clusterId = config["clusterId"].getInt().uint16
|
|
|
|
if config.hasKey("shardId"):
|
|
wakuCfg.shardId = @[config["shardId"].getInt().uint16]
|
|
|
|
if config.hasKey("clusterId") or config.hasKey("shardId"):
|
|
wakuCfg.pubsubTopic = "/waku/2/rs/" & $wakuCfg.clusterId & "/" & $wakuCfg.shardId[0]
|
|
|
|
if config.hasKey("staticPeers"):
|
|
wakuCfg.staticPeers = @[]
|
|
for peer in config["staticPeers"]:
|
|
wakuCfg.staticPeers.add(peer.getStr())
|
|
|
|
if config.hasKey("mixEnabled"):
|
|
wakuCfg.mixEnabled = config["mixEnabled"].getBool(false)
|
|
if config.hasKey("mixNodes"):
|
|
wakuCfg.mixNodes = @[]
|
|
for node in config["mixNodes"]:
|
|
wakuCfg.mixNodes.add(node.getStr())
|
|
if config.hasKey("destPeerAddr"):
|
|
wakuCfg.destPeerAddr = config["destPeerAddr"].getStr("")
|
|
if config.hasKey("minMixPoolSize"):
|
|
wakuCfg.minMixPoolSize = config["minMixPoolSize"].getInt(4)
|
|
if config.hasKey("gifterNodeAddr"):
|
|
wakuCfg.gifterNodeAddr = config["gifterNodeAddr"].getStr("")
|
|
if config.hasKey("gifterAuthKey"):
|
|
wakuCfg.gifterAuthKey = config["gifterAuthKey"].getStr("")
|
|
|
|
# Create Waku client
|
|
let wakuClient = initWakuClient(wakuCfg)
|
|
|
|
# Create Chat client
|
|
let client = ?newClient(wakuClient, installation_name = name)
|
|
|
|
# Register event handlers
|
|
client.onNewMessage(chatCallbacks.onNewMessage)
|
|
client.onNewConversation(chatCallbacks.onNewConversation)
|
|
client.onDeliveryAck(chatCallbacks.onDeliveryAck)
|
|
|
|
notice "Chat client created", name = name
|
|
return ok(client)
|
|
except CatchableError as e:
|
|
return err("failed to create client: " & e.msg)
|
|
|
|
registerReqFFI(CreateClientRequest, ctx: ptr FFIContext[ChatClient]):
|
|
proc(
|
|
configJson: cstring, chatCallbacks: ChatCallbacks
|
|
): Future[Result[string, string]] {.async.} =
|
|
ctx.myLib[] = (await createChatClient(configJson, chatCallbacks)).valueOr:
|
|
error "CreateClientRequest failed", error = error
|
|
return err($error)
|
|
return ok("")
|
|
|
|
#################################################
|
|
# ChatClient Lifecycle Operations
|
|
#################################################
|
|
|
|
proc chat_start(
|
|
ctx: ptr FFIContext[ChatClient],
|
|
callback: FFICallBack,
|
|
userData: pointer
|
|
) {.ffi.} =
|
|
try:
|
|
await ctx.myLib[].start()
|
|
return ok("")
|
|
except CatchableError as e:
|
|
error "chat_start failed", error = e.msg
|
|
return err("failed to start client: " & e.msg)
|
|
|
|
proc chat_stop(
|
|
ctx: ptr FFIContext[ChatClient],
|
|
callback: FFICallBack,
|
|
userData: pointer
|
|
) {.ffi.} =
|
|
try:
|
|
await ctx.myLib[].stop()
|
|
return ok("")
|
|
except CatchableError as e:
|
|
error "chat_stop failed", error = e.msg
|
|
return err("failed to stop client: " & e.msg)
|
|
|
|
#################################################
|
|
# ChatClient Info Operations
|
|
#################################################
|
|
|
|
proc chat_get_id(
|
|
ctx: ptr FFIContext[ChatClient],
|
|
callback: FFICallBack,
|
|
userData: pointer
|
|
) {.ffi.} =
|
|
## Get the client's identifier
|
|
let clientId = ctx.myLib[].getId()
|
|
return ok(clientId)
|
|
|
|
#################################################
|
|
# Mix Protocol Status
|
|
#################################################
|
|
|
|
proc chat_get_mix_status(
|
|
ctx: ptr FFIContext[ChatClient],
|
|
callback: FFICallBack,
|
|
userData: pointer
|
|
) {.ffi.} =
|
|
let client = ctx.myLib[]
|
|
let mixEnabled = client.ds.cfg.mixEnabled
|
|
var poolSize = 0
|
|
if mixEnabled:
|
|
poolSize = client.ds.getMixPoolSize()
|
|
let status = %*{
|
|
"mixEnabled": mixEnabled,
|
|
"mixReady": client.ds.mixReady,
|
|
"mixPoolSize": poolSize,
|
|
"minPoolSize": client.ds.cfg.minMixPoolSize
|
|
}
|
|
return ok($status)
|
|
|
|
#################################################
|
|
# Conversation List Operations
|
|
#################################################
|
|
|
|
proc chat_list_conversations(
|
|
ctx: ptr FFIContext[ChatClient],
|
|
callback: FFICallBack,
|
|
userData: pointer
|
|
) {.ffi.} =
|
|
## List all conversations as JSON array
|
|
let convos = ctx.myLib[].listConversations()
|
|
var convoList = newJArray()
|
|
for convo in convos:
|
|
convoList.add(%*{"id": convo.id()})
|
|
return ok($convoList)
|
|
|
|
proc chat_get_conversation(
|
|
ctx: ptr FFIContext[ChatClient],
|
|
callback: FFICallBack,
|
|
userData: pointer,
|
|
convoId: cstring
|
|
) {.ffi.} =
|
|
## Get a specific conversation by ID
|
|
let convo = ctx.myLib[].getConversation($convoId)
|
|
return ok($(%*{"id": convo.id()}))
|
|
|