mirror of
https://github.com/logos-messaging/logos-delivery.git
synced 2026-03-06 17:13:35 +00:00
Adjust liblmapi example
This commit is contained in:
parent
10367d9c81
commit
936e36ada1
27
Makefile
27
Makefile
@ -433,7 +433,7 @@ docker-liteprotocoltester-push:
|
||||
################
|
||||
## C Bindings ##
|
||||
################
|
||||
.PHONY: cbindings cwaku_example libwaku liblmapi
|
||||
.PHONY: cbindings cwaku_example libwaku liblmapi liblmapi_example
|
||||
|
||||
STATIC ?= 0
|
||||
LIBWAKU_BUILD_COMMAND ?= libwakuDynamic
|
||||
@ -463,6 +463,31 @@ libwaku: | build deps librln
|
||||
liblmapi: | build deps librln
|
||||
echo -e $(BUILD_MSG) "build/$@.$(LIB_EXT)" && $(ENV_SCRIPT) nim $(LMAPI_BUILD_COMMAND) $(NIM_PARAMS) waku.nims $@.$(LIB_EXT)
|
||||
|
||||
liblmapi_example: | build liblmapi
|
||||
@echo -e $(BUILD_MSG) "build/$@"
|
||||
ifeq ($(detected_OS),Darwin)
|
||||
gcc -o build/$@ \
|
||||
liblmapi/examples/liblmapi_example.c \
|
||||
-I./liblmapi \
|
||||
-L./build \
|
||||
-llmapi \
|
||||
-Wl,-rpath,./build
|
||||
else ifeq ($(detected_OS),Linux)
|
||||
gcc -o build/$@ \
|
||||
liblmapi/examples/liblmapi_example.c \
|
||||
-I./liblmapi \
|
||||
-L./build \
|
||||
-llmapi \
|
||||
-Wl,-rpath,'$$ORIGIN'
|
||||
else ifeq ($(detected_OS),Windows)
|
||||
gcc -o build/$@.exe \
|
||||
liblmapi/examples/liblmapi_example.c \
|
||||
-I./liblmapi \
|
||||
-L./build \
|
||||
-llmapi \
|
||||
-lws2_32
|
||||
endif
|
||||
|
||||
#####################
|
||||
## Mobile Bindings ##
|
||||
#####################
|
||||
|
||||
165
liblmapi/BUILD.md
Normal file
165
liblmapi/BUILD.md
Normal file
@ -0,0 +1,165 @@
|
||||
# Building liblmapi and Examples
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Nim 2.x compiler
|
||||
- Rust toolchain (for RLN dependencies)
|
||||
- GCC or Clang compiler
|
||||
- Make
|
||||
|
||||
## Building the Library
|
||||
|
||||
### Dynamic Library
|
||||
|
||||
```bash
|
||||
make liblmapi
|
||||
```
|
||||
|
||||
This creates `build/liblmapi.dylib` (macOS) or `build/liblmapi.so` (Linux).
|
||||
|
||||
### Static Library
|
||||
|
||||
```bash
|
||||
nim liblmapiStatic
|
||||
```
|
||||
|
||||
This creates `build/liblmapi.a`.
|
||||
|
||||
## Building Examples
|
||||
|
||||
### liblmapi Example
|
||||
|
||||
Compile the C example that demonstrates all library features:
|
||||
|
||||
```bash
|
||||
# Using Make (recommended)
|
||||
make liblmapi_example
|
||||
|
||||
# Or manually on macOS:
|
||||
gcc -o build/liblmapi_example \
|
||||
liblmapi/examples/liblmapi_example.c \
|
||||
-I./liblmapi \
|
||||
-L./build \
|
||||
-llmapi \
|
||||
-Wl,-rpath,./build
|
||||
|
||||
# Or manually on Linux:
|
||||
gcc -o build/liblmapi_example \
|
||||
liblmapi/examples/liblmapi_example.c \
|
||||
-I./liblmapi \
|
||||
-L./build \
|
||||
-llmapi \
|
||||
-Wl,-rpath='$ORIGIN'
|
||||
```
|
||||
|
||||
## Running Examples
|
||||
|
||||
```bash
|
||||
./build/liblmapi_example
|
||||
```
|
||||
|
||||
The example will:
|
||||
1. Create a Logos Messaging node
|
||||
2. Register event callbacks for message events
|
||||
3. Start the node
|
||||
4. Subscribe to a content topic
|
||||
5. Send a message
|
||||
6. Show message delivery events (sent, propagated, or error)
|
||||
7. Unsubscribe and cleanup
|
||||
|
||||
## Build Artifacts
|
||||
|
||||
After building, you'll have:
|
||||
|
||||
```
|
||||
build/
|
||||
├── liblmapi.dylib # Dynamic library (34MB)
|
||||
├── liblmapi.dylib.dSYM/ # Debug symbols
|
||||
└── liblmapi_example # Compiled example (34KB)
|
||||
```
|
||||
|
||||
## Library Headers
|
||||
|
||||
The main header file is:
|
||||
- `liblmapi/liblmapi.h` - C API declarations
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Library not found at runtime
|
||||
|
||||
If you get "library not found" errors when running the example:
|
||||
|
||||
**macOS:**
|
||||
```bash
|
||||
export DYLD_LIBRARY_PATH=/path/to/build:$DYLD_LIBRARY_PATH
|
||||
./build/liblmapi_example
|
||||
```
|
||||
|
||||
**Linux:**
|
||||
```bash
|
||||
export LD_LIBRARY_PATH=/path/to/build:$LD_LIBRARY_PATH
|
||||
./build/liblmapi_example
|
||||
```
|
||||
|
||||
### Compilation fails
|
||||
|
||||
Make sure you've run:
|
||||
```bash
|
||||
make update
|
||||
```
|
||||
|
||||
This updates all git submodules which are required for building.
|
||||
|
||||
## Static Linking
|
||||
|
||||
To link statically instead of dynamically:
|
||||
|
||||
```bash
|
||||
gcc -o build/simple_example \
|
||||
liblmapi/examples/simple_example.c \
|
||||
-I./liblmapi \
|
||||
build/liblmapi.a \
|
||||
-lm -lpthread
|
||||
```
|
||||
|
||||
Note: Static library is much larger (~129MB) but creates a standalone executable.
|
||||
|
||||
## Cross-Compilation
|
||||
|
||||
For cross-compilation, you need to:
|
||||
1. Build the Nim library for the target platform
|
||||
2. Use the appropriate cross-compiler
|
||||
3. Link against the target platform's liblmapi
|
||||
|
||||
Example for Linux from macOS:
|
||||
```bash
|
||||
# Build library for Linux (requires Docker or cross-compilation setup)
|
||||
# Then compile with cross-compiler
|
||||
```
|
||||
|
||||
## Integration with Your Project
|
||||
|
||||
### CMake
|
||||
|
||||
```cmake
|
||||
find_library(LMAPI_LIBRARY NAMES lmapi PATHS ${PROJECT_SOURCE_DIR}/build)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/liblmapi)
|
||||
target_link_libraries(your_target ${LMAPI_LIBRARY})
|
||||
```
|
||||
|
||||
### Makefile
|
||||
|
||||
```makefile
|
||||
CFLAGS += -I/path/to/liblmapi
|
||||
LDFLAGS += -L/path/to/build -llmapi -Wl,-rpath,/path/to/build
|
||||
|
||||
your_program: your_program.c
|
||||
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
|
||||
```
|
||||
|
||||
## API Documentation
|
||||
|
||||
See:
|
||||
- [liblmapi.h](liblmapi/liblmapi.h) - API function declarations
|
||||
- [MESSAGE_EVENTS.md](liblmapi/MESSAGE_EVENTS.md) - Message event handling guide
|
||||
- [IMPLEMENTATION_SUMMARY.md](liblmapi/IMPLEMENTATION_SUMMARY.md) - Implementation details
|
||||
155
liblmapi/IMPLEMENTATION_SUMMARY.md
Normal file
155
liblmapi/IMPLEMENTATION_SUMMARY.md
Normal file
@ -0,0 +1,155 @@
|
||||
# liblmapi - Summary
|
||||
|
||||
## Overview
|
||||
|
||||
Created a new C FFI library `liblmapi` (Logos Messaging API) that provides a simplified interface to the high-level API functions from `waku/api/api.nim`.
|
||||
|
||||
## Files Created
|
||||
|
||||
### Core Library Files
|
||||
|
||||
1. **liblmapi/liblmapi.h** - C header file
|
||||
- Defines C FFI interface
|
||||
- Includes function declarations for node lifecycle and messaging
|
||||
- Return codes and callback typedef
|
||||
|
||||
2. **liblmapi/liblmapi.nim** - Main library entry point
|
||||
- Imports and includes API modules
|
||||
- Exports `lmapi_destroy` function
|
||||
- Follows same pattern as `library/libwaku.nim`
|
||||
|
||||
3. **liblmapi/declare_lib.nim** - Library declaration
|
||||
- Uses `declareLibrary("lmapi")` macro
|
||||
- Exports `lmapi_set_event_callback` function
|
||||
|
||||
4. **liblmapi/nim.cfg** - Nim configuration
|
||||
- Sets up compiler flags (gc:refc, threads:on)
|
||||
- Configures paths for nim-ffi and project root
|
||||
- Library-specific build settings
|
||||
|
||||
### API Implementation Files
|
||||
|
||||
5. **liblmapi/lmapi/node_api.nim** - Node lifecycle API
|
||||
- `lmapi_create_node` - Creates node from JSON config
|
||||
- `lmapi_start_node` - Starts the node
|
||||
- `lmapi_stop_node` - Stops the node
|
||||
- Uses `registerReqFFI` macro for CreateNodeRequest
|
||||
|
||||
6. **liblmapi/lmapi/messaging_api.nim** - Messaging API
|
||||
- `lmapi_subscribe` - Subscribe to content topic
|
||||
- `lmapi_unsubscribe` - Unsubscribe from content topic
|
||||
- `lmapi_send` - Send message with base64-encoded payload
|
||||
- All use `{.ffi.}` pragma for automatic FFI wrapping
|
||||
|
||||
### Documentation and Examples
|
||||
|
||||
7. **liblmapi/README.md** - Main documentation
|
||||
- API function reference
|
||||
- Configuration examples
|
||||
- Build instructions
|
||||
- Usage patterns
|
||||
- Architecture overview
|
||||
|
||||
8. **liblmapi/examples/liblmapi_example.c** - C example program
|
||||
- Demonstrates all API functions
|
||||
- Shows proper callback handling
|
||||
- Complete lifecycle example
|
||||
|
||||
9. **liblmapi/examples/README.md** - Example documentation
|
||||
- Build instructions per platform
|
||||
- Expected output
|
||||
- Usage notes
|
||||
|
||||
### Build System Integration
|
||||
|
||||
10. **Modified waku.nims**
|
||||
- Added `liblmapiStatic` task
|
||||
- Added `liblmapiDynamic` task
|
||||
- Both use `buildLibrary` helper with chronicle params
|
||||
|
||||
11. **Modified Makefile**
|
||||
- Added `liblmapi` to PHONY targets
|
||||
- Added `LMAPI_BUILD_COMMAND` variable
|
||||
- Added `liblmapi` target that calls nim tasks
|
||||
- Respects STATIC flag for static/dynamic build
|
||||
|
||||
## API Functions
|
||||
|
||||
### Node Lifecycle
|
||||
- `lmapi_create_node` - Create and configure node
|
||||
- `lmapi_start_node` - Start node operations
|
||||
- `lmapi_stop_node` - Stop node operations
|
||||
- `lmapi_destroy` - Clean up and free resources
|
||||
|
||||
### Messaging
|
||||
- `lmapi_subscribe` - Subscribe to content topic
|
||||
- `lmapi_unsubscribe` - Unsubscribe from content topic
|
||||
- `lmapi_send` - Send message envelope
|
||||
|
||||
### Events
|
||||
- `lmapi_set_event_callback` - Register event callback
|
||||
|
||||
## Build Commands
|
||||
|
||||
```bash
|
||||
# Build dynamic library (default)
|
||||
make liblmapi
|
||||
|
||||
# Build static library
|
||||
make liblmapi STATIC=1
|
||||
|
||||
# Or directly via nim
|
||||
nim liblmapiDynamic waku.nims liblmapi.so
|
||||
nim liblmapiStatic waku.nims liblmapi.a
|
||||
```
|
||||
|
||||
## Key Design Decisions
|
||||
|
||||
1. **Follows libwaku pattern**: Same structure and conventions as existing `library/libwaku.nim`
|
||||
|
||||
2. **Uses nim-ffi framework**: Leverages vendor/nim-ffi for:
|
||||
- Thread-safe request processing
|
||||
- Async operation management
|
||||
- Callback marshaling
|
||||
- Memory management between C and Nim
|
||||
|
||||
3. **Wraps new high-level API**: Directly wraps `waku/api/api.nim` functions:
|
||||
- `createNode(config: NodeConfig)`
|
||||
- `subscribe(w: Waku, contentTopic: ContentTopic)`
|
||||
- `send(w: Waku, envelope: MessageEnvelope)`
|
||||
|
||||
4. **JSON-based configuration**: Uses JSON for:
|
||||
- Node configuration (mode, networking, protocols)
|
||||
- Message envelopes (contentTopic, payload, ephemeral)
|
||||
- Simplifies C interface while maintaining flexibility
|
||||
|
||||
5. **Base64 payload encoding**: Message payloads must be base64-encoded in JSON
|
||||
- Avoids binary data issues in JSON
|
||||
- Standard encoding for C interop
|
||||
|
||||
## Integration Points
|
||||
|
||||
The library integrates with:
|
||||
|
||||
- `waku/api/api.nim` - Main API functions
|
||||
- `waku/api/api_conf.nim` - Configuration types (NodeConfig, NetworkingConfig, etc.)
|
||||
- `waku/api/types.nim` - Core types (MessageEnvelope, RequestId, etc.)
|
||||
- `waku/factory/waku.nim` - Waku instance type
|
||||
- `vendor/nim-ffi/` - FFI infrastructure
|
||||
|
||||
## Testing
|
||||
|
||||
To test the library:
|
||||
|
||||
1. Build it: `make liblmapi`
|
||||
2. Build the example: `make liblmapi_example` or `cd liblmapi/examples && gcc -o liblmapi_example liblmapi_example.c -I.. -L../../build -llmapi`
|
||||
3. Run: `./build/liblmapi_example`
|
||||
|
||||
## Next Steps
|
||||
|
||||
Potential enhancements:
|
||||
- Add more examples (async, multi-threaded, etc.)
|
||||
- Add proper test suite
|
||||
- Add CI/CD integration
|
||||
- Add mobile platform support (Android/iOS)
|
||||
- Add language bindings (Python, Go, etc.)
|
||||
148
liblmapi/MESSAGE_EVENTS.md
Normal file
148
liblmapi/MESSAGE_EVENTS.md
Normal file
@ -0,0 +1,148 @@
|
||||
# Message Event Handling in LMAPI
|
||||
|
||||
## Overview
|
||||
|
||||
The LMAPI library emits three types of message delivery events that clients can listen to by registering an event callback using `lmapi_set_event_callback()`.
|
||||
|
||||
## Event Types
|
||||
|
||||
### 1. message_sent
|
||||
Emitted when a message is successfully accepted by the send service and queued for delivery.
|
||||
|
||||
**JSON Structure:**
|
||||
```json
|
||||
{
|
||||
"eventType": "message_sent",
|
||||
"requestId": "unique-request-id",
|
||||
"messageHash": "0x..."
|
||||
}
|
||||
```
|
||||
|
||||
**Fields:**
|
||||
- `eventType`: Always "message_sent"
|
||||
- `requestId`: Request ID returned from the send operation
|
||||
- `messageHash`: Hash of the message that was sent
|
||||
|
||||
### 2. message_propagated
|
||||
Emitted when a message has been successfully propagated to neighboring nodes on the network.
|
||||
|
||||
**JSON Structure:**
|
||||
```json
|
||||
{
|
||||
"eventType": "message_propagated",
|
||||
"requestId": "unique-request-id",
|
||||
"messageHash": "0x..."
|
||||
}
|
||||
```
|
||||
|
||||
**Fields:**
|
||||
- `eventType`: Always "message_propagated"
|
||||
- `requestId`: Request ID from the send operation
|
||||
- `messageHash`: Hash of the message that was propagated
|
||||
|
||||
### 3. message_error
|
||||
Emitted when an error occurs during message sending or propagation.
|
||||
|
||||
**JSON Structure:**
|
||||
```json
|
||||
{
|
||||
"eventType": "message_error",
|
||||
"requestId": "unique-request-id",
|
||||
"messageHash": "0x...",
|
||||
"error": "error description"
|
||||
}
|
||||
```
|
||||
|
||||
**Fields:**
|
||||
- `eventType`: Always "message_error"
|
||||
- `requestId`: Request ID from the send operation
|
||||
- `messageHash`: Hash of the message that failed
|
||||
- `error`: Description of what went wrong
|
||||
|
||||
## Usage
|
||||
|
||||
### 1. Define an Event Callback
|
||||
|
||||
```c
|
||||
void event_callback(int ret, const char *msg, size_t len, void *userData) {
|
||||
if (ret != RET_OK || msg == NULL || len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the JSON message
|
||||
// Extract eventType field
|
||||
// Handle based on event type
|
||||
|
||||
if (eventType == "message_sent") {
|
||||
// Handle message sent
|
||||
} else if (eventType == "message_propagated") {
|
||||
// Handle message propagated
|
||||
} else if (eventType == "message_error") {
|
||||
// Handle message error
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Register the Callback
|
||||
|
||||
```c
|
||||
void *ctx = lmapi_create_node(config, callback, userData);
|
||||
lmapi_set_event_callback(ctx, event_callback, NULL);
|
||||
```
|
||||
|
||||
### 3. Start the Node
|
||||
|
||||
Once the node is started, events will be delivered to your callback:
|
||||
|
||||
```c
|
||||
lmapi_start_node(ctx, callback, userData);
|
||||
```
|
||||
|
||||
## Event Flow
|
||||
|
||||
For a typical successful message send:
|
||||
|
||||
1. **send** → Returns request ID
|
||||
2. **message_sent** → Message accepted and queued
|
||||
3. **message_propagated** → Message delivered to peers
|
||||
|
||||
For a failed message send:
|
||||
|
||||
1. **send** → Returns request ID
|
||||
2. **message_sent** → Message accepted and queued
|
||||
3. **message_error** → Delivery failed with error description
|
||||
|
||||
## Important Notes
|
||||
|
||||
1. **Thread Safety**: The event callback is invoked from the FFI worker thread. Ensure your callback is thread-safe if it accesses shared state.
|
||||
|
||||
2. **Non-Blocking**: Keep the callback fast and non-blocking. Do not perform long-running operations in the callback.
|
||||
|
||||
3. **JSON Parsing**: The example uses a simple string-based parser. For production, use a proper JSON library like:
|
||||
- [cJSON](https://github.com/DaveGamble/cJSON)
|
||||
- [json-c](https://github.com/json-c/json-c)
|
||||
- [Jansson](https://github.com/akheron/jansson)
|
||||
|
||||
4. **Memory Management**: The message buffer is owned by the library. Copy any data you need to retain.
|
||||
|
||||
5. **Event Order**: Events are delivered in the order they occur, but timing depends on network conditions.
|
||||
|
||||
## Example Implementation
|
||||
|
||||
See `examples/liblmapi_example.c` for a complete working example that:
|
||||
- Registers an event callback
|
||||
- Sends a message
|
||||
- Receives and prints all three event types
|
||||
- Properly parses the JSON event structure
|
||||
|
||||
## Debugging Events
|
||||
|
||||
To see all events during development:
|
||||
|
||||
```c
|
||||
void debug_event_callback(int ret, const char *msg, size_t len, void *userData) {
|
||||
printf("Event received: %.*s\n", (int)len, msg);
|
||||
}
|
||||
```
|
||||
|
||||
This will print the raw JSON for all events, helping you understand the event structure.
|
||||
262
liblmapi/README.md
Normal file
262
liblmapi/README.md
Normal file
@ -0,0 +1,262 @@
|
||||
# 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
|
||||
|
||||
#### `lmapi_create_node`
|
||||
Creates a new instance of the node from the given configuration JSON.
|
||||
|
||||
```c
|
||||
void *lmapi_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",
|
||||
"clusterId": 1,
|
||||
"entryNodes": [
|
||||
"enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im"
|
||||
],
|
||||
"networkingConfig": {
|
||||
"listenIpv4": "0.0.0.0",
|
||||
"p2pTcpPort": 60000,
|
||||
"discv5UdpPort": 9000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `lmapi_start_node`
|
||||
Starts the node.
|
||||
|
||||
```c
|
||||
int lmapi_start_node(
|
||||
void *ctx,
|
||||
FFICallBack callback,
|
||||
void *userData
|
||||
);
|
||||
```
|
||||
|
||||
#### `lmapi_stop_node`
|
||||
Stops the node.
|
||||
|
||||
```c
|
||||
int lmapi_stop_node(
|
||||
void *ctx,
|
||||
FFICallBack callback,
|
||||
void *userData
|
||||
);
|
||||
```
|
||||
|
||||
#### `lmapi_destroy`
|
||||
Destroys a node instance and frees resources.
|
||||
|
||||
```c
|
||||
int lmapi_destroy(
|
||||
void *ctx,
|
||||
FFICallBack callback,
|
||||
void *userData
|
||||
);
|
||||
```
|
||||
|
||||
### Messaging
|
||||
|
||||
#### `lmapi_subscribe`
|
||||
Subscribe to a content topic to receive messages.
|
||||
|
||||
```c
|
||||
int lmapi_subscribe(
|
||||
void *ctx,
|
||||
FFICallBack callback,
|
||||
void *userData,
|
||||
const char *contentTopic
|
||||
);
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `ctx`: Context pointer from `lmapi_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")
|
||||
|
||||
#### `lmapi_unsubscribe`
|
||||
Unsubscribe from a content topic.
|
||||
|
||||
```c
|
||||
int lmapi_unsubscribe(
|
||||
void *ctx,
|
||||
FFICallBack callback,
|
||||
void *userData,
|
||||
const char *contentTopic
|
||||
);
|
||||
```
|
||||
|
||||
#### `lmapi_send`
|
||||
Send a message.
|
||||
|
||||
```c
|
||||
int lmapi_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
|
||||
|
||||
#### `lmapi_set_event_callback`
|
||||
Sets a callback that will be invoked whenever an event occurs (e.g., message received).
|
||||
|
||||
```c
|
||||
void lmapi_set_event_callback(
|
||||
void *ctx,
|
||||
FFICallBack callback,
|
||||
void *userData
|
||||
);
|
||||
```
|
||||
|
||||
**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 liblmapiStatic # Build static library
|
||||
# or
|
||||
make liblmapiDynamic # 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 "liblmapi.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 = "{"
|
||||
"\"mode\": \"Core\","
|
||||
"\"clusterId\": 1"
|
||||
"}";
|
||||
|
||||
// Create node
|
||||
void *ctx = lmapi_create_node(config, callback, NULL);
|
||||
if (ctx == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Start node
|
||||
lmapi_start_node(ctx, callback, NULL);
|
||||
|
||||
// Subscribe to a topic
|
||||
lmapi_subscribe(ctx, callback, NULL, "/myapp/1/chat/proto");
|
||||
|
||||
// Send a message
|
||||
const char *msg = "{"
|
||||
"\"contentTopic\": \"/myapp/1/chat/proto\","
|
||||
"\"payload\": \"SGVsbG8gV29ybGQ=\","
|
||||
"\"ephemeral\": false"
|
||||
"}";
|
||||
lmapi_send(ctx, callback, NULL, msg);
|
||||
|
||||
// Clean up
|
||||
lmapi_stop_node(ctx, callback, NULL);
|
||||
lmapi_destroy(ctx, callback, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
The library is structured as follows:
|
||||
|
||||
- `liblmapi.h`: C header file with function declarations
|
||||
- `liblmapi.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/`
|
||||
88
liblmapi/examples/README.md
Normal file
88
liblmapi/examples/README.md
Normal file
@ -0,0 +1,88 @@
|
||||
# Examples for liblmapi
|
||||
|
||||
This directory contains example programs demonstrating the usage of the Logos Messaging API (LMAPI) library.
|
||||
|
||||
## Building the Examples
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Build the liblmapi library first:
|
||||
```bash
|
||||
cd /path/to/logos-messaging-nim
|
||||
make liblmapi
|
||||
```
|
||||
|
||||
2. The library will be available in `build/liblmapi.so` (or `.dylib` on macOS, `.dll` on Windows)
|
||||
|
||||
### Compile the liblmapi Example
|
||||
|
||||
#### On Linux/macOS:
|
||||
```bash
|
||||
# Shared library
|
||||
gcc -o liblmapi_example liblmapi_example.c -I.. -L../../build -llmapi -Wl,-rpath,../../build
|
||||
|
||||
# Static library (if built with STATIC=1)
|
||||
gcc -o liblmapi_example liblmapi_example.c -I.. ../../build/liblmapi.a -lpthread -lm -ldl
|
||||
```
|
||||
|
||||
#### On macOS:
|
||||
```bash
|
||||
gcc -o liblmapi_example liblmapi_example.c -I.. -L../../build -llmapi
|
||||
```
|
||||
|
||||
#### On Windows (MinGW):
|
||||
```bash
|
||||
gcc -o liblmapi_example.exe liblmapi_example.c -I.. -L../../build -llmapi -lws2_32
|
||||
```
|
||||
|
||||
## Running the Examples
|
||||
|
||||
### liblmapi Example
|
||||
|
||||
```bash
|
||||
./liblmapi_example
|
||||
```
|
||||
|
||||
This example demonstrates:
|
||||
1. Creating a node with configuration
|
||||
2. Starting the node
|
||||
3. Subscribing to a content topic
|
||||
4. Sending a message
|
||||
5. Unsubscribing from the topic
|
||||
6. Stopping and destroying the node
|
||||
|
||||
### Expected Output
|
||||
|
||||
```
|
||||
=== Logos Messaging API (LMAPI) Example ===
|
||||
|
||||
1. Creating node...
|
||||
[create_node] Success
|
||||
|
||||
2. Starting node...
|
||||
[start_node] Success
|
||||
|
||||
3. Subscribing to content topic...
|
||||
[subscribe] Success
|
||||
|
||||
4. Sending a message...
|
||||
[send] Success: <request-id>
|
||||
|
||||
5. Unsubscribing from content topic...
|
||||
[unsubscribe] Success
|
||||
|
||||
6. Stopping node...
|
||||
[stop_node] Success
|
||||
|
||||
7. Destroying context...
|
||||
[destroy] Success
|
||||
|
||||
=== Example completed ===
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The examples use simple synchronous callbacks with sleep() for demonstration
|
||||
- In production code, you should use proper async patterns
|
||||
- Error handling in these examples is basic - production code should be more robust
|
||||
- The payload in messages must be base64-encoded
|
||||
@ -9,26 +9,26 @@
|
||||
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;
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ 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) {
|
||||
@ -45,14 +45,14 @@ void event_callback(int ret, const char *msg, size_t len, void *userData) {
|
||||
}
|
||||
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];
|
||||
@ -60,7 +60,7 @@ void event_callback(int ret, const char *msg, size_t len, void *userData) {
|
||||
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];
|
||||
@ -68,20 +68,20 @@ void event_callback(int ret, const char *msg, size_t len, void *userData) {
|
||||
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",
|
||||
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);
|
||||
}
|
||||
|
||||
@ -105,8 +105,10 @@ int main() {
|
||||
// Configuration JSON for creating a node
|
||||
const char *config = "{"
|
||||
"\"mode\": \"Core\","
|
||||
"\"clusterId\": 1,"
|
||||
"\"entryNodes\": [],"
|
||||
"\"clusterId\": 16,"
|
||||
"\"numShards\": 5,"
|
||||
"\"shards\": [64, 128, 1, 32, 256],"
|
||||
"\"entryNodes\": [\"/dns4/boot-01.gc-us-central1-a.status.prod.status.im/tcp/30303/p2p/16Uiu2HAm8mUZ18tBWPXDQsaF7PbCKYA35z7WB2xNZH2EVq1qS8LJ\"],"
|
||||
"\"networkingConfig\": {"
|
||||
"\"listenIpv4\": \"0.0.0.0\","
|
||||
"\"p2pTcpPort\": 60000,"
|
||||
@ -153,7 +155,7 @@ int main() {
|
||||
|
||||
// Wait for message events to arrive
|
||||
printf("Waiting for message delivery events...\n");
|
||||
sleep(3);
|
||||
sleep(60);
|
||||
|
||||
printf("\n6. Unsubscribing from content topic...\n");
|
||||
lmapi_unsubscribe(ctx, simple_callback, (void *)"unsubscribe", contentTopic);
|
||||
Loading…
x
Reference in New Issue
Block a user