mirror of
https://github.com/logos-messaging/logos-delivery.git
synced 2026-03-03 07:33:14 +00:00
Initial for liblmapi library (static & dynamic) based on current state of lmapi. nix build support added.
This commit is contained in:
parent
09034837e6
commit
10367d9c81
13
Makefile
13
Makefile
@ -433,10 +433,11 @@ docker-liteprotocoltester-push:
|
||||
################
|
||||
## C Bindings ##
|
||||
################
|
||||
.PHONY: cbindings cwaku_example libwaku
|
||||
.PHONY: cbindings cwaku_example libwaku liblmapi
|
||||
|
||||
STATIC ?= 0
|
||||
BUILD_COMMAND ?= libwakuDynamic
|
||||
LIBWAKU_BUILD_COMMAND ?= libwakuDynamic
|
||||
LMAPI_BUILD_COMMAND ?= liblmapiDynamic
|
||||
|
||||
ifeq ($(detected_OS),Windows)
|
||||
LIB_EXT_DYNAMIC = dll
|
||||
@ -452,11 +453,15 @@ endif
|
||||
LIB_EXT := $(LIB_EXT_DYNAMIC)
|
||||
ifeq ($(STATIC), 1)
|
||||
LIB_EXT = $(LIB_EXT_STATIC)
|
||||
BUILD_COMMAND = libwakuStatic
|
||||
LIBWAKU_BUILD_COMMAND = libwakuStatic
|
||||
LMAPI_BUILD_COMMAND = liblmapiStatic
|
||||
endif
|
||||
|
||||
libwaku: | build deps librln
|
||||
echo -e $(BUILD_MSG) "build/$@.$(LIB_EXT)" && $(ENV_SCRIPT) nim $(BUILD_COMMAND) $(NIM_PARAMS) waku.nims $@.$(LIB_EXT)
|
||||
echo -e $(BUILD_MSG) "build/$@.$(LIB_EXT)" && $(ENV_SCRIPT) nim $(LIBWAKU_BUILD_COMMAND) $(NIM_PARAMS) waku.nims $@.$(LIB_EXT)
|
||||
|
||||
liblmapi: | build deps librln
|
||||
echo -e $(BUILD_MSG) "build/$@.$(LIB_EXT)" && $(ENV_SCRIPT) nim $(LMAPI_BUILD_COMMAND) $(NIM_PARAMS) waku.nims $@.$(LIB_EXT)
|
||||
|
||||
#####################
|
||||
## Mobile Bindings ##
|
||||
|
||||
@ -71,6 +71,13 @@
|
||||
zerokitRln = zerokit.packages.${system}.rln;
|
||||
};
|
||||
|
||||
liblmapi = pkgs.callPackage ./nix/default.nix {
|
||||
inherit stableSystems;
|
||||
src = self;
|
||||
targets = ["liblmapi"];
|
||||
zerokitRln = zerokit.packages.${system}.rln;
|
||||
};
|
||||
|
||||
default = libwaku;
|
||||
});
|
||||
|
||||
|
||||
10
liblmapi/declare_lib.nim
Normal file
10
liblmapi/declare_lib.nim
Normal file
@ -0,0 +1,10 @@
|
||||
import ffi
|
||||
import waku/factory/waku
|
||||
|
||||
declareLibrary("lmapi")
|
||||
|
||||
proc lmapi_set_event_callback(
|
||||
ctx: ptr FFIContext[Waku], callback: FFICallBack, userData: pointer
|
||||
) {.dynlib, exportc, cdecl.} =
|
||||
ctx[].eventCallback = cast[pointer](callback)
|
||||
ctx[].eventUserData = userData
|
||||
173
liblmapi/examples/simple_example.c
Normal file
173
liblmapi/examples/simple_example.c
Normal file
@ -0,0 +1,173 @@
|
||||
#include "../liblmapi.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// 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) {
|
||||
char searchStr[256];
|
||||
snprintf(searchStr, sizeof(searchStr), "\"%s\":\"", field);
|
||||
|
||||
const char *start = strstr(json, searchStr);
|
||||
if (!start) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
start += strlen(searchStr);
|
||||
const char *end = strchr(start, '"');
|
||||
if (!end) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t len = end - start;
|
||||
if (len >= bufSize) {
|
||||
len = bufSize - 1;
|
||||
}
|
||||
|
||||
memcpy(buffer, start, len);
|
||||
buffer[len] = '\0';
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Event callback that handles message events
|
||||
void event_callback(int ret, const char *msg, size_t len, void *userData) {
|
||||
if (ret != RET_OK || msg == NULL || len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create null-terminated string for easier parsing
|
||||
char *eventJson = malloc(len + 1);
|
||||
if (!eventJson) {
|
||||
return;
|
||||
}
|
||||
memcpy(eventJson, msg, len);
|
||||
eventJson[len] = '\0';
|
||||
|
||||
// Extract eventType
|
||||
char eventType[64];
|
||||
if (!extract_json_field(eventJson, "eventType", eventType, sizeof(eventType))) {
|
||||
free(eventJson);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle different event types
|
||||
if (strcmp(eventType, "message_sent") == 0) {
|
||||
char requestId[128];
|
||||
char messageHash[128];
|
||||
extract_json_field(eventJson, "requestId", requestId, sizeof(requestId));
|
||||
extract_json_field(eventJson, "messageHash", messageHash, sizeof(messageHash));
|
||||
printf("📤 [EVENT] Message sent - RequestID: %s, Hash: %s\n", requestId, messageHash);
|
||||
|
||||
} else if (strcmp(eventType, "message_error") == 0) {
|
||||
char requestId[128];
|
||||
char messageHash[128];
|
||||
char error[256];
|
||||
extract_json_field(eventJson, "requestId", requestId, sizeof(requestId));
|
||||
extract_json_field(eventJson, "messageHash", messageHash, sizeof(messageHash));
|
||||
extract_json_field(eventJson, "error", error, sizeof(error));
|
||||
printf("❌ [EVENT] Message error - RequestID: %s, Hash: %s, Error: %s\n",
|
||||
requestId, messageHash, error);
|
||||
|
||||
} else if (strcmp(eventType, "message_propagated") == 0) {
|
||||
char requestId[128];
|
||||
char messageHash[128];
|
||||
extract_json_field(eventJson, "requestId", requestId, sizeof(requestId));
|
||||
extract_json_field(eventJson, "messageHash", messageHash, sizeof(messageHash));
|
||||
printf("✅ [EVENT] Message propagated - RequestID: %s, Hash: %s\n", requestId, messageHash);
|
||||
|
||||
} else {
|
||||
printf("ℹ️ [EVENT] Unknown event type: %s\n", eventType);
|
||||
}
|
||||
|
||||
free(eventJson);
|
||||
}
|
||||
|
||||
// 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 (ret == RET_OK) {
|
||||
if (len > 0) {
|
||||
printf("[%s] Success: %.*s\n", operation, (int)len, msg);
|
||||
} else {
|
||||
printf("[%s] Success\n", operation);
|
||||
}
|
||||
} else {
|
||||
printf("[%s] Error: %.*s\n", operation, (int)len, msg);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("=== Logos Messaging API (LMAPI) Example ===\n\n");
|
||||
|
||||
// Configuration JSON for creating a node
|
||||
const char *config = "{"
|
||||
"\"mode\": \"Core\","
|
||||
"\"clusterId\": 1,"
|
||||
"\"entryNodes\": [],"
|
||||
"\"networkingConfig\": {"
|
||||
"\"listenIpv4\": \"0.0.0.0\","
|
||||
"\"p2pTcpPort\": 60000,"
|
||||
"\"discv5UdpPort\": 9000"
|
||||
"}"
|
||||
"}";
|
||||
|
||||
printf("1. Creating node...\n");
|
||||
void *ctx = lmapi_create_node(config, simple_callback, (void *)"create_node");
|
||||
if (ctx == NULL) {
|
||||
printf("Failed to create node\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Wait a bit for the callback
|
||||
sleep(1);
|
||||
|
||||
printf("\n2. Setting up event callback...\n");
|
||||
lmapi_set_event_callback(ctx, event_callback, NULL);
|
||||
printf("Event callback registered for message events\n");
|
||||
|
||||
printf("\n3. Starting node...\n");
|
||||
lmapi_start_node(ctx, simple_callback, (void *)"start_node");
|
||||
|
||||
// Wait for node to start
|
||||
sleep(2);
|
||||
|
||||
printf("\n4. Subscribing to content topic...\n");
|
||||
const char *contentTopic = "/example/1/chat/proto";
|
||||
lmapi_subscribe(ctx, simple_callback, (void *)"subscribe", contentTopic);
|
||||
|
||||
// Wait for subscription
|
||||
sleep(1);
|
||||
|
||||
printf("\n5. Sending a message...\n");
|
||||
printf("Watch for message events (sent, propagated, or error):\n");
|
||||
// Create base64-encoded payload: "Hello, Logos Messaging!"
|
||||
const char *message = "{"
|
||||
"\"contentTopic\": \"/example/1/chat/proto\","
|
||||
"\"payload\": \"SGVsbG8sIExvZ29zIE1lc3NhZ2luZyE=\","
|
||||
"\"ephemeral\": false"
|
||||
"}";
|
||||
lmapi_send(ctx, simple_callback, (void *)"send", message);
|
||||
|
||||
// Wait for message events to arrive
|
||||
printf("Waiting for message delivery events...\n");
|
||||
sleep(3);
|
||||
|
||||
printf("\n6. Unsubscribing from content topic...\n");
|
||||
lmapi_unsubscribe(ctx, simple_callback, (void *)"unsubscribe", contentTopic);
|
||||
|
||||
sleep(1);
|
||||
|
||||
printf("\n7. Stopping node...\n");
|
||||
lmapi_stop_node(ctx, simple_callback, (void *)"stop_node");
|
||||
|
||||
sleep(1);
|
||||
|
||||
printf("\n8. Destroying context...\n");
|
||||
lmapi_destroy(ctx, simple_callback, (void *)"destroy");
|
||||
|
||||
printf("\n=== Example completed ===\n");
|
||||
return 0;
|
||||
}
|
||||
27
liblmapi/json_event.nim
Normal file
27
liblmapi/json_event.nim
Normal file
@ -0,0 +1,27 @@
|
||||
import std/[json, macros]
|
||||
|
||||
type JsonEvent*[T] = ref object
|
||||
eventType*: string
|
||||
payload*: T
|
||||
|
||||
macro toFlatJson*(event: JsonEvent): JsonNode =
|
||||
## Serializes JsonEvent[T] to flat JSON with eventType first,
|
||||
## followed by all fields from T's payload
|
||||
result = quote:
|
||||
var jsonObj = newJObject()
|
||||
jsonObj["eventType"] = %`event`.eventType
|
||||
|
||||
# Serialize payload fields into the same object (flattening)
|
||||
let payloadJson = %`event`.payload
|
||||
for key, val in payloadJson.pairs:
|
||||
jsonObj[key] = val
|
||||
|
||||
jsonObj
|
||||
|
||||
proc `$`*[T](event: JsonEvent[T]): string =
|
||||
$toFlatJson(event)
|
||||
|
||||
proc newJsonEvent*[T](eventType: string, payload: T): JsonEvent[T] =
|
||||
## Creates a new JsonEvent with the given eventType and payload.
|
||||
## The payload's fields will be flattened into the JSON output.
|
||||
JsonEvent[T](eventType: eventType, payload: payload)
|
||||
81
liblmapi/liblmapi.h
Normal file
81
liblmapi/liblmapi.h
Normal file
@ -0,0 +1,81 @@
|
||||
|
||||
// Generated manually and inspired by libwaku.h
|
||||
// Header file for Logos Messaging API (LMAPI) library
|
||||
#ifndef __liblmapi__
|
||||
#define __liblmapi__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// The possible returned values for the functions that return int
|
||||
#define RET_OK 0
|
||||
#define RET_ERR 1
|
||||
#define RET_MISSING_CALLBACK 2
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef void (*FFICallBack)(int callerRet, const char *msg, size_t len, void *userData);
|
||||
|
||||
// Creates a new instance of the node from the given configuration JSON.
|
||||
// Returns a pointer to the Context needed by the rest of the API functions.
|
||||
// Configuration should be in JSON format following the NodeConfig structure.
|
||||
void *lmapi_create_node(
|
||||
const char *configJson,
|
||||
FFICallBack callback,
|
||||
void *userData);
|
||||
|
||||
// Starts the node.
|
||||
int lmapi_start_node(void *ctx,
|
||||
FFICallBack callback,
|
||||
void *userData);
|
||||
|
||||
// Stops the node.
|
||||
int lmapi_stop_node(void *ctx,
|
||||
FFICallBack callback,
|
||||
void *userData);
|
||||
|
||||
// Destroys an instance of a node created with lmapi_create_node
|
||||
int lmapi_destroy(void *ctx,
|
||||
FFICallBack callback,
|
||||
void *userData);
|
||||
|
||||
// Subscribe to a content topic.
|
||||
// contentTopic: string representing the content topic (e.g., "/myapp/1/chat/proto")
|
||||
int lmapi_subscribe(void *ctx,
|
||||
FFICallBack callback,
|
||||
void *userData,
|
||||
const char *contentTopic);
|
||||
|
||||
// Unsubscribe from a content topic.
|
||||
int lmapi_unsubscribe(void *ctx,
|
||||
FFICallBack callback,
|
||||
void *userData,
|
||||
const char *contentTopic);
|
||||
|
||||
// Send a message.
|
||||
// messageJson: JSON string with the following structure:
|
||||
// {
|
||||
// "contentTopic": "/myapp/1/chat/proto",
|
||||
// "payload": "base64-encoded-payload",
|
||||
// "ephemeral": false
|
||||
// }
|
||||
// Returns a request ID that can be used to track the message delivery.
|
||||
int lmapi_send(void *ctx,
|
||||
FFICallBack callback,
|
||||
void *userData,
|
||||
const char *messageJson);
|
||||
|
||||
// Sets a callback that will be invoked whenever an event occurs.
|
||||
// It is crucial that the passed callback is fast, non-blocking and potentially thread-safe.
|
||||
void lmapi_set_event_callback(void *ctx,
|
||||
FFICallBack callback,
|
||||
void *userData);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __liblmapi__ */
|
||||
29
liblmapi/liblmapi.nim
Normal file
29
liblmapi/liblmapi.nim
Normal file
@ -0,0 +1,29 @@
|
||||
import std/[atomics, options]
|
||||
import chronicles, chronos, chronos/threadsync, ffi
|
||||
import waku/factory/waku, waku/node/waku_node, ./declare_lib
|
||||
|
||||
################################################################################
|
||||
## Include different APIs, i.e. all procs with {.ffi.} pragma
|
||||
include ./lmapi/node_api, ./lmapi/messaging_api
|
||||
|
||||
################################################################################
|
||||
### Exported procs
|
||||
|
||||
proc lmapi_destroy(
|
||||
ctx: ptr FFIContext[Waku], callback: FFICallBack, userData: pointer
|
||||
): cint {.dynlib, exportc, cdecl.} =
|
||||
initializeLibrary()
|
||||
checkParams(ctx, callback, userData)
|
||||
|
||||
ffi.destroyFFIContext(ctx).isOkOr:
|
||||
let msg = "liblmapi 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
|
||||
|
||||
# ### End of exported procs
|
||||
# ################################################################################
|
||||
86
liblmapi/lmapi/messaging_api.nim
Normal file
86
liblmapi/lmapi/messaging_api.nim
Normal file
@ -0,0 +1,86 @@
|
||||
import std/[json, base64]
|
||||
import chronos, results, ffi
|
||||
import stew/byteutils
|
||||
import
|
||||
waku/factory/waku,
|
||||
waku/waku_core/topics/content_topic,
|
||||
waku/api/[api, types],
|
||||
../declare_lib
|
||||
|
||||
proc lmapi_subscribe(
|
||||
ctx: ptr FFIContext[Waku],
|
||||
callback: FFICallBack,
|
||||
userData: pointer,
|
||||
contentTopicStr: cstring,
|
||||
) {.ffi.} =
|
||||
# ContentTopic is just a string type alias
|
||||
let contentTopic = ContentTopic($contentTopicStr)
|
||||
|
||||
(await api.subscribe(ctx.myLib[], contentTopic)).isOkOr:
|
||||
let errMsg = $error
|
||||
return err("Subscribe failed: " & errMsg)
|
||||
|
||||
return ok("")
|
||||
|
||||
proc lmapi_unsubscribe(
|
||||
ctx: ptr FFIContext[Waku],
|
||||
callback: FFICallBack,
|
||||
userData: pointer,
|
||||
contentTopicStr: cstring,
|
||||
) {.ffi.} =
|
||||
# ContentTopic is just a string type alias
|
||||
let contentTopic = ContentTopic($contentTopicStr)
|
||||
|
||||
api.unsubscribe(ctx.myLib[], contentTopic).isOkOr:
|
||||
let errMsg = $error
|
||||
return err("Unsubscribe failed: " & errMsg)
|
||||
|
||||
return ok("")
|
||||
|
||||
proc lmapi_send(
|
||||
ctx: ptr FFIContext[Waku],
|
||||
callback: FFICallBack,
|
||||
userData: pointer,
|
||||
messageJson: cstring,
|
||||
) {.ffi.} =
|
||||
## Parse the message JSON and send the message
|
||||
var jsonNode: JsonNode
|
||||
try:
|
||||
jsonNode = parseJson($messageJson)
|
||||
except Exception as e:
|
||||
return err("Failed to parse message JSON: " & e.msg)
|
||||
|
||||
# Extract content topic
|
||||
if not jsonNode.hasKey("contentTopic"):
|
||||
return err("Missing contentTopic field")
|
||||
|
||||
# ContentTopic is just a string type alias
|
||||
let contentTopic = ContentTopic(jsonNode["contentTopic"].getStr())
|
||||
|
||||
# Extract payload (expect base64 encoded string)
|
||||
if not jsonNode.hasKey("payload"):
|
||||
return err("Missing payload field")
|
||||
|
||||
var payload: seq[byte]
|
||||
try:
|
||||
let payloadStr = jsonNode["payload"].getStr()
|
||||
# base64.decode returns string, convert to seq[byte]
|
||||
let decodedStr = base64.decode(payloadStr)
|
||||
payload = cast[seq[byte]](decodedStr)
|
||||
except Exception as e:
|
||||
return err("Failed to decode payload: " & e.msg)
|
||||
|
||||
# Extract ephemeral flag
|
||||
let ephemeral = jsonNode.getOrDefault("ephemeral").getBool(false)
|
||||
|
||||
# Create message envelope
|
||||
let envelope = MessageEnvelope.init(
|
||||
contentTopic = contentTopic, payload = payload, ephemeral = ephemeral
|
||||
)
|
||||
|
||||
# Send the message
|
||||
let requestId = (await api.send(ctx.myLib[], envelope)).valueOr:
|
||||
let errMsg = $error
|
||||
return err("Send failed: " & errMsg)
|
||||
|
||||
return ok($requestId)
|
||||
155
liblmapi/lmapi/node_api.nim
Normal file
155
liblmapi/lmapi/node_api.nim
Normal file
@ -0,0 +1,155 @@
|
||||
import std/[json, options]
|
||||
import chronos, results, ffi
|
||||
import
|
||||
waku/factory/waku,
|
||||
waku/node/waku_node,
|
||||
waku/api/[api, api_conf, types],
|
||||
waku/events/message_events,
|
||||
../declare_lib,
|
||||
../json_event
|
||||
|
||||
# Add JSON serialization for RequestId
|
||||
proc `%`*(id: RequestId): JsonNode =
|
||||
%($id)
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
# Build node config
|
||||
let nodeConfig = NodeConfig.init(
|
||||
mode = mode,
|
||||
protocolsConfig = protocolsConfig,
|
||||
networkingConfig = networkingConfig,
|
||||
)
|
||||
|
||||
# Create the node
|
||||
ctx.myLib[] = (await api.createNode(nodeConfig)).valueOr:
|
||||
let errMsg = $error
|
||||
chronicles.error "CreateNodeRequest failed", err = errMsg
|
||||
return err(errMsg)
|
||||
|
||||
return ok("")
|
||||
|
||||
proc lmapi_create_node(
|
||||
configJson: cstring, callback: FFICallback, userData: pointer
|
||||
): pointer {.dynlib, exportc, cdecl.} =
|
||||
initializeLibrary()
|
||||
|
||||
if isNil(callback):
|
||||
echo "error: missing callback in lmapi_create_node"
|
||||
return nil
|
||||
|
||||
var ctx = ffi.createFFIContext[Waku]().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)
|
||||
return nil
|
||||
|
||||
return ctx
|
||||
|
||||
proc lmapi_start_node(
|
||||
ctx: ptr FFIContext[Waku], callback: FFICallBack, userData: pointer
|
||||
) {.ffi.} =
|
||||
# setting up outgoing event listeners
|
||||
let sentListener = MessageSentEvent.listen(
|
||||
ctx.myLib[].brokerCtx,
|
||||
proc(event: MessageSentEvent) {.async: (raises: []).} =
|
||||
callEventCallback(ctx, "onMessageSent"):
|
||||
$newJsonEvent("message_sent", event),
|
||||
).valueOr:
|
||||
chronicles.error "MessageSentEvent.listen failed", err = $error
|
||||
return err("MessageSentEvent.listen failed: " & $error)
|
||||
|
||||
let errorListener = MessageErrorEvent.listen(
|
||||
ctx.myLib[].brokerCtx,
|
||||
proc(event: MessageErrorEvent) {.async: (raises: []).} =
|
||||
callEventCallback(ctx, "onMessageError"):
|
||||
$newJsonEvent("message_error", event),
|
||||
).valueOr:
|
||||
chronicles.error "MessageErrorEvent.listen failed", err = $error
|
||||
return err("MessageErrorEvent.listen failed: " & $error)
|
||||
|
||||
let propagatedListener = MessagePropagatedEvent.listen(
|
||||
ctx.myLib[].brokerCtx,
|
||||
proc(event: MessagePropagatedEvent) {.async: (raises: []).} =
|
||||
callEventCallback(ctx, "onMessagePropagated"):
|
||||
$newJsonEvent("message_propagated", event),
|
||||
).valueOr:
|
||||
chronicles.error "MessagePropagatedEvent.listen failed", err = $error
|
||||
return err("MessagePropagatedEvent.listen failed: " & $error)
|
||||
|
||||
(await startWaku(addr ctx.myLib[])).isOkOr:
|
||||
let errMsg = $error
|
||||
chronicles.error "START_NODE failed", err = errMsg
|
||||
return err("failed to start: " & errMsg)
|
||||
return ok("")
|
||||
|
||||
proc lmapi_stop_node(
|
||||
ctx: ptr FFIContext[Waku], callback: FFICallBack, userData: pointer
|
||||
) {.ffi.} =
|
||||
MessageErrorEvent.dropAllListeners(ctx.myLib[].brokerCtx)
|
||||
MessageSentEvent.dropAllListeners(ctx.myLib[].brokerCtx)
|
||||
MessagePropagatedEvent.dropAllListeners(ctx.myLib[].brokerCtx)
|
||||
|
||||
(await ctx.myLib[].stop()).isOkOr:
|
||||
let errMsg = $error
|
||||
chronicles.error "STOP_NODE failed", err = errMsg
|
||||
return err("failed to stop: " & errMsg)
|
||||
return ok("")
|
||||
27
liblmapi/nim.cfg
Normal file
27
liblmapi/nim.cfg
Normal file
@ -0,0 +1,27 @@
|
||||
# Nim configuration for liblmapi
|
||||
|
||||
# Ensure correct compiler configuration
|
||||
--gc:
|
||||
refc
|
||||
--threads:
|
||||
on
|
||||
|
||||
# Include paths
|
||||
--path:
|
||||
"../vendor/nim-ffi"
|
||||
--path:
|
||||
"../"
|
||||
|
||||
# Optimization and debugging
|
||||
--opt:
|
||||
speed
|
||||
--debugger:
|
||||
native
|
||||
|
||||
# Export symbols for dynamic library
|
||||
--app:
|
||||
lib
|
||||
--noMain
|
||||
|
||||
# Enable FFI macro features when needed for debugging
|
||||
# --define:ffiDumpMacros
|
||||
@ -94,8 +94,9 @@ in stdenv.mkDerivation {
|
||||
# Copy library files
|
||||
cp build/* $out/bin/ 2>/dev/null || true
|
||||
|
||||
# Copy the header file
|
||||
cp library/libwaku.h $out/include/
|
||||
# Copy header files
|
||||
cp library/libwaku.h $out/include/ 2>/dev/null || true
|
||||
cp liblmapi/liblmapi.h $out/include/ 2>/dev/null || true
|
||||
'';
|
||||
|
||||
meta = with pkgs.lib; {
|
||||
|
||||
18
waku.nimble
18
waku.nimble
@ -64,7 +64,7 @@ proc buildBinary(name: string, srcDir = "./", params = "", lang = "c") =
|
||||
exec "nim " & lang & " --out:build/" & name & " --mm:refc " & extra_params & " " &
|
||||
srcDir & name & ".nim"
|
||||
|
||||
proc buildLibrary(lib_name: string, srcDir = "./", params = "", `type` = "static") =
|
||||
proc buildLibrary(lib_name: string, srcDir = "./", params = "", `type` = "static", srcFile = "libwaku.nim", mainPrefix = "libwaku") =
|
||||
if not dirExists "build":
|
||||
mkDir "build"
|
||||
# allow something like "nim nimbus --verbosity:0 --hints:off nimbus.nims"
|
||||
@ -73,12 +73,12 @@ proc buildLibrary(lib_name: string, srcDir = "./", params = "", `type` = "static
|
||||
extra_params &= " " & paramStr(i)
|
||||
if `type` == "static":
|
||||
exec "nim c" & " --out:build/" & lib_name &
|
||||
" --threads:on --app:staticlib --opt:size --noMain --mm:refc --header -d:metrics --nimMainPrefix:libwaku --skipParentCfg:on -d:discv5_protocol_id=d5waku " &
|
||||
extra_params & " " & srcDir & "libwaku.nim"
|
||||
" --threads:on --app:staticlib --opt:size --noMain --mm:refc --header -d:metrics --nimMainPrefix:" & mainPrefix & " --skipParentCfg:on -d:discv5_protocol_id=d5waku " &
|
||||
extra_params & " " & srcDir & srcFile
|
||||
else:
|
||||
exec "nim c" & " --out:build/" & lib_name &
|
||||
" --threads:on --app:lib --opt:size --noMain --mm:refc --header -d:metrics --nimMainPrefix:libwaku --skipParentCfg:off -d:discv5_protocol_id=d5waku " &
|
||||
extra_params & " " & srcDir & "libwaku.nim"
|
||||
" --threads:on --app:lib --opt:size --noMain --mm:refc --header -d:metrics --nimMainPrefix:" & mainPrefix & " --skipParentCfg:off -d:discv5_protocol_id=d5waku " &
|
||||
extra_params & " " & srcDir & srcFile
|
||||
|
||||
proc buildMobileAndroid(srcDir = ".", params = "") =
|
||||
let cpu = getEnv("CPU")
|
||||
@ -400,3 +400,11 @@ task libWakuIOS, "Build the mobile bindings for iOS":
|
||||
let srcDir = "./library"
|
||||
let extraParams = "-d:chronicles_log_level=ERROR"
|
||||
buildMobileIOS srcDir, extraParams
|
||||
|
||||
task liblmapiStatic, "Build the liblmapi (Logos Messaging API) static library":
|
||||
let lib_name = paramStr(paramCount())
|
||||
buildLibrary lib_name, "liblmapi/", chroniclesParams, "static", "liblmapi.nim", "liblmapi"
|
||||
|
||||
task liblmapiDynamic, "Build the liblmapi (Logos Messaging API) dynamic library":
|
||||
let lib_name = paramStr(paramCount())
|
||||
buildLibrary lib_name, "liblmapi/", chroniclesParams, "dynamic", "liblmapi.nim", "liblmapi"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user