diff --git a/liblogosdelivery/declare_lib.nim b/liblogosdelivery/declare_lib.nim index 8486275a9..98209c649 100644 --- a/liblogosdelivery/declare_lib.nim +++ b/liblogosdelivery/declare_lib.nim @@ -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 diff --git a/liblogosdelivery/examples/logosdelivery_example.c b/liblogosdelivery/examples/logosdelivery_example.c index 930cbf5af..5437be427 100644 --- a/liblogosdelivery/examples/logosdelivery_example.c +++ b/liblogosdelivery/examples/logosdelivery_example.c @@ -4,6 +4,8 @@ #include #include +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"); diff --git a/liblogosdelivery/logos_delivery_api/messaging_api.nim b/liblogosdelivery/logos_delivery_api/messaging_api.nim index 19cbe6f67..536c53fef 100644 --- a/liblogosdelivery/logos_delivery_api/messaging_api.nim +++ b/liblogosdelivery/logos_delivery_api/messaging_api.nim @@ -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: diff --git a/liblogosdelivery/logos_delivery_api/node_api.nim b/liblogosdelivery/logos_delivery_api/node_api.nim index 9ff589ad4..6a0041857 100644 --- a/liblogosdelivery/logos_delivery_api/node_api.nim +++ b/liblogosdelivery/logos_delivery_api/node_api.nim @@ -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)