feat: migrate the FFI layer to nim-ffi 0.2.0

nim-ffi 0.2.0 reshapes the authoring model: `.ffi.` procs take the
library value plus typed params instead of threading (ctx, callback,
userData) by hand, the macro validates the context itself, and payloads
ride the wire as CBOR rather than ad-hoc JSON strings. The old idiom no
longer compiles against it, so the whole surface moves at once.

Proc names are camelCase chosen so the generated snake_case export
matches the previous C symbol exactly (wakuRelayPublish ->
waku_relay_publish), keeping the ABI names stable.

Node lifecycle now uses the dedicated pragmas: `.ffiCtor.` for
create_node (LogosDelivery.new already returns the Future[Result[...]]
the contract wants) and `.ffiDtor.` for destroy. Contexts come from the
macro-emitted FFIContextPool, which caps live contexts at 32.

Events become typed `.ffiEvent.` procs over `.ffi.` payload objects. The
payloads carry wire-friendly scalars rather than the domain types, which
are not serialisable; byte fields stay base64. This is what makes the
generated bindings emit typed listeners instead of leaving consumers to
register by name and parse JSON themselves.

The payload fields are deliberately unexported. genBindings copies field
names verbatim, so an export marker leaks into the generated Rust as
`pub payload*: String` and the file does not parse -- a nim-ffi bug (it
strips the marker from type names but not fields, so its single-file
examples never hit it). Construction therefore lives behind the emit*
procs in declare_lib, which also keeps event emission in one place and
collapses each listener body to a single call.

`requireInitializedNode` is gone: the macro rejects a null/invalid ctx
before the handler runs, so all 14 call sites were redundant.

Relay and filter push handlers are declared `raises: [Defect]`, so the
emit call is wrapped explicitly -- the dispatch path no longer guards
the body for us.

genBindings() emits the C/C++/Rust bindings and must stay last in the
compilation root; it is a no-op without -d:ffiGenBindings. The Rust
output is checked in so consumers can vendor it directly.

Known gaps, tracked separately: the hand-written liblogosdelivery.h /
_kernel.h still declare the pre-CBOR signatures and need generating or
dropping, and nimble resolves cbor_serialization 0.4.0 while the lock
and nim-ffi both pin 0.3.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ivan FB 2026-07-16 00:14:42 +02:00
parent a49a892ae2
commit 7080a629da
No known key found for this signature in database
GPG Key ID: DF0C67A04C543270
25 changed files with 2436 additions and 541 deletions

View File

@ -154,17 +154,39 @@ Note: The `payload` field should be base64-encoded.
### Events
#### `logosdelivery_set_event_callback`
Sets a callback that will be invoked whenever an event occurs (e.g., message received).
#### `logosdelivery_add_event_listener`
Registers a callback invoked whenever the named event fires (e.g., message received).
Listeners are registered per event name, so register once for each event you want
to observe.
```c
void logosdelivery_set_event_callback(
uint64_t logosdelivery_add_event_listener(
void *ctx,
const char *eventName,
FFICallBack callback,
void *userData
);
```
**Returns:** The listener id (> 0), or 0 if `callback` is NULL.
Event names: `onMessageSent`, `onMessageError`, `onMessagePropagated`,
`onMessageReceived`, `onConnectionStatusChange`, `onTopicHealthChange`,
`onConnectionChange`, `onChannelMessageReceived`, `onChannelMessageSent`,
`onChannelMessageError`, `onReceivedMessage`.
#### `logosdelivery_remove_event_listener`
Unregisters a previously added listener.
```c
int logosdelivery_remove_event_listener(
void *ctx,
uint64_t listenerId
);
```
**Returns:** `RET_OK` when a listener was removed, `RET_ERR` otherwise.
**Important:** The callback should be fast, non-blocking, and thread-safe.
## Building

View File

@ -7,46 +7,34 @@ import
logos_delivery/api/types,
../declare_lib
proc logosdelivery_channel_create(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
channelIdStr: cstring,
contentTopicStr: cstring,
senderIdStr: cstring,
) {.ffi.} =
requireInitializedNode(ctx, "ChannelCreate"):
proc logosdeliveryChannelCreate*(
lib: LogosDelivery,
channelIdStr: string,
contentTopicStr: string,
senderIdStr: string,
): Future[Result[string, string]] {.ffi.} =
requireChannels(lib, "ChannelCreate"):
return err(errMsg)
requireChannels(ctx, "ChannelCreate"):
return err(errMsg)
let id = ctx.myLib[].reliableChannelManager.createReliableChannel(
ChannelId($channelIdStr),
ContentTopic($contentTopicStr),
SdsParticipantID($senderIdStr),
let id = lib.reliableChannelManager.createReliableChannel(
ChannelId(channelIdStr),
ContentTopic(contentTopicStr),
SdsParticipantID(senderIdStr),
).valueOr:
return err("ChannelCreate failed: " & $error)
return ok(string(id))
proc logosdelivery_channel_send(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
channelIdStr: cstring,
messageJson: cstring,
) {.ffi.} =
proc logosdeliveryChannelSend*(
lib: LogosDelivery, channelIdStr: string, messageJson: string
): Future[Result[string, string]] {.ffi.} =
## `messageJson` carries `{ "payload": <base64>, "ephemeral": <bool> }`.
requireInitializedNode(ctx, "ChannelSend"):
return err(errMsg)
requireChannels(ctx, "ChannelSend"):
requireChannels(lib, "ChannelSend"):
return err(errMsg)
var jsonNode: JsonNode
try:
jsonNode = parseJson($messageJson)
jsonNode = parseJson(messageJson)
except Exception as e:
return err("Failed to parse channel message JSON: " & e.msg)
@ -59,27 +47,19 @@ proc logosdelivery_channel_send(
let ephemeral = jsonNode.getOrDefault("ephemeral").getBool(false)
let requestId = (
await ctx.myLib[].reliableChannelManager.send(
ChannelId($channelIdStr), payload, ephemeral
)
await lib.reliableChannelManager.send(ChannelId(channelIdStr), payload, ephemeral)
).valueOr:
return err("ChannelSend failed: " & $error)
return ok($requestId)
proc logosdelivery_channel_close(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
channelIdStr: cstring,
) {.ffi.} =
requireInitializedNode(ctx, "ChannelClose"):
proc logosdeliveryChannelClose*(
lib: LogosDelivery, channelIdStr: string
): Future[Result[string, string]] {.ffi.} =
requireChannels(lib, "ChannelClose"):
return err(errMsg)
requireChannels(ctx, "ChannelClose"):
return err(errMsg)
(await ctx.myLib[].reliableChannelManager.closeChannel(ChannelId($channelIdStr))).isOkOr:
(await lib.reliableChannelManager.closeChannel(ChannelId(channelIdStr))).isOkOr:
return err("ChannelClose failed: " & $error)
return ok("")

View File

@ -1,52 +1,186 @@
import ffi
import std/locks
import results
import logos_delivery
import
logos_delivery/waku/common/base64,
logos_delivery/waku/waku_core/message,
logos_delivery/waku/waku_core/message/digest
declareLibrary("logosdelivery")
declareLibrary("logosdelivery", LogosDelivery)
var eventCallbackLock: Lock
initLock(eventCallbackLock)
template requireInitializedNode*(
ctx: ptr FFIContext[LogosDelivery], opName: string, onError: untyped
) =
if isNil(ctx):
let errMsg {.inject.} = opName & " failed: invalid context"
onError
elif isNil(ctx.myLib) or isNil(ctx.myLib[]):
let errMsg {.inject.} = opName & " failed: node is not initialized"
onError
template requireMessaging*(
ctx: ptr FFIContext[LogosDelivery], opName: string, onError: untyped
) =
## Use after `requireInitializedNode`. Fails if the node has no messaging client
## (a kernel-only / fleet node).
ctx.myLib[].ensureMessaging().isOkOr:
template requireMessaging*(lib: LogosDelivery, opName: string, onError: untyped) =
## Fails if the node has no messaging client (a kernel-only / fleet node).
lib.ensureMessaging().isOkOr:
let errMsg {.inject.} = opName & " failed: " & error
onError
template requireChannels*(
ctx: ptr FFIContext[LogosDelivery], opName: string, onError: untyped
) =
## Use after `requireInitializedNode`. Fails if the node has no reliable channel
## manager (a kernel-only / fleet node).
ctx.myLib[].ensureChannels().isOkOr:
template requireChannels*(lib: LogosDelivery, opName: string, onError: untyped) =
## Fails if the node has no reliable channel manager (a kernel-only / fleet node).
lib.ensureChannels().isOkOr:
let errMsg {.inject.} = opName & " failed: " & error
onError
proc logosdelivery_set_event_callback(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.dynlib, exportc, cdecl.} =
if isNil(ctx):
echo "error: invalid context in logosdelivery_set_event_callback"
return
# Outgoing event payloads. These mirror the domain event types but hold only
# wire-friendly scalars, so they serialise through the library's ABI format and
# surface as typed listeners in the generated bindings. Byte fields are
# base64-encoded strings.
#
# The fields are deliberately unexported: genBindings copies field names
# verbatim, so an export marker would leak into the generated bindings as
# `pub payload*: String`. The `emit*` procs below are the construction path.
# prevent race conditions that might happen due incorrect usage.
eventCallbackLock.acquire()
defer:
eventCallbackLock.release()
type WakuMessagePayload* {.ffi.} = object
payload: string
contentTopic: string
version: uint32
timestamp: int64
ephemeral: bool
meta: string
proof: string
ctx[].eventCallback = cast[pointer](callback)
ctx[].eventUserData = userData
type MessageSentPayload* {.ffi.} = object
requestId: string
messageHash: string
type MessageErrorPayload* {.ffi.} = object
requestId: string
messageHash: string
error: string
type MessagePropagatedPayload* {.ffi.} = object
requestId: string
messageHash: string
type MessageReceivedPayload* {.ffi.} = object
messageHash: string
message: WakuMessagePayload
type ConnectionStatusChangePayload* {.ffi.} = object
connectionStatus: string
type TopicHealthChangePayload* {.ffi.} = object
pubsubTopic: string
topicHealth: string
type ConnectionChangePayload* {.ffi.} = object
peerId: string
peerEvent: string
type ChannelMessageReceivedPayload* {.ffi.} = object
channelId: string
senderId: string
payload: string
type ChannelMessageSentPayload* {.ffi.} = object
channelId: string
requestId: string
type ChannelMessageErrorPayload* {.ffi.} = object
channelId: string
requestId: string
error: string
type ReceivedMessagePayload* {.ffi.} = object
pubsubTopic: string
messageHash: string
wakuMessage: WakuMessagePayload
proc onMessageSent(e: MessageSentPayload) {.ffiEvent: "onMessageSent".}
proc onMessageError(e: MessageErrorPayload) {.ffiEvent: "onMessageError".}
proc onMessagePropagated(e: MessagePropagatedPayload) {.ffiEvent: "onMessagePropagated".}
proc onMessageReceived(e: MessageReceivedPayload) {.ffiEvent: "onMessageReceived".}
proc onConnectionStatusChange(
e: ConnectionStatusChangePayload
) {.ffiEvent: "onConnectionStatusChange".}
proc onTopicHealthChange(e: TopicHealthChangePayload) {.ffiEvent: "onTopicHealthChange".}
proc onConnectionChange(e: ConnectionChangePayload) {.ffiEvent: "onConnectionChange".}
proc onChannelMessageReceived(
e: ChannelMessageReceivedPayload
) {.ffiEvent: "onChannelMessageReceived".}
proc onChannelMessageSent(
e: ChannelMessageSentPayload
) {.ffiEvent: "onChannelMessageSent".}
proc onChannelMessageError(
e: ChannelMessageErrorPayload
) {.ffiEvent: "onChannelMessageError".}
proc onReceivedMessage(e: ReceivedMessagePayload) {.ffiEvent: "onReceivedMessage".}
proc toWakuMessagePayload(msg: WakuMessage): WakuMessagePayload =
return WakuMessagePayload(
payload: string(base64.encode(msg.payload)),
contentTopic: msg.contentTopic,
version: uint32(msg.version),
timestamp: int64(msg.timestamp),
ephemeral: msg.ephemeral,
meta: string(base64.encode(msg.meta)),
proof: string(base64.encode(msg.proof)),
)
proc emitMessageSent*(requestId, messageHash: string) =
onMessageSent(MessageSentPayload(requestId: requestId, messageHash: messageHash))
proc emitMessageError*(requestId, messageHash, error: string) =
onMessageError(
MessageErrorPayload(
requestId: requestId, messageHash: messageHash, error: error
)
)
proc emitMessagePropagated*(requestId, messageHash: string) =
onMessagePropagated(
MessagePropagatedPayload(requestId: requestId, messageHash: messageHash)
)
proc emitMessageReceived*(messageHash: string, msg: WakuMessage) =
onMessageReceived(
MessageReceivedPayload(
messageHash: messageHash, message: toWakuMessagePayload(msg)
)
)
proc emitConnectionStatusChange*(connectionStatus: string) =
onConnectionStatusChange(
ConnectionStatusChangePayload(connectionStatus: connectionStatus)
)
proc emitTopicHealthChange*(pubsubTopic, topicHealth: string) =
onTopicHealthChange(
TopicHealthChangePayload(pubsubTopic: pubsubTopic, topicHealth: topicHealth)
)
proc emitConnectionChange*(peerId, peerEvent: string) =
onConnectionChange(ConnectionChangePayload(peerId: peerId, peerEvent: peerEvent))
proc emitChannelMessageReceived*(channelId, senderId: string, payload: seq[byte]) =
onChannelMessageReceived(
ChannelMessageReceivedPayload(
channelId: channelId,
senderId: senderId,
payload: string(base64.encode(payload)),
)
)
proc emitChannelMessageSent*(channelId, requestId: string) =
onChannelMessageSent(
ChannelMessageSentPayload(channelId: channelId, requestId: requestId)
)
proc emitChannelMessageError*(channelId, requestId, error: string) =
onChannelMessageError(
ChannelMessageErrorPayload(
channelId: channelId, requestId: requestId, error: error
)
)
proc emitReceivedMessage*(pubSubTopic: string, msg: WakuMessage) =
onReceivedMessage(
ReceivedMessagePayload(
pubsubTopic: pubSubTopic,
messageHash: computeMessageHash(pubSubTopic, msg).to0xHex(),
wakuMessage: toWakuMessagePayload(msg),
)
)

View File

@ -2,45 +2,33 @@ import std/strutils
import chronos, results, ffi
import logos_delivery, library/declare_lib
proc waku_version(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
let v = (await ctx.myLib[].waku.version()).valueOr:
proc wakuVersion*(lib: LogosDelivery): Future[Result[string, string]] {.ffi.} =
let v = (await lib.waku.version()).valueOr:
return err(error)
return ok(v)
proc waku_listen_addresses(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
proc wakuListenAddresses*(lib: LogosDelivery): Future[Result[string, string]] {.ffi.} =
## returns a comma-separated string of the listen addresses
let addrs = (await ctx.myLib[].waku.listenAddresses()).valueOr:
let addrs = (await lib.waku.listenAddresses()).valueOr:
return err(error)
return ok(addrs.join(","))
proc waku_get_my_enr(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
let enrUri = (await ctx.myLib[].waku.myEnr()).valueOr:
proc wakuGetMyEnr*(lib: LogosDelivery): Future[Result[string, string]] {.ffi.} =
let enrUri = (await lib.waku.myEnr()).valueOr:
return err(error)
return ok(enrUri)
proc waku_get_my_peerid(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
let peerId = (await ctx.myLib[].waku.myPeerId()).valueOr:
proc wakuGetMyPeerid*(lib: LogosDelivery): Future[Result[string, string]] {.ffi.} =
let peerId = (await lib.waku.myPeerId()).valueOr:
return err(error)
return ok(peerId)
proc waku_get_metrics(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
let m = (await ctx.myLib[].waku.metrics()).valueOr:
proc wakuGetMetrics*(lib: LogosDelivery): Future[Result[string, string]] {.ffi.} =
let m = (await lib.waku.metrics()).valueOr:
return err(error)
return ok(m)
proc waku_is_online(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
let online = (await ctx.myLib[].waku.isOnline()).valueOr:
proc wakuIsOnline*(lib: LogosDelivery): Future[Result[string, string]] {.ffi.} =
let online = (await lib.waku.isOnline()).valueOr:
return err(error)
return ok($online)

View File

@ -2,58 +2,43 @@ import std/strutils
import chronos, chronicles, results, ffi
import logos_delivery, library/declare_lib
proc waku_discv5_update_bootnodes(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
bootnodes: cstring,
) {.ffi.} =
proc wakuDiscv5UpdateBootnodes*(
lib: LogosDelivery, bootnodes: string
): Future[Result[string, string]] {.ffi.} =
## Updates the bootnode list used for discovering new peers via DiscoveryV5
## bootnodes - JSON array containing the bootnode ENRs i.e. `["enr:...", "enr:..."]`
(await ctx.myLib[].waku.discv5UpdateBootnodes($bootnodes)).isOkOr:
(await lib.waku.discv5UpdateBootnodes(bootnodes)).isOkOr:
error "UPDATE_DISCV5_BOOTSTRAP_NODES failed", error = error
return err(error)
return ok("discovery request processed correctly")
proc waku_dns_discovery(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
enrTreeUrl: cstring,
nameDnsServer: cstring,
timeoutMs: cint,
) {.ffi.} =
proc wakuDnsDiscovery*(
lib: LogosDelivery, enrTreeUrl: string, nameDnsServer: string, timeoutMs: int32
): Future[Result[string, string]] {.ffi.} =
let nodes = (
await ctx.myLib[].waku.dnsDiscovery($enrTreeUrl, $nameDnsServer, int(timeoutMs))
await lib.waku.dnsDiscovery(enrTreeUrl, nameDnsServer, int(timeoutMs))
).valueOr:
error "GET_BOOTSTRAP_NODES failed", error = error
return err(error)
## returns a comma-separated string of bootstrap nodes' multiaddresses
return ok(nodes.join(","))
proc waku_start_discv5(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
(await ctx.myLib[].waku.startDiscv5()).isOkOr:
proc wakuStartDiscv5*(lib: LogosDelivery): Future[Result[string, string]] {.ffi.} =
(await lib.waku.startDiscv5()).isOkOr:
error "START_DISCV5 failed", error = error
return err(error)
return ok("discv5 started correctly")
proc waku_stop_discv5(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
(await ctx.myLib[].waku.stopDiscv5()).isOkOr:
proc wakuStopDiscv5*(lib: LogosDelivery): Future[Result[string, string]] {.ffi.} =
(await lib.waku.stopDiscv5()).isOkOr:
error "STOP_DISCV5 failed", error = error
return err(error)
return ok("discv5 stopped correctly")
proc waku_peer_exchange_request(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
numPeers: uint64,
) {.ffi.} =
let numValidPeers = (await ctx.myLib[].waku.peerExchangeRequest(numPeers)).valueOr:
proc wakuPeerExchangeRequest*(
lib: LogosDelivery, numPeers: uint64
): Future[Result[string, string]] {.ffi.} =
let numValidPeers = (await lib.waku.peerExchangeRequest(numPeers)).valueOr:
error "waku_peer_exchange_request failed", error = error
return err(error)
return ok($numValidPeers)

View File

@ -6,75 +6,58 @@ type PeerInfo = object
protocols: seq[string]
addresses: seq[string]
proc waku_get_peerids_from_peerstore(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
proc wakuGetPeeridsFromPeerstore*(
lib: LogosDelivery
): Future[Result[string, string]] {.ffi.} =
## returns a comma-separated string of peerIDs
let peerIds = (await ctx.myLib[].waku.peerIdsFromPeerstore()).valueOr:
let peerIds = (await lib.waku.peerIdsFromPeerstore()).valueOr:
return err(error)
return ok(peerIds.join(","))
proc waku_connect(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
peerMultiAddr: cstring,
timeoutMs: cuint,
) {.ffi.} =
let peers = ($peerMultiAddr).split(",")
(await ctx.myLib[].waku.connect(peers, uint32(timeoutMs))).isOkOr:
proc wakuConnect*(
lib: LogosDelivery, peerMultiAddr: string, timeoutMs: uint32
): Future[Result[string, string]] {.ffi.} =
let peers = peerMultiAddr.split(",")
(await lib.waku.connect(peers, uint32(timeoutMs))).isOkOr:
return err(error)
return ok("")
proc waku_disconnect_peer_by_id(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
peerId: cstring,
) {.ffi.} =
(await ctx.myLib[].waku.disconnectPeerById($peerId)).isOkOr:
proc wakuDisconnectPeerById*(
lib: LogosDelivery, peerId: string
): Future[Result[string, string]] {.ffi.} =
(await lib.waku.disconnectPeerById(peerId)).isOkOr:
error "DISCONNECT_PEER_BY_ID failed", error = error
return err(error)
return ok("")
proc waku_disconnect_all_peers(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
(await ctx.myLib[].waku.disconnectAllPeers()).isOkOr:
proc wakuDisconnectAllPeers*(
lib: LogosDelivery
): Future[Result[string, string]] {.ffi.} =
(await lib.waku.disconnectAllPeers()).isOkOr:
return err(error)
return ok("")
proc waku_dial_peer(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
peerMultiAddr: cstring,
protocol: cstring,
timeoutMs: cuint,
) {.ffi.} =
(await ctx.myLib[].waku.dialPeer($peerMultiAddr, $protocol, int(timeoutMs))).isOkOr:
proc wakuDialPeer*(
lib: LogosDelivery, peerMultiAddr: string, protocol: string, timeoutMs: uint32
): Future[Result[string, string]] {.ffi.} =
(await lib.waku.dialPeer(peerMultiAddr, protocol, int(timeoutMs))).isOkOr:
error "DIAL_PEER failed", error = error
return err(error)
return ok("")
proc waku_dial_peer_by_id(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
peerId: cstring,
protocol: cstring,
timeoutMs: cuint,
) {.ffi.} =
(await ctx.myLib[].waku.dialPeerById($peerId, $protocol, int(timeoutMs))).isOkOr:
proc wakuDialPeerById*(
lib: LogosDelivery, peerId: string, protocol: string, timeoutMs: uint32
): Future[Result[string, string]] {.ffi.} =
(await lib.waku.dialPeerById(peerId, protocol, int(timeoutMs))).isOkOr:
error "DIAL_PEER_BY_ID failed", error = error
return err(error)
return ok("")
proc waku_get_connected_peers_info(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
proc wakuGetConnectedPeersInfo*(
lib: LogosDelivery
): Future[Result[string, string]] {.ffi.} =
## returns a JSON string mapping peerIDs to objects with protocols and addresses
let peers = (await ctx.myLib[].waku.connectedPeersInfo()).valueOr:
let peers = (await lib.waku.connectedPeersInfo()).valueOr:
return err(error)
var peersMap = initTable[string, PeerInfo]()
@ -84,21 +67,18 @@ proc waku_get_connected_peers_info(
return ok($(%*peersMap))
proc waku_get_connected_peers(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
proc wakuGetConnectedPeers*(
lib: LogosDelivery
): Future[Result[string, string]] {.ffi.} =
## returns a comma-separated string of peerIDs
let peerIds = (await ctx.myLib[].waku.connectedPeers()).valueOr:
let peerIds = (await lib.waku.connectedPeers()).valueOr:
return err(error)
return ok(peerIds.join(","))
proc waku_get_peerids_by_protocol(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
protocol: cstring,
) {.ffi.} =
proc wakuGetPeeridsByProtocol*(
lib: LogosDelivery, protocol: string
): Future[Result[string, string]] {.ffi.} =
## returns a comma-separated string of peerIDs that mount the given protocol
let peerIds = (await ctx.myLib[].waku.peerIdsByProtocol($protocol)).valueOr:
let peerIds = (await lib.waku.peerIdsByProtocol(protocol)).valueOr:
return err(error)
return ok(peerIds.join(","))

View File

@ -1,13 +1,9 @@
import chronos, results, ffi
import logos_delivery, library/declare_lib
proc waku_ping_peer(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
peerAddr: cstring,
timeoutMs: cuint,
) {.ffi.} =
let rttNanos = (await ctx.myLib[].waku.pingPeer($peerAddr, int(timeoutMs))).valueOr:
proc wakuPingPeer*(
lib: LogosDelivery, peerAddr: string, timeoutMs: uint32
): Future[Result[string, string]] {.ffi.} =
let rttNanos = (await lib.waku.pingPeer(peerAddr, int(timeoutMs))).valueOr:
return err(error)
return ok($rttNanos)

View File

@ -9,49 +9,45 @@ import
library/events/json_message_event,
library/declare_lib
proc waku_filter_subscribe(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
pubSubTopic: cstring,
contentTopics: cstring,
) {.ffi.} =
proc onReceivedMessage(ctx: ptr FFIContext[LogosDelivery]): FilterPushHandler =
proc wakuFilterSubscribe*(
lib: LogosDelivery, pubSubTopic: string, contentTopics: string
): Future[Result[string, string]] {.ffi.} =
proc receivedMessageHandler(): FilterPushHandler =
return proc(pubsubTopic: PubsubTopic, msg: WakuMessage) {.async.} =
callEventCallback(ctx, "onReceivedMessage"):
$JsonMessageEvent.new(pubsubTopic, msg)
# This handler is `raises: [Defect]`, so the payload build has to be guarded.
try:
emitReceivedMessage(pubsubTopic, msg)
except Exception, CatchableError:
error "onReceivedMessage failed to emit event",
error = getCurrentExceptionMsg()
(
await ctx.myLib[].waku.filterSubscribe(
PubsubTopic($pubSubTopic),
($contentTopics).split(",").mapIt(ContentTopic(it)),
FilterPushHandler(onReceivedMessage(ctx)),
await lib.waku.filterSubscribe(
PubsubTopic(pubSubTopic),
contentTopics.split(",").mapIt(ContentTopic(it)),
FilterPushHandler(receivedMessageHandler()),
)
).isOkOr:
error "fail filter subscribe", error = error
return err(error)
return ok("")
proc waku_filter_unsubscribe(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
pubSubTopic: cstring,
contentTopics: cstring,
) {.ffi.} =
proc wakuFilterUnsubscribe*(
lib: LogosDelivery, pubSubTopic: string, contentTopics: string
): Future[Result[string, string]] {.ffi.} =
(
await ctx.myLib[].waku.filterUnsubscribe(
PubsubTopic($pubSubTopic), ($contentTopics).split(",").mapIt(ContentTopic(it))
await lib.waku.filterUnsubscribe(
PubsubTopic(pubSubTopic), contentTopics.split(",").mapIt(ContentTopic(it))
)
).isOkOr:
error "fail filter unsubscribe", error = error
return err(error)
return ok("")
proc waku_filter_unsubscribe_all(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
(await ctx.myLib[].waku.filterUnsubscribeAll()).isOkOr:
proc wakuFilterUnsubscribeAll*(
lib: LogosDelivery
): Future[Result[string, string]] {.ffi.} =
(await lib.waku.filterUnsubscribeAll()).isOkOr:
error "fail filter unsubscribe all", error = error
return err(error)
return ok("")

View File

@ -7,16 +7,12 @@ import
library/events/json_message_event,
library/declare_lib
proc waku_lightpush_publish(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
pubSubTopic: cstring,
jsonWakuMessage: cstring,
) {.ffi.} =
proc wakuLightpushPublish*(
lib: LogosDelivery, pubSubTopic: string, jsonWakuMessage: string
): Future[Result[string, string]] {.ffi.} =
var jsonMessage: JsonMessage
try:
let jsonContent = parseJson($jsonWakuMessage)
let jsonContent = parseJson(jsonWakuMessage)
jsonMessage = JsonMessage.fromJsonNode(jsonContent).valueOr:
raise newException(JsonParsingError, $error)
except JsonParsingError as exc:
@ -26,7 +22,7 @@ proc waku_lightpush_publish(
return err("Problem building the WakuMessage: " & $error)
let msgHashHex = (
await ctx.myLib[].waku.lightpushPublish(PubsubTopic($pubSubTopic), msg)
await lib.waku.lightpushPublish(PubsubTopic(pubSubTopic), msg)
).valueOr:
error "PUBLISH failed", error = error
return err(error)

View File

@ -8,111 +8,87 @@ import
library/events/json_message_event,
library/declare_lib
proc waku_relay_get_peers_in_mesh(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
pubSubTopic: cstring,
) {.ffi.} =
let peers = (await ctx.myLib[].waku.relayPeersInMesh(PubsubTopic($pubSubTopic))).valueOr:
proc wakuRelayGetPeersInMesh*(
lib: LogosDelivery, pubSubTopic: string
): Future[Result[string, string]] {.ffi.} =
let peers = (await lib.waku.relayPeersInMesh(PubsubTopic(pubSubTopic))).valueOr:
error "LIST_MESH_PEERS failed", error = error
return err(error)
## returns a comma-separated string of peerIDs
return ok(peers.join(","))
proc waku_relay_get_num_peers_in_mesh(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
pubSubTopic: cstring,
) {.ffi.} =
let n = (await ctx.myLib[].waku.relayNumPeersInMesh(PubsubTopic($pubSubTopic))).valueOr:
proc wakuRelayGetNumPeersInMesh*(
lib: LogosDelivery, pubSubTopic: string
): Future[Result[string, string]] {.ffi.} =
let n = (await lib.waku.relayNumPeersInMesh(PubsubTopic(pubSubTopic))).valueOr:
error "NUM_MESH_PEERS failed", error = error
return err(error)
return ok($n)
proc waku_relay_get_connected_peers(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
pubSubTopic: cstring,
) {.ffi.} =
proc wakuRelayGetConnectedPeers*(
lib: LogosDelivery, pubSubTopic: string
): Future[Result[string, string]] {.ffi.} =
## Returns the list of all connected peers to an specific pubsub topic
let peers = (await ctx.myLib[].waku.relayConnectedPeers(PubsubTopic($pubSubTopic))).valueOr:
let peers = (await lib.waku.relayConnectedPeers(PubsubTopic(pubSubTopic))).valueOr:
error "LIST_CONNECTED_PEERS failed", error = error
return err(error)
return ok(peers.join(","))
proc waku_relay_get_num_connected_peers(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
pubSubTopic: cstring,
) {.ffi.} =
let n = (await ctx.myLib[].waku.relayNumConnectedPeers(PubsubTopic($pubSubTopic))).valueOr:
proc wakuRelayGetNumConnectedPeers*(
lib: LogosDelivery, pubSubTopic: string
): Future[Result[string, string]] {.ffi.} =
let n = (await lib.waku.relayNumConnectedPeers(PubsubTopic(pubSubTopic))).valueOr:
error "NUM_CONNECTED_PEERS failed", error = error
return err(error)
return ok($n)
proc waku_relay_add_protected_shard(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
clusterId: cint,
shardId: cint,
publicKey: cstring,
) {.ffi.} =
proc wakuRelayAddProtectedShard*(
lib: LogosDelivery, clusterId: int32, shardId: int32, publicKey: string
): Future[Result[string, string]] {.ffi.} =
## Protects a shard with a public key
(
await ctx.myLib[].waku.relayAddProtectedShard(
uint16(clusterId), uint16(shardId), $publicKey
await lib.waku.relayAddProtectedShard(
uint16(clusterId), uint16(shardId), publicKey
)
).isOkOr:
return err(error)
return ok("")
proc waku_relay_subscribe(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
pubSubTopic: cstring,
) {.ffi.} =
proc onReceivedMessage(ctx: ptr FFIContext[LogosDelivery]): WakuRelayHandler =
proc wakuRelaySubscribe*(
lib: LogosDelivery, pubSubTopic: string
): Future[Result[string, string]] {.ffi.} =
proc receivedMessageHandler(): WakuRelayHandler =
return proc(pubsubTopic: PubsubTopic, msg: WakuMessage) {.async.} =
callEventCallback(ctx, "onReceivedMessage"):
$JsonMessageEvent.new(pubsubTopic, msg)
# This handler is `raises: [Defect]`, so the payload build has to be guarded.
try:
emitReceivedMessage(pubsubTopic, msg)
except Exception, CatchableError:
error "onReceivedMessage failed to emit event",
error = getCurrentExceptionMsg()
(
await ctx.myLib[].waku.relaySubscribe(
PubsubTopic($pubSubTopic), WakuRelayHandler(onReceivedMessage(ctx))
await lib.waku.relaySubscribe(
PubsubTopic(pubSubTopic), WakuRelayHandler(receivedMessageHandler())
)
).isOkOr:
error "SUBSCRIBE failed", error = error
return err(error)
return ok("")
proc waku_relay_unsubscribe(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
pubSubTopic: cstring,
) {.ffi.} =
(await ctx.myLib[].waku.relayUnsubscribe(PubsubTopic($pubSubTopic))).isOkOr:
proc wakuRelayUnsubscribe*(
lib: LogosDelivery, pubSubTopic: string
): Future[Result[string, string]] {.ffi.} =
(await lib.waku.relayUnsubscribe(PubsubTopic(pubSubTopic))).isOkOr:
error "UNSUBSCRIBE failed", error = error
return err(error)
return ok("")
proc waku_relay_publish(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
pubSubTopic: cstring,
jsonWakuMessage: cstring,
timeoutMs: cuint,
) {.ffi.} =
proc wakuRelayPublish*(
lib: LogosDelivery, pubSubTopic: string, jsonWakuMessage: string, timeoutMs: uint32
): Future[Result[string, string]] {.ffi.} =
var jsonMessage: JsonMessage
try:
let jsonContent = parseJson($jsonWakuMessage)
let jsonContent = parseJson(jsonWakuMessage)
jsonMessage = JsonMessage.fromJsonNode(jsonContent).valueOr:
raise newException(JsonParsingError, $error)
except JsonParsingError as exc:
@ -122,44 +98,37 @@ proc waku_relay_publish(
return err("Problem building the WakuMessage: " & $error)
let msgHash = (
await ctx.myLib[].waku.relayPublish(
PubsubTopic($pubSubTopic), msg, uint32(timeoutMs)
)
await lib.waku.relayPublish(PubsubTopic(pubSubTopic), msg, uint32(timeoutMs))
).valueOr:
error "PUBLISH failed", error = error
return err(error)
return ok(msgHash)
proc waku_default_pubsub_topic(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
let topic = (await ctx.myLib[].waku.defaultPubsubTopic()).valueOr:
proc wakuDefaultPubsubTopic*(
lib: LogosDelivery
): Future[Result[string, string]] {.ffi.} =
let topic = (await lib.waku.defaultPubsubTopic()).valueOr:
return err(error)
return ok(string(topic))
proc waku_content_topic(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
appName: cstring,
appVersion: cuint,
contentTopicName: cstring,
encoding: cstring,
) {.ffi.} =
proc wakuContentTopic*(
lib: LogosDelivery,
appName: string,
appVersion: uint32,
contentTopicName: string,
encoding: string,
): Future[Result[string, string]] {.ffi.} =
let topic = (
await ctx.myLib[].waku.buildContentTopic(
$appName, uint32(appVersion), $contentTopicName, $encoding
await lib.waku.buildContentTopic(
appName, uint32(appVersion), contentTopicName, encoding
)
).valueOr:
return err(error)
return ok(string(topic))
proc waku_pubsub_topic(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
topicName: cstring,
) {.ffi.} =
let topic = (await ctx.myLib[].waku.buildPubsubTopic($topicName)).valueOr:
proc wakuPubsubTopic*(
lib: LogosDelivery, topicName: string
): Future[Result[string, string]] {.ffi.} =
let topic = (await lib.waku.buildPubsubTopic(topicName)).valueOr:
return err(error)
return ok(string(topic))

View File

@ -64,16 +64,11 @@ func fromJsonNode(jsonContent: JsonNode): Result[StoreQueryRequest, string] =
)
)
proc waku_store_query(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
jsonQuery: cstring,
peerAddr: cstring,
timeoutMs: cint,
) {.ffi.} =
proc wakuStoreQuery*(
lib: LogosDelivery, jsonQuery: string, peerAddr: string, timeoutMs: int32
): Future[Result[string, string]] {.ffi.} =
let jsonContentRes = catch:
parseJson($jsonQuery)
parseJson(jsonQuery)
if jsonContentRes.isErr():
return err("StoreRequest failed parsing store request: " & jsonContentRes.error.msg)
@ -81,7 +76,7 @@ proc waku_store_query(
let storeQueryRequest = ?fromJsonNode(jsonContentRes.get())
let queryResponse = (
await ctx.myLib[].waku.storeQuery(storeQueryRequest, $peerAddr, int(timeoutMs))
await lib.waku.storeQuery(storeQueryRequest, peerAddr, int(timeoutMs))
).valueOr:
return err("StoreRequest failed store query: " & error)

View File

@ -102,16 +102,25 @@ extern "C"
void *userData,
const char *channelId);
// Channel lifecycle events are delivered through the event callback set via
// logosdelivery_set_event_callback: "onChannelMessageReceived" (payload
// Channel lifecycle events are delivered to listeners registered via
// logosdelivery_add_event_listener: "onChannelMessageReceived" (payload
// base64-encoded), "onChannelMessageSent", "onChannelMessageError".
// Sets a callback that will be invoked whenever an event occurs.
// Registers a callback invoked whenever the named event fires. Listeners are
// per event name; register once per event you care about. Returns the listener
// id (> 0) to pass to logosdelivery_remove_event_listener, or 0 if callback is
// NULL.
// It is crucial that the passed callback is fast, non-blocking and potentially thread-safe.
void logosdelivery_set_event_callback(void *ctx,
uint64_t logosdelivery_add_event_listener(void *ctx,
const char *eventName,
FFICallBack callback,
void *userData);
// Unregisters the listener with the given id. Returns RET_OK when a listener
// was removed, RET_ERR otherwise.
int logosdelivery_remove_event_listener(void *ctx,
uint64_t listenerId);
// Retrieves the list of available node info IDs.
int logosdelivery_get_available_node_info_ids(void *ctx,
FFICallBack callback,

View File

@ -33,3 +33,8 @@ include
# logosdelivery_* surface in ./logos_delivery_api/node_api. The former
# waku_new / waku_start / waku_stop / waku_destroy entry points were removed to
# avoid maintaining two parallel node-lifecycle APIs.
# Must stay the last FFI call in the compilation root: it emits the C/C++/Rust
# bindings from the registries the annotations above populate. No-op unless
# built with -d:ffiGenBindings.
genBindings()

View File

@ -36,7 +36,7 @@ extern "C"
FFICallBack callback,
void *userData);
// NOTE: event callbacks are registered via logosdelivery_set_event_callback
// NOTE: event listeners are registered via logosdelivery_add_event_listener
// (declared above) which the waku_* API shares.
int waku_content_topic(void *ctx,

View File

@ -2,41 +2,29 @@ import std/[json, strutils]
import logos_delivery/waku/factory/waku_state_info
import tools/confutils/[cli_args, config_option_meta]
proc logosdelivery_get_available_node_info_ids(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
proc logosdeliveryGetAvailableNodeInfoIds*(
lib: LogosDelivery
): Future[Result[string, string]] {.ffi.} =
## Returns the list of all available node info item ids that
## can be queried with `get_node_info_item`.
requireInitializedNode(ctx, "GetNodeInfoIds"):
return err(errMsg)
return ok($lib.waku.stateInfo.getAllPossibleInfoItemIds())
return ok($ctx.myLib[].waku.stateInfo.getAllPossibleInfoItemIds())
proc logosdelivery_get_node_info(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
nodeInfoId: cstring,
) {.ffi.} =
proc logosdeliveryGetNodeInfo*(
lib: LogosDelivery, nodeInfoId: string
): Future[Result[string, string]] {.ffi.} =
## Returns the content of the node info item with the given id if it exists.
requireInitializedNode(ctx, "GetNodeInfoItem"):
return err(errMsg)
let infoItemIdEnum =
try:
parseEnum[NodeInfoId]($nodeInfoId)
parseEnum[NodeInfoId](nodeInfoId)
except ValueError:
return err("Invalid node info id: " & $nodeInfoId)
return err("Invalid node info id: " & nodeInfoId)
return ok(ctx.myLib[].waku.stateInfo.getNodeInfoItem(infoItemIdEnum))
return ok(lib.waku.stateInfo.getNodeInfoItem(infoItemIdEnum))
proc logosdelivery_get_available_configs(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
proc logosdeliveryGetAvailableConfigs*(
lib: LogosDelivery
): Future[Result[string, string]] {.ffi.} =
## Returns information about the accepted config items.
requireInitializedNode(ctx, "GetAvailableConfigs"):
return err(errMsg)
let optionMetas: seq[ConfigOptionMeta] = extractConfigOptionMeta(WakuNodeConf)
var configOptionDetails = newJArray()

View File

@ -8,64 +8,46 @@ import
logos_delivery/api/types,
../declare_lib
proc logosdelivery_subscribe(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
contentTopicStr: cstring,
) {.ffi.} =
requireInitializedNode(ctx, "Subscribe"):
return err(errMsg)
requireMessaging(ctx, "Subscribe"):
proc logosdeliverySubscribe*(
lib: LogosDelivery, contentTopicStr: string
): Future[Result[string, string]] {.ffi.} =
requireMessaging(lib, "Subscribe"):
return err(errMsg)
# ContentTopic is just a string type alias
let contentTopic = ContentTopic($contentTopicStr)
let contentTopic = ContentTopic(contentTopicStr)
(await ctx.myLib[].messagingClient.subscribe(contentTopic)).isOkOr:
(await lib.messagingClient.subscribe(contentTopic)).isOkOr:
let errMsg = $error
return err("Subscribe failed: " & errMsg)
return ok("")
proc logosdelivery_unsubscribe(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
contentTopicStr: cstring,
) {.ffi.} =
requireInitializedNode(ctx, "Unsubscribe"):
return err(errMsg)
requireMessaging(ctx, "Unsubscribe"):
proc logosdeliveryUnsubscribe*(
lib: LogosDelivery, contentTopicStr: string
): Future[Result[string, string]] {.ffi.} =
requireMessaging(lib, "Unsubscribe"):
return err(errMsg)
# ContentTopic is just a string type alias
let contentTopic = ContentTopic($contentTopicStr)
let contentTopic = ContentTopic(contentTopicStr)
ctx.myLib[].messagingClient.unsubscribe(contentTopic).isOkOr:
lib.messagingClient.unsubscribe(contentTopic).isOkOr:
let errMsg = $error
return err("Unsubscribe failed: " & errMsg)
return ok("")
proc logosdelivery_send(
ctx: ptr FFIContext[LogosDelivery],
callback: FFICallBack,
userData: pointer,
messageJson: cstring,
) {.ffi.} =
requireInitializedNode(ctx, "Send"):
return err(errMsg)
requireMessaging(ctx, "Send"):
proc logosdeliverySend*(
lib: LogosDelivery, messageJson: string
): Future[Result[string, string]] {.ffi.} =
requireMessaging(lib, "Send"):
return err(errMsg)
## Parse the message JSON and send the message
var jsonNode: JsonNode
try:
jsonNode = parseJson($messageJson)
jsonNode = parseJson(messageJson)
except Exception as e:
return err("Failed to parse message JSON: " & e.msg)
@ -93,7 +75,7 @@ proc logosdelivery_send(
)
# Send the message via the messaging layer's own API.
let requestId = (await ctx.myLib[].messagingClient.send(envelope)).valueOr:
let requestId = (await lib.messagingClient.send(envelope)).valueOr:
let errMsg = $error
return err("Send failed: " & errMsg)

View File

@ -16,206 +16,129 @@ import
proc `%`*(id: RequestId): JsonNode =
%($id)
registerReqFFI(CreateNodeRequest, ctx: ptr FFIContext[LogosDelivery]):
proc(configJson: cstring): Future[Result[string, string]] {.async.} =
let conf = parseLogosDeliveryConf($configJson).valueOr:
error "Failed to parse Logos Delivery configuration JSON",
error = error, configJson = $configJson
return err("failed parseLogosDeliveryConf " & error)
proc logosdeliveryCreateNode*(
configJson: string
): Future[Result[LogosDelivery, string]] {.ffiCtor.} =
let conf = parseLogosDeliveryConf(configJson).valueOr:
error "Failed to parse Logos Delivery configuration JSON",
error = error, configJson = configJson
return err("failed parseLogosDeliveryConf " & error)
ctx.myLib[] = (await LogosDelivery.new(conf)).valueOr:
let errMsg = $error
chronicles.error "CreateNodeRequest failed", err = errMsg
return err(errMsg)
return ok("")
proc logosdelivery_destroy(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
): cint {.dynlib, exportc, cdecl.} =
initializeLibrary()
checkParams(ctx, callback, userData)
ffi.destroyFFIContext(ctx).isOkOr:
let msg = "liblogosdelivery error: " & $error
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)), userData)
return RET_ERR
## always need to invoke the callback although we don't retrieve value to the caller
callback(RET_OK, nil, 0, userData)
return RET_OK
proc logosdelivery_create_node(
configJson: cstring, callback: FFICallback, userData: pointer
): pointer {.dynlib, exportc, cdecl.} =
initializeLibrary()
if callback.isNil():
echo "error: missing callback in logosdelivery_create_node"
return nil
var ctx = ffi.createFFIContext[LogosDelivery]().valueOr:
let msg = "Error in createFFIContext: " & $error
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)), userData)
return nil
ctx.userData = userData
ffi.sendRequestToFFIThread(
ctx, CreateNodeRequest.ffiNewReq(callback, userData, configJson)
).isOkOr:
let msg = "error in sendRequestToFFIThread: " & $error
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)), userData)
# free allocated resources as they won't be available
ffi.destroyFFIContext(ctx).isOkOr:
chronicles.error "Error in destroyFFIContext after sendRequestToFFIThread during creation",
err = $error
return nil
return ctx
proc logosdelivery_start_node(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
requireInitializedNode(ctx, "START_NODE"):
return err(errMsg)
return await LogosDelivery.new(conf)
proc logosdeliveryStartNode*(
lib: LogosDelivery
): Future[Result[string, string]] {.ffi.} =
# setting up outgoing event listeners
let sentListener = MessageSentEvent.listen(
ctx.myLib[].waku.brokerCtx,
lib.waku.brokerCtx,
proc(event: MessageSentEvent) {.async: (raises: []).} =
callEventCallback(ctx, "onMessageSent"):
$newJsonEvent("message_sent", event),
emitMessageSent($event.requestId, event.messageHash),
).valueOr:
chronicles.error "MessageSentEvent.listen failed", err = $error
return err("MessageSentEvent.listen failed: " & $error)
let errorListener = MessageErrorEvent.listen(
ctx.myLib[].waku.brokerCtx,
lib.waku.brokerCtx,
proc(event: MessageErrorEvent) {.async: (raises: []).} =
callEventCallback(ctx, "onMessageError"):
$newJsonEvent("message_error", event),
emitMessageError($event.requestId, event.messageHash, event.error),
).valueOr:
chronicles.error "MessageErrorEvent.listen failed", err = $error
return err("MessageErrorEvent.listen failed: " & $error)
let propagatedListener = MessagePropagatedEvent.listen(
ctx.myLib[].waku.brokerCtx,
lib.waku.brokerCtx,
proc(event: MessagePropagatedEvent) {.async: (raises: []).} =
callEventCallback(ctx, "onMessagePropagated"):
$newJsonEvent("message_propagated", event),
emitMessagePropagated($event.requestId, event.messageHash),
).valueOr:
chronicles.error "MessagePropagatedEvent.listen failed", err = $error
return err("MessagePropagatedEvent.listen failed: " & $error)
let receivedListener = MessageReceivedEvent.listen(
ctx.myLib[].waku.brokerCtx,
lib.waku.brokerCtx,
proc(event: MessageReceivedEvent) {.async: (raises: []).} =
callEventCallback(ctx, "onMessageReceived"):
$newJsonEvent("message_received", event),
emitMessageReceived(event.messageHash, event.message),
).valueOr:
chronicles.error "MessageReceivedEvent.listen failed", err = $error
return err("MessageReceivedEvent.listen failed: " & $error)
let ConnectionStatusChangeListener = EventConnectionStatusChange.listen(
ctx.myLib[].waku.brokerCtx,
lib.waku.brokerCtx,
proc(event: EventConnectionStatusChange) {.async: (raises: []).} =
callEventCallback(ctx, "onConnectionStatusChange"):
$newJsonEvent("connection_status_change", event),
emitConnectionStatusChange($event.connectionStatus),
).valueOr:
chronicles.error "ConnectionStatusChange.listen failed", err = $error
return err("ConnectionStatusChange.listen failed: " & $error)
let shardTopicHealthListener = EventShardTopicHealthChange.listen(
ctx.myLib[].waku.brokerCtx,
lib.waku.brokerCtx,
proc(event: EventShardTopicHealthChange) {.async: (raises: []).} =
callEventCallback(ctx, "onTopicHealthChange"):
$(
%*{
"eventType": "relay_topic_health_change",
"pubsubTopic": $event.topic,
"topicHealth": $event.health,
}
),
emitTopicHealthChange($event.topic, $event.health),
).valueOr:
chronicles.error "EventShardTopicHealthChange.listen failed", err = $error
return err("EventShardTopicHealthChange.listen failed: " & $error)
let peerEventListener = WakuPeerEvent.listen(
ctx.myLib[].waku.brokerCtx,
lib.waku.brokerCtx,
proc(event: WakuPeerEvent) {.async: (raises: []).} =
callEventCallback(ctx, "onConnectionChange"):
$(
%*{
"eventType": "connection_change",
"peerId": $event.peerId,
"peerEvent": $event.kind,
}
),
emitConnectionChange($event.peerId, $event.kind),
).valueOr:
chronicles.error "WakuPeerEvent.listen failed", err = $error
return err("WakuPeerEvent.listen failed: " & $error)
let channelReceivedListener = ChannelMessageReceivedEvent.listen(
ctx.myLib[].waku.brokerCtx,
lib.waku.brokerCtx,
proc(event: ChannelMessageReceivedEvent) {.async: (raises: []).} =
callEventCallback(ctx, "onChannelMessageReceived"):
$(
%*{
"eventType": "channel_message_received",
"channelId": string(event.channelId),
"senderId": $event.senderId,
"payload": string(base64.encode(event.payload)),
}
),
emitChannelMessageReceived(
string(event.channelId), $event.senderId, event.payload
),
).valueOr:
chronicles.error "ChannelMessageReceivedEvent.listen failed", err = $error
return err("ChannelMessageReceivedEvent.listen failed: " & $error)
let channelSentListener = ChannelMessageSentEvent.listen(
ctx.myLib[].waku.brokerCtx,
lib.waku.brokerCtx,
proc(event: ChannelMessageSentEvent) {.async: (raises: []).} =
callEventCallback(ctx, "onChannelMessageSent"):
$newJsonEvent("channel_message_sent", event),
emitChannelMessageSent(string(event.channelId), $event.requestId),
).valueOr:
chronicles.error "ChannelMessageSentEvent.listen failed", err = $error
return err("ChannelMessageSentEvent.listen failed: " & $error)
let channelErrorListener = ChannelMessageErrorEvent.listen(
ctx.myLib[].waku.brokerCtx,
lib.waku.brokerCtx,
proc(event: ChannelMessageErrorEvent) {.async: (raises: []).} =
callEventCallback(ctx, "onChannelMessageError"):
$newJsonEvent("channel_message_error", event),
emitChannelMessageError(
string(event.channelId), $event.requestId, event.error
),
).valueOr:
chronicles.error "ChannelMessageErrorEvent.listen failed", err = $error
return err("ChannelMessageErrorEvent.listen failed: " & $error)
(await ctx.myLib[].start()).isOkOr:
(await lib.start()).isOkOr:
let errMsg = $error
chronicles.error "START_NODE failed", err = errMsg
return err("failed to start: " & errMsg)
return ok("")
proc logosdelivery_stop_node(
ctx: ptr FFIContext[LogosDelivery], callback: FFICallBack, userData: pointer
) {.ffi.} =
requireInitializedNode(ctx, "STOP_NODE"):
return err(errMsg)
proc logosdeliveryStopNode*(
lib: LogosDelivery
): Future[Result[string, string]] {.ffi.} =
await MessageErrorEvent.dropAllListeners(lib.waku.brokerCtx)
await MessageSentEvent.dropAllListeners(lib.waku.brokerCtx)
await MessagePropagatedEvent.dropAllListeners(lib.waku.brokerCtx)
await MessageReceivedEvent.dropAllListeners(lib.waku.brokerCtx)
await EventConnectionStatusChange.dropAllListeners(lib.waku.brokerCtx)
await EventShardTopicHealthChange.dropAllListeners(lib.waku.brokerCtx)
await WakuPeerEvent.dropAllListeners(lib.waku.brokerCtx)
await ChannelMessageReceivedEvent.dropAllListeners(lib.waku.brokerCtx)
await ChannelMessageSentEvent.dropAllListeners(lib.waku.brokerCtx)
await ChannelMessageErrorEvent.dropAllListeners(lib.waku.brokerCtx)
await MessageErrorEvent.dropAllListeners(ctx.myLib[].waku.brokerCtx)
await MessageSentEvent.dropAllListeners(ctx.myLib[].waku.brokerCtx)
await MessagePropagatedEvent.dropAllListeners(ctx.myLib[].waku.brokerCtx)
await MessageReceivedEvent.dropAllListeners(ctx.myLib[].waku.brokerCtx)
await EventConnectionStatusChange.dropAllListeners(ctx.myLib[].waku.brokerCtx)
await EventShardTopicHealthChange.dropAllListeners(ctx.myLib[].waku.brokerCtx)
await WakuPeerEvent.dropAllListeners(ctx.myLib[].waku.brokerCtx)
await ChannelMessageReceivedEvent.dropAllListeners(ctx.myLib[].waku.brokerCtx)
await ChannelMessageSentEvent.dropAllListeners(ctx.myLib[].waku.brokerCtx)
await ChannelMessageErrorEvent.dropAllListeners(ctx.myLib[].waku.brokerCtx)
(await ctx.myLib[].stop()).isOkOr:
(await lib.stop()).isOkOr:
let errMsg = $error
chronicles.error "STOP_NODE failed", err = errMsg
return err("failed to stop: " & errMsg)
return ok("")
proc logosdeliveryDestroy*(lib: LogosDelivery) {.ffiDtor.} =
discard

View File

@ -0,0 +1,13 @@
[package]
name = "logosdelivery"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1", features = ["derive"] }
ciborium = "0.2"
flume = { version = "0.11", default-features = false, features = ["async"] }
tokio = { version = "1", features = ["sync", "time"] }
[dev-dependencies]
tokio = { version = "1", features = ["rt-multi-thread", "macros", "sync", "time"] }

View File

@ -0,0 +1,47 @@
use std::path::PathBuf;
use std::process::Command;
fn main() {
let manifest = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
let nim_src = manifest.join("library/liblogosdelivery.nim");
let nim_src = nim_src.canonicalize().unwrap_or(manifest.join("library/liblogosdelivery.nim"));
// Walk up to find the nim-ffi repo root (directory containing nim_src's library)
// The repo root is where nim c should be run from (contains config.nims).
// We assume nim_src lives somewhere under repo_root.
// Derive repo_root as the ancestor that contains the .nimble file or config.nims.
let mut repo_root = nim_src.clone();
loop {
repo_root = match repo_root.parent() {
Some(p) => p.to_path_buf(),
None => break,
};
if repo_root.join("config.nims").exists() || repo_root.join("ffi.nimble").exists() {
break;
}
}
#[cfg(target_os = "macos")]
let lib_ext = "dylib";
#[cfg(target_os = "linux")]
let lib_ext = "so";
let out_lib = repo_root.join(format!("liblogosdelivery.{lib_ext}"));
let mut cmd = Command::new("nim");
cmd.arg("c")
.arg("--mm:orc")
.arg("-d:chronicles_log_level=WARN")
.arg("--app:lib")
.arg("--noMain")
.arg(format!("--nimMainPrefix:liblogosdelivery"))
.arg(format!("-o:{}", out_lib.display()));
cmd.arg(&nim_src).current_dir(&repo_root);
let status = cmd.status().expect("failed to run nim compiler");
assert!(status.success(), "Nim compilation failed");
println!("cargo:rustc-link-search={}", repo_root.display());
println!("cargo:rustc-link-lib=logosdelivery");
println!("cargo:rerun-if-changed={}", nim_src.display());
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
use std::os::raw::{c_char, c_int, c_void};
pub type FFICallback = unsafe extern "C" fn(
ret: c_int,
msg: *const c_char,
len: usize,
user_data: *mut c_void,
);
#[link(name = "logosdelivery")]
extern "C" {
pub fn logosdelivery_create_node(req_cbor: *const u8, req_cbor_len: usize, callback: FFICallback, user_data: *mut c_void) -> *mut c_void;
pub fn logosdelivery_start_node(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn logosdelivery_stop_node(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn logosdelivery_destroy(ctx: *mut c_void) -> c_int;
pub fn logosdelivery_subscribe(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn logosdelivery_unsubscribe(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn logosdelivery_send(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn logosdelivery_get_available_node_info_ids(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn logosdelivery_get_node_info(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn logosdelivery_get_available_configs(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_get_peerids_from_peerstore(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_connect(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_disconnect_peer_by_id(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_disconnect_all_peers(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_dial_peer(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_dial_peer_by_id(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_get_connected_peers_info(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_get_connected_peers(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_get_peerids_by_protocol(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_discv5_update_bootnodes(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_dns_discovery(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_start_discv5(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_stop_discv5(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_peer_exchange_request(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_version(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_listen_addresses(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_get_my_enr(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_get_my_peerid(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_get_metrics(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_is_online(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_ping_peer(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_relay_get_peers_in_mesh(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_relay_get_num_peers_in_mesh(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_relay_get_connected_peers(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_relay_get_num_connected_peers(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_relay_add_protected_shard(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_relay_subscribe(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_relay_unsubscribe(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_relay_publish(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_default_pubsub_topic(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_content_topic(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_pubsub_topic(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_store_query(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_lightpush_publish(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_filter_subscribe(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_filter_unsubscribe(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn waku_filter_unsubscribe_all(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn logosdelivery_channel_create(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn logosdelivery_channel_send(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn logosdelivery_channel_close(ctx: *mut c_void, callback: FFICallback, user_data: *mut c_void, req_cbor: *const u8, req_cbor_len: usize) -> c_int;
pub fn logosdelivery_add_event_listener(ctx: *mut c_void, event_name: *const c_char, callback: FFICallback, user_data: *mut c_void) -> u64;
pub fn logosdelivery_remove_event_listener(ctx: *mut c_void, listener_id: u64) -> c_int;
}

View File

@ -0,0 +1,5 @@
mod ffi;
mod types;
mod api;
pub use types::*;
pub use api::*;

View File

@ -0,0 +1,384 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuMessagePayload {
pub payload: String,
#[serde(rename = "contentTopic")]
pub content_topic: String,
pub version: u32,
pub timestamp: i64,
pub ephemeral: bool,
pub meta: String,
pub proof: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessageSentPayload {
#[serde(rename = "requestId")]
pub request_id: String,
#[serde(rename = "messageHash")]
pub message_hash: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessageErrorPayload {
#[serde(rename = "requestId")]
pub request_id: String,
#[serde(rename = "messageHash")]
pub message_hash: String,
pub error: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessagePropagatedPayload {
#[serde(rename = "requestId")]
pub request_id: String,
#[serde(rename = "messageHash")]
pub message_hash: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessageReceivedPayload {
#[serde(rename = "messageHash")]
pub message_hash: String,
pub message: WakuMessagePayload,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConnectionStatusChangePayload {
#[serde(rename = "connectionStatus")]
pub connection_status: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TopicHealthChangePayload {
#[serde(rename = "pubsubTopic")]
pub pubsub_topic: String,
#[serde(rename = "topicHealth")]
pub topic_health: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConnectionChangePayload {
#[serde(rename = "peerId")]
pub peer_id: String,
#[serde(rename = "peerEvent")]
pub peer_event: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChannelMessageReceivedPayload {
#[serde(rename = "channelId")]
pub channel_id: String,
#[serde(rename = "senderId")]
pub sender_id: String,
pub payload: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChannelMessageSentPayload {
#[serde(rename = "channelId")]
pub channel_id: String,
#[serde(rename = "requestId")]
pub request_id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChannelMessageErrorPayload {
#[serde(rename = "channelId")]
pub channel_id: String,
#[serde(rename = "requestId")]
pub request_id: String,
pub error: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReceivedMessagePayload {
#[serde(rename = "pubsubTopic")]
pub pubsub_topic: String,
#[serde(rename = "messageHash")]
pub message_hash: String,
#[serde(rename = "wakuMessage")]
pub waku_message: WakuMessagePayload,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogosdeliveryCreateNodeCtorReq {
#[serde(rename = "configJson")]
pub config_json: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogosdeliveryStartNodeReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogosdeliveryStopNodeReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogosdeliverySubscribeReq {
#[serde(rename = "contentTopicStr")]
pub content_topic_str: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogosdeliveryUnsubscribeReq {
#[serde(rename = "contentTopicStr")]
pub content_topic_str: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogosdeliverySendReq {
#[serde(rename = "messageJson")]
pub message_json: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogosdeliveryGetAvailableNodeInfoIdsReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogosdeliveryGetNodeInfoReq {
#[serde(rename = "nodeInfoId")]
pub node_info_id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogosdeliveryGetAvailableConfigsReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuGetPeeridsFromPeerstoreReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuConnectReq {
#[serde(rename = "peerMultiAddr")]
pub peer_multi_addr: String,
#[serde(rename = "timeoutMs")]
pub timeout_ms: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuDisconnectPeerByIdReq {
#[serde(rename = "peerId")]
pub peer_id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuDisconnectAllPeersReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuDialPeerReq {
#[serde(rename = "peerMultiAddr")]
pub peer_multi_addr: String,
pub protocol: String,
#[serde(rename = "timeoutMs")]
pub timeout_ms: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuDialPeerByIdReq {
#[serde(rename = "peerId")]
pub peer_id: String,
pub protocol: String,
#[serde(rename = "timeoutMs")]
pub timeout_ms: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuGetConnectedPeersInfoReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuGetConnectedPeersReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuGetPeeridsByProtocolReq {
pub protocol: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuDiscv5UpdateBootnodesReq {
pub bootnodes: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuDnsDiscoveryReq {
#[serde(rename = "enrTreeUrl")]
pub enr_tree_url: String,
#[serde(rename = "nameDnsServer")]
pub name_dns_server: String,
#[serde(rename = "timeoutMs")]
pub timeout_ms: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuStartDiscv5Req {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuStopDiscv5Req {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuPeerExchangeRequestReq {
#[serde(rename = "numPeers")]
pub num_peers: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuVersionReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuListenAddressesReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuGetMyEnrReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuGetMyPeeridReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuGetMetricsReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuIsOnlineReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuPingPeerReq {
#[serde(rename = "peerAddr")]
pub peer_addr: String,
#[serde(rename = "timeoutMs")]
pub timeout_ms: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuRelayGetPeersInMeshReq {
#[serde(rename = "pubSubTopic")]
pub pub_sub_topic: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuRelayGetNumPeersInMeshReq {
#[serde(rename = "pubSubTopic")]
pub pub_sub_topic: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuRelayGetConnectedPeersReq {
#[serde(rename = "pubSubTopic")]
pub pub_sub_topic: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuRelayGetNumConnectedPeersReq {
#[serde(rename = "pubSubTopic")]
pub pub_sub_topic: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuRelayAddProtectedShardReq {
#[serde(rename = "clusterId")]
pub cluster_id: i32,
#[serde(rename = "shardId")]
pub shard_id: i32,
#[serde(rename = "publicKey")]
pub public_key: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuRelaySubscribeReq {
#[serde(rename = "pubSubTopic")]
pub pub_sub_topic: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuRelayUnsubscribeReq {
#[serde(rename = "pubSubTopic")]
pub pub_sub_topic: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuRelayPublishReq {
#[serde(rename = "pubSubTopic")]
pub pub_sub_topic: String,
#[serde(rename = "jsonWakuMessage")]
pub json_waku_message: String,
#[serde(rename = "timeoutMs")]
pub timeout_ms: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuDefaultPubsubTopicReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuContentTopicReq {
#[serde(rename = "appName")]
pub app_name: String,
#[serde(rename = "appVersion")]
pub app_version: u32,
#[serde(rename = "contentTopicName")]
pub content_topic_name: String,
pub encoding: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuPubsubTopicReq {
#[serde(rename = "topicName")]
pub topic_name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuStoreQueryReq {
#[serde(rename = "jsonQuery")]
pub json_query: String,
#[serde(rename = "peerAddr")]
pub peer_addr: String,
#[serde(rename = "timeoutMs")]
pub timeout_ms: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuLightpushPublishReq {
#[serde(rename = "pubSubTopic")]
pub pub_sub_topic: String,
#[serde(rename = "jsonWakuMessage")]
pub json_waku_message: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuFilterSubscribeReq {
#[serde(rename = "pubSubTopic")]
pub pub_sub_topic: String,
#[serde(rename = "contentTopics")]
pub content_topics: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuFilterUnsubscribeReq {
#[serde(rename = "pubSubTopic")]
pub pub_sub_topic: String,
#[serde(rename = "contentTopics")]
pub content_topics: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WakuFilterUnsubscribeAllReq {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogosdeliveryChannelCreateReq {
#[serde(rename = "channelIdStr")]
pub channel_id_str: String,
#[serde(rename = "contentTopicStr")]
pub content_topic_str: String,
#[serde(rename = "senderIdStr")]
pub sender_id_str: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogosdeliveryChannelSendReq {
#[serde(rename = "channelIdStr")]
pub channel_id_str: String,
#[serde(rename = "messageJson")]
pub message_json: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogosdeliveryChannelCloseReq {
#[serde(rename = "channelIdStr")]
pub channel_id_str: String,
}

View File

@ -61,7 +61,7 @@ requires "nim >= 2.2.4",
# Packages not on nimble (use git URLs)
requires "https://github.com/logos-messaging/nim-ffi#v0.1.3"
requires "https://github.com/logos-messaging/nim-ffi#master"
requires "https://github.com/logos-messaging/nim-sds.git#b12f5ee07c5b764303b51fb948b32a4ade1de3b5"
@ -504,6 +504,14 @@ task liblogosdeliveryStaticLinux, "Generate bindings":
task liblogosdeliveryStaticMac, "Generate bindings":
buildLibStaticMac("liblogosdelivery", "library")
task liblogosdeliveryGenBindingsRust, "Emit the Rust bindings for liblogosdelivery":
# --compileOnly is enough: genBindings() writes the files during macro
# expansion, so nothing needs linking.
exec "nim c --threads:on --mm:refc --skipParentCfg:off -d:discv5_protocol_id=d5waku " &
"-d:ffiGenBindings -d:targetLang=rust -d:ffiOutputDir=library/rust_bindings " &
"-d:ffiSrcPath=library/liblogosdelivery.nim " & getMyCPU() & getNimParams() &
" --compileOnly library/liblogosdelivery.nim"
### Formatting tasks
task nphchanges, "Run nph on .nim/.nims/.nimble files changed on this branch/PR":

View File

@ -643,18 +643,19 @@
}
},
"ffi": {
"version": "0.1.3",
"vcsRevision": "06111de155253b34e47ed2aaed1d61d08d62cc1b",
"version": "#master",
"vcsRevision": "9ed1fedf96e675ff4fd60c3054b6818dbbd1d54b",
"url": "https://github.com/logos-messaging/nim-ffi",
"downloadMethod": "git",
"dependencies": [
"nim",
"chronos",
"chronicles",
"taskpools"
"taskpools",
"cbor_serialization"
],
"checksums": {
"sha1": "6f9d49375ea1dc71add55c72ac80a808f238e5b0"
"sha1": "4819b421c88c25785e6ab3d9f3c2b3f105b60b17"
}
},
"boringssl": {