mirror of
https://github.com/logos-messaging/logos-delivery.git
synced 2026-07-21 04:00:27 +00:00
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>
301 lines
7.2 KiB
Markdown
301 lines
7.2 KiB
Markdown
# Logos Messaging API (LMAPI) Library
|
|
|
|
A C FFI library providing a simplified interface to Logos Messaging functionality.
|
|
|
|
## Overview
|
|
|
|
This library wraps the high-level API functions from `waku/api/api.nim` and exposes them via a C FFI interface, making them accessible from C, C++, and other languages that support C FFI.
|
|
|
|
## API Functions
|
|
|
|
### Node Lifecycle
|
|
|
|
#### `logosdelivery_create_node`
|
|
Creates a new instance of the node from the given configuration JSON.
|
|
|
|
```c
|
|
void *logosdelivery_create_node(
|
|
const char *configJson,
|
|
FFICallBack callback,
|
|
void *userData
|
|
);
|
|
```
|
|
|
|
**Parameters:**
|
|
- `configJson`: JSON string containing node configuration
|
|
- `callback`: Callback function to receive the result
|
|
- `userData`: User data passed to the callback
|
|
|
|
**Returns:** Pointer to the context needed by other API functions, or NULL on error.
|
|
|
|
**Example configuration JSON:**
|
|
```json
|
|
{
|
|
"mode": "Core",
|
|
"preset": "logos.dev",
|
|
"messagingOverrides": {
|
|
"listen-address": "0.0.0.0",
|
|
"tcp-port": 60000,
|
|
"discv5-udp-port": 9000
|
|
}
|
|
}
|
|
```
|
|
|
|
The configuration object has four optional top-level keys: `mode` (`"Core"` or
|
|
`"Edge"`, defaults to `"Core"`), `preset`, `messagingOverrides` (per-field node
|
|
config overrides), and `channelsOverrides` (reliable-channel overrides).
|
|
Override keys accept the config field name or its CLI switch name (e.g.
|
|
`"clusterId"` or `"cluster-id"`); unknown keys are rejected.
|
|
Use `"preset"` to select a network preset (e.g., `"twn"`, `"logos.dev"`,
|
|
`"status.prod"`) which auto-configures entry nodes, cluster ID, sharding, and
|
|
other network-specific settings.
|
|
|
|
Available presets:
|
|
|
|
| Preset | Cluster ID | RLN | Sharding | Network |
|
|
| --- | --- | --- | --- | --- |
|
|
| `twn` | 1 | on | auto (8 shards) | The Waku Network |
|
|
| `logos.dev` | 2 | off | auto (8 shards) | Logos Dev Network |
|
|
| `logos.test` | 2 | off | auto (8 shards) | Logos Test Network |
|
|
| `status.prod` | 16 | off | auto (1 shard) | Status Production Network |
|
|
|
|
#### `logosdelivery_start_node`
|
|
Starts the node.
|
|
|
|
```c
|
|
int logosdelivery_start_node(
|
|
void *ctx,
|
|
FFICallBack callback,
|
|
void *userData
|
|
);
|
|
```
|
|
|
|
#### `logosdelivery_stop_node`
|
|
Stops the node.
|
|
|
|
```c
|
|
int logosdelivery_stop_node(
|
|
void *ctx,
|
|
FFICallBack callback,
|
|
void *userData
|
|
);
|
|
```
|
|
|
|
#### `logosdelivery_destroy`
|
|
Destroys a node instance and frees resources.
|
|
|
|
```c
|
|
int logosdelivery_destroy(
|
|
void *ctx,
|
|
FFICallBack callback,
|
|
void *userData
|
|
);
|
|
```
|
|
|
|
### Messaging
|
|
|
|
#### `logosdelivery_subscribe`
|
|
Subscribe to a content topic to receive messages.
|
|
|
|
```c
|
|
int logosdelivery_subscribe(
|
|
void *ctx,
|
|
FFICallBack callback,
|
|
void *userData,
|
|
const char *contentTopic
|
|
);
|
|
```
|
|
|
|
**Parameters:**
|
|
- `ctx`: Context pointer from `logosdelivery_create_node`
|
|
- `callback`: Callback function to receive the result
|
|
- `userData`: User data passed to the callback
|
|
- `contentTopic`: Content topic string (e.g., "/myapp/1/chat/proto")
|
|
|
|
#### `logosdelivery_unsubscribe`
|
|
Unsubscribe from a content topic.
|
|
|
|
```c
|
|
int logosdelivery_unsubscribe(
|
|
void *ctx,
|
|
FFICallBack callback,
|
|
void *userData,
|
|
const char *contentTopic
|
|
);
|
|
```
|
|
|
|
#### `logosdelivery_send`
|
|
Send a message.
|
|
|
|
```c
|
|
int logosdelivery_send(
|
|
void *ctx,
|
|
FFICallBack callback,
|
|
void *userData,
|
|
const char *messageJson
|
|
);
|
|
```
|
|
|
|
**Parameters:**
|
|
- `messageJson`: JSON string containing the message
|
|
|
|
**Example message JSON:**
|
|
```json
|
|
{
|
|
"contentTopic": "/myapp/1/chat/proto",
|
|
"payload": "SGVsbG8gV29ybGQ=",
|
|
"ephemeral": false
|
|
}
|
|
```
|
|
|
|
Note: The `payload` field should be base64-encoded.
|
|
|
|
**Returns:** Request ID in the callback message that can be used to track message delivery.
|
|
|
|
### Events
|
|
|
|
#### `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
|
|
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
|
|
|
|
The library follows the same build system as the main Logos Messaging project.
|
|
|
|
### Build the library
|
|
|
|
```bash
|
|
make liblogosdeliveryStatic # Build static library
|
|
# or
|
|
make liblogosdeliveryDynamic # Build dynamic library
|
|
```
|
|
|
|
## Return Codes
|
|
|
|
All functions that return `int` use the following return codes:
|
|
|
|
- `RET_OK` (0): Success
|
|
- `RET_ERR` (1): Error
|
|
- `RET_MISSING_CALLBACK` (2): Missing callback function
|
|
|
|
## Callback Function
|
|
|
|
All API functions use the following callback signature:
|
|
|
|
```c
|
|
typedef void (*FFICallBack)(
|
|
int callerRet,
|
|
const char *msg,
|
|
size_t len,
|
|
void *userData
|
|
);
|
|
```
|
|
|
|
**Parameters:**
|
|
- `callerRet`: Return code (RET_OK, RET_ERR, etc.)
|
|
- `msg`: Response message (may be empty for success)
|
|
- `len`: Length of the message
|
|
- `userData`: User data passed in the original call
|
|
|
|
## Example Usage
|
|
|
|
```c
|
|
#include "liblogosdelivery.h"
|
|
#include <stdio.h>
|
|
|
|
void callback(int ret, const char *msg, size_t len, void *userData) {
|
|
if (ret == RET_OK) {
|
|
printf("Success: %.*s\n", (int)len, msg);
|
|
} else {
|
|
printf("Error: %.*s\n", (int)len, msg);
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
const char *config = "{"
|
|
"\"logLevel\": \"INFO\","
|
|
"\"mode\": \"Core\","
|
|
"\"preset\": \"logos.dev\""
|
|
"}";
|
|
|
|
// Create node
|
|
void *ctx = logosdelivery_create_node(config, callback, NULL);
|
|
if (ctx == NULL) {
|
|
return 1;
|
|
}
|
|
|
|
// Start node
|
|
logosdelivery_start_node(ctx, callback, NULL);
|
|
|
|
// Subscribe to a topic
|
|
logosdelivery_subscribe(ctx, callback, NULL, "/myapp/1/chat/proto");
|
|
|
|
// Send a message
|
|
const char *msg = "{"
|
|
"\"contentTopic\": \"/myapp/1/chat/proto\","
|
|
"\"payload\": \"SGVsbG8gV29ybGQ=\","
|
|
"\"ephemeral\": false"
|
|
"}";
|
|
logosdelivery_send(ctx, callback, NULL, msg);
|
|
|
|
// Clean up
|
|
logosdelivery_stop_node(ctx, callback, NULL);
|
|
logosdelivery_destroy(ctx, callback, NULL);
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
## Architecture
|
|
|
|
The library is structured as follows:
|
|
|
|
- `liblogosdelivery.h`: C header file with function declarations
|
|
- `liblogosdelivery.nim`: Main library entry point
|
|
- `declare_lib.nim`: Library declaration and initialization
|
|
- `lmapi/node_api.nim`: Node lifecycle API implementation
|
|
- `lmapi/messaging_api.nim`: Subscribe/send API implementation
|
|
|
|
The library uses the nim-ffi framework for FFI infrastructure, which handles:
|
|
- Thread-safe request processing
|
|
- Async operation management
|
|
- Memory management between C and Nim
|
|
- Callback marshaling
|
|
|
|
## See Also
|
|
|
|
- Main API documentation: `waku/api/api.nim`
|
|
- Original libwaku library: `library/libwaku.nim`
|
|
- nim-ffi framework: `vendor/nim-ffi/`
|