Added ctx and ctx.myLib check to avoid uninitialzed calls and crash. Adjusted logosdelivery_example with proper error handling and JSON config format

This commit is contained in:
NagyZoltanPeter 2026-02-14 01:03:47 +01:00
parent c269a363ad
commit 2c0cc8be75
No known key found for this signature in database
GPG Key ID: 3E1F97CF4A7B6F42
4 changed files with 55 additions and 82 deletions

View File

@ -3,8 +3,22 @@ import waku/factory/waku
declareLibrary("logosdelivery")
template requireInitializedNode*(
ctx: ptr FFIContext[Waku], 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
proc logosdelivery_set_event_callback(
ctx: ptr FFIContext[Waku], callback: FFICallBack, userData: pointer
) {.dynlib, exportc, cdecl.} =
if isNil(ctx):
echo "error: invalid context in logosdelivery_set_event_callback"
return
ctx[].eventCallback = cast[pointer](callback)
ctx[].eventUserData = userData

View File

@ -4,6 +4,8 @@
#include <unistd.h>
#include <stdlib.h>
static int create_node_ok = -1;
// Helper function to extract a JSON string field value
// Very basic parser - for production use a proper JSON library
const char* extract_json_field(const char *json, const char *field, char *buffer, size_t bufSize) {
@ -88,6 +90,11 @@ void event_callback(int ret, const char *msg, size_t len, void *userData) {
// Simple callback that prints results
void simple_callback(int ret, const char *msg, size_t len, void *userData) {
const char *operation = (const char *)userData;
if (operation != NULL && strcmp(operation, "create_node") == 0) {
create_node_ok = (ret == RET_OK) ? 1 : 0;
}
if (ret == RET_OK) {
if (len > 0) {
printf("[%s] Success: %.*s\n", operation, (int)len, msg);
@ -107,10 +114,13 @@ int main() {
"\"logLevel\": \"DEBUG\","
// "\"mode\": \"Edge\","
"\"mode\": \"Core\","
"\"clusterId\": 42,"
"\"numShards\": 8,"
// "\"shards\": [0,1,2,3,4,5,6,7],"
"\"entryNodes\": [\"/dns4/node-01.do-ams3.misc.logos-chat.status.im/tcp/30303/p2p/16Uiu2HAkxoqUTud5LUPQBRmkeL2xP4iKx2kaABYXomQRgmLUgf78\"],"
"\"protocolsConfig\": {"
"\"entryNodes\": [\"/dns4/node-01.do-ams3.misc.logos-chat.status.im/tcp/30303/p2p/16Uiu2HAkxoqUTud5LUPQBRmkeL2xP4iKx2kaABYXomQRgmLUgf78\"],"
"\"clusterId\": 42,"
"\"autoShardingConfig\": {"
"\"numShardsInCluster\": 8"
"}"
"},"
"\"networkingConfig\": {"
"\"listenIpv4\": \"0.0.0.0\","
"\"p2pTcpPort\": 60000,"
@ -128,6 +138,12 @@ int main() {
// Wait a bit for the callback
sleep(1);
if (create_node_ok != 1) {
printf("Create node failed, stopping example early.\n");
logosdelivery_destroy(ctx, simple_callback, (void *)"destroy");
return 1;
}
printf("\n2. Setting up event callback...\n");
logosdelivery_set_event_callback(ctx, event_callback, NULL);
printf("Event callback registered for message events\n");

View File

@ -13,6 +13,9 @@ proc logosdelivery_subscribe(
userData: pointer,
contentTopicStr: cstring,
) {.ffi.} =
requireInitializedNode(ctx, "Subscribe"):
return err(errMsg)
# ContentTopic is just a string type alias
let contentTopic = ContentTopic($contentTopicStr)
@ -28,6 +31,9 @@ proc logosdelivery_unsubscribe(
userData: pointer,
contentTopicStr: cstring,
) {.ffi.} =
requireInitializedNode(ctx, "Unsubscribe"):
return err(errMsg)
# ContentTopic is just a string type alias
let contentTopic = ContentTopic($contentTopicStr)
@ -43,6 +49,9 @@ proc logosdelivery_send(
userData: pointer,
messageJson: cstring,
) {.ffi.} =
requireInitializedNode(ctx, "Send"):
return err(errMsg)
## Parse the message JSON and send the message
var jsonNode: JsonNode
try:

View File

@ -1,10 +1,9 @@
import std/[json, options, strutils]
import std/json
import chronos, results, ffi
import
waku/factory/waku,
waku/node/waku_node,
waku/api/[api, api_conf, types],
waku/common/logging,
waku/events/message_events,
../declare_lib,
../json_event
@ -16,82 +15,11 @@ proc `%`*(id: RequestId): JsonNode =
registerReqFFI(CreateNodeRequest, ctx: ptr FFIContext[Waku]):
proc(configJson: cstring): Future[Result[string, string]] {.async.} =
## Parse the JSON configuration and create a node
var jsonNode: JsonNode
try:
jsonNode = parseJson($configJson)
except Exception as e:
return err("Failed to parse config JSON: " & e.msg)
# Extract basic configuration
let mode =
if jsonNode.hasKey("mode") and jsonNode["mode"].getStr() == "Edge":
WakuMode.Edge
else:
WakuMode.Core
# Build protocols config
var entryNodes: seq[string] = @[]
if jsonNode.hasKey("entryNodes"):
for node in jsonNode["entryNodes"]:
entryNodes.add(node.getStr())
var staticStoreNodes: seq[string] = @[]
if jsonNode.hasKey("staticStoreNodes"):
for node in jsonNode["staticStoreNodes"]:
staticStoreNodes.add(node.getStr())
let clusterId =
if jsonNode.hasKey("clusterId"):
uint16(jsonNode["clusterId"].getInt())
else:
1u16 # Default cluster ID
# Build networking config
let networkingConfig =
if jsonNode.hasKey("networkingConfig"):
let netJson = jsonNode["networkingConfig"]
NetworkingConfig(
listenIpv4: netJson.getOrDefault("listenIpv4").getStr("0.0.0.0"),
p2pTcpPort: uint16(netJson.getOrDefault("p2pTcpPort").getInt(60000)),
discv5UdpPort: uint16(netJson.getOrDefault("discv5UdpPort").getInt(9000)),
)
else:
DefaultNetworkingConfig
# Build protocols config
let protocolsConfig = ProtocolsConfig.init(
entryNodes = entryNodes,
staticStoreNodes = staticStoreNodes,
clusterId = clusterId,
)
# Parse log configuration
let logLevel =
if jsonNode.hasKey("logLevel"):
try:
parseEnum[logging.LogLevel](jsonNode["logLevel"].getStr().toUpperAscii())
except ValueError:
logging.LogLevel.INFO # Default if parsing fails
else:
logging.LogLevel.INFO
let logFormat =
if jsonNode.hasKey("logFormat"):
try:
parseEnum[logging.LogFormat](jsonNode["logFormat"].getStr().toUpperAscii())
except ValueError:
logging.LogFormat.TEXT # Default if parsing fails
else:
logging.LogFormat.TEXT
# Build node config
let nodeConfig = NodeConfig.init(
mode = mode,
protocolsConfig = protocolsConfig,
networkingConfig = networkingConfig,
logLevel = logLevel,
logFormat = logFormat,
)
let nodeConfig =
try:
decodeNodeConfigFromJson($configJson)
except SerializationError as e:
return err("Failed to parse config JSON: " & e.msg)
# Create the node
ctx.myLib[] = (await api.createNode(nodeConfig)).valueOr:
@ -129,6 +57,9 @@ proc logosdelivery_create_node(
proc logosdelivery_start_node(
ctx: ptr FFIContext[Waku], callback: FFICallBack, userData: pointer
) {.ffi.} =
requireInitializedNode(ctx, "START_NODE"):
return err(errMsg)
# setting up outgoing event listeners
let sentListener = MessageSentEvent.listen(
ctx.myLib[].brokerCtx,
@ -166,6 +97,9 @@ proc logosdelivery_start_node(
proc logosdelivery_stop_node(
ctx: ptr FFIContext[Waku], callback: FFICallBack, userData: pointer
) {.ffi.} =
requireInitializedNode(ctx, "STOP_NODE"):
return err(errMsg)
MessageErrorEvent.dropAllListeners(ctx.myLib[].brokerCtx)
MessageSentEvent.dropAllListeners(ctx.myLib[].brokerCtx)
MessagePropagatedEvent.dropAllListeners(ctx.myLib[].brokerCtx)