mirror of
https://github.com/logos-co/logos-messaging-module.git
synced 2026-08-27 18:51:09 +00:00
Merge back from master
This commit is contained in:
+5
-38
@@ -1,39 +1,6 @@
|
||||
# Build directories
|
||||
build/
|
||||
result
|
||||
result-*
|
||||
.direnv/
|
||||
|
||||
# CMake
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
cmake_install.cmake
|
||||
Makefile
|
||||
*.cmake
|
||||
|
||||
# Compiled objects
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Qt
|
||||
*.moc
|
||||
moc_*.cpp
|
||||
qrc_*.cpp
|
||||
*.qm
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
._*
|
||||
|
||||
# Nix
|
||||
.pre-commit-config.yaml
|
||||
build
|
||||
.deps/
|
||||
vendor/*
|
||||
lib/*
|
||||
result
|
||||
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
[submodule "vendor/logos-delivery"]
|
||||
path = vendor/logos-delivery
|
||||
url = https://github.com/logos-messaging/logos-delivery.git
|
||||
branch = master
|
||||
fetchRecurseSubmodules = true
|
||||
[submodule "vendor/logos-liblogos"]
|
||||
path = vendor/logos-liblogos
|
||||
url = https://github.com/logos-co/logos-liblogos
|
||||
[submodule "vendor/logos-cpp-sdk"]
|
||||
path = vendor/logos-cpp-sdk
|
||||
url = https://github.com/logos-co/logos-cpp-sdk
|
||||
+18
-291
@@ -1,304 +1,31 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(DeliveryModulePlugin LANGUAGES CXX)
|
||||
project(LogosDeliveryModulePlugin LANGUAGES CXX)
|
||||
|
||||
# Require C++20
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
option(LOGOS_MESSAGING_MODULE_USE_VENDOR "Force use of vendored Logos dependencies" OFF)
|
||||
|
||||
# Allow override from environment or command line
|
||||
if(NOT DEFINED LOGOS_LIBLOGOS_ROOT)
|
||||
set(_parent_liblogos "${CMAKE_CURRENT_SOURCE_DIR}/../logos-liblogos")
|
||||
set(_use_vendor ${LOGOS_MESSAGING_MODULE_USE_VENDOR})
|
||||
if(NOT _use_vendor)
|
||||
if(NOT EXISTS "${_parent_liblogos}/interface.h")
|
||||
set(_use_vendor ON)
|
||||
endif()
|
||||
endif()
|
||||
if(_use_vendor)
|
||||
set(LOGOS_LIBLOGOS_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/vendor/logos-liblogos")
|
||||
else()
|
||||
set(LOGOS_LIBLOGOS_ROOT "${_parent_liblogos}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED LOGOS_CPP_SDK_ROOT)
|
||||
set(_parent_cpp_sdk "${CMAKE_CURRENT_SOURCE_DIR}/../logos-cpp-sdk")
|
||||
set(_use_vendor ${LOGOS_MESSAGING_MODULE_USE_VENDOR})
|
||||
if(NOT _use_vendor)
|
||||
if(NOT EXISTS "${_parent_cpp_sdk}/cpp/logos_api.h")
|
||||
set(_use_vendor ON)
|
||||
endif()
|
||||
endif()
|
||||
if(_use_vendor)
|
||||
set(LOGOS_CPP_SDK_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/vendor/logos-cpp-sdk")
|
||||
else()
|
||||
set(LOGOS_CPP_SDK_ROOT "${_parent_cpp_sdk}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED LOGOS_DELIVERY_ROOT)
|
||||
set(LOGOS_DELIVERY_ROOT "$ENV{LOGOS_DELIVERY_ROOT}")
|
||||
endif()
|
||||
|
||||
# Check if dependencies are available (support both source and installed layouts)
|
||||
set(_liblogos_found FALSE)
|
||||
if(EXISTS "${LOGOS_LIBLOGOS_ROOT}/interface.h")
|
||||
set(_liblogos_found TRUE)
|
||||
set(_liblogos_is_source TRUE)
|
||||
elseif(EXISTS "${LOGOS_LIBLOGOS_ROOT}/include/interface.h")
|
||||
set(_liblogos_found TRUE)
|
||||
set(_liblogos_is_source FALSE)
|
||||
endif()
|
||||
|
||||
set(_cpp_sdk_found FALSE)
|
||||
if(EXISTS "${LOGOS_CPP_SDK_ROOT}/cpp/logos_api.h")
|
||||
set(_cpp_sdk_found TRUE)
|
||||
set(_cpp_sdk_is_source TRUE)
|
||||
elseif(EXISTS "${LOGOS_CPP_SDK_ROOT}/include/cpp/logos_api.h")
|
||||
set(_cpp_sdk_found TRUE)
|
||||
set(_cpp_sdk_is_source FALSE)
|
||||
endif()
|
||||
|
||||
if(NOT _liblogos_found)
|
||||
message(FATAL_ERROR "logos-liblogos not found at ${LOGOS_LIBLOGOS_ROOT}. "
|
||||
"Set LOGOS_LIBLOGOS_ROOT or run git submodule update --init --recursive.")
|
||||
endif()
|
||||
|
||||
if(NOT _cpp_sdk_found)
|
||||
message(FATAL_ERROR "logos-cpp-sdk not found at ${LOGOS_CPP_SDK_ROOT}. "
|
||||
"Set LOGOS_CPP_SDK_ROOT or run git submodule update --init --recursive.")
|
||||
endif()
|
||||
|
||||
# Root that contains the vendored dependencies (logos-core checkout or script vendor directory)
|
||||
get_filename_component(LOGOS_DEPS_ROOT "${LOGOS_CPP_SDK_ROOT}" DIRECTORY)
|
||||
|
||||
# Find Qt RemoteObjects (needed for LogosAPI)
|
||||
if(NOT DEFINED QT_VERSION_MAJOR)
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core RemoteObjects)
|
||||
if(Qt6_FOUND)
|
||||
set(QT_VERSION_MAJOR 6)
|
||||
else()
|
||||
set(QT_VERSION_MAJOR 5)
|
||||
endif()
|
||||
endif()
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core RemoteObjects)
|
||||
|
||||
# Run Logos C++ generator on metadata before compilation
|
||||
set(METADATA_JSON "${CMAKE_CURRENT_SOURCE_DIR}/metadata.json")
|
||||
set(PLUGINS_OUTPUT_DIR "${CMAKE_BINARY_DIR}/modules")
|
||||
|
||||
# Try to find the generator binary
|
||||
if(_cpp_sdk_is_source)
|
||||
# Source layout: build the generator
|
||||
set(CPP_GENERATOR_BUILD_DIR "${LOGOS_DEPS_ROOT}/build/cpp-generator")
|
||||
set(CPP_GENERATOR "${CPP_GENERATOR_BUILD_DIR}/bin/logos-cpp-generator")
|
||||
|
||||
if(NOT TARGET cpp_generator_build)
|
||||
add_custom_target(cpp_generator_build
|
||||
COMMAND bash "${LOGOS_CPP_SDK_ROOT}/cpp-generator/compile.sh"
|
||||
WORKING_DIRECTORY "${LOGOS_DEPS_ROOT}"
|
||||
COMMENT "Building logos-cpp-generator via ${LOGOS_CPP_SDK_ROOT}/cpp-generator/compile.sh"
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
|
||||
add_custom_target(run_cpp_generator_messaging
|
||||
COMMAND "${CPP_GENERATOR}" --metadata "${METADATA_JSON}" --module-dir "${PLUGINS_OUTPUT_DIR}"
|
||||
WORKING_DIRECTORY "${LOGOS_DEPS_ROOT}"
|
||||
COMMENT "Running logos-cpp-generator on ${METADATA_JSON} with module-dir ${PLUGINS_OUTPUT_DIR}"
|
||||
VERBATIM
|
||||
)
|
||||
add_dependencies(run_cpp_generator_messaging cpp_generator_build)
|
||||
# Include the Logos Module CMake helper
|
||||
if(DEFINED ENV{LOGOS_MODULE_BUILDER_ROOT})
|
||||
include($ENV{LOGOS_MODULE_BUILDER_ROOT}/cmake/LogosModule.cmake)
|
||||
else()
|
||||
# Installed layout: use the generator from the install path
|
||||
find_program(CPP_GENERATOR logos-cpp-generator PATHS ${LOGOS_CPP_SDK_ROOT}/bin NO_DEFAULT_PATH REQUIRED)
|
||||
|
||||
add_custom_target(run_cpp_generator_messaging
|
||||
COMMAND "${CPP_GENERATOR}" --metadata "${METADATA_JSON}" --module-dir "${PLUGINS_OUTPUT_DIR}"
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||
COMMENT "Running logos-cpp-generator on ${METADATA_JSON} with module-dir ${PLUGINS_OUTPUT_DIR}"
|
||||
VERBATIM
|
||||
)
|
||||
message(FATAL_ERROR "LogosModule.cmake not found. Set LOGOS_MODULE_BUILDER_ROOT.")
|
||||
endif()
|
||||
|
||||
# Find liblogosdelivery library
|
||||
set(LIBLOGOSDELIVERY_DIR "${LOGOS_DELIVERY_ROOT}/bin")
|
||||
# Prioritize platform-specific library names
|
||||
if(APPLE)
|
||||
set(LIBLOGOSDELIVERY_NAMES liblogosdelivery.dylib liblogosdelivery.so)
|
||||
elseif(WIN32)
|
||||
set(LIBLOGOSDELIVERY_NAMES liblogosdelivery.dll lmapi.dll)
|
||||
else()
|
||||
set(LIBLOGOSDELIVERY_NAMES liblogosdelivery.so)
|
||||
endif()
|
||||
find_library(LIBLOGOSDELIVERY_PATH NAMES ${LIBLOGOSDELIVERY_NAMES} PATHS ${LIBLOGOSDELIVERY_DIR} NO_DEFAULT_PATH)
|
||||
|
||||
# Plugin sources
|
||||
set(PLUGIN_SOURCES
|
||||
src/delivery_module_plugin.cpp
|
||||
src/delivery_module_plugin.h
|
||||
src/delivery_module_interface.h
|
||||
)
|
||||
|
||||
# Add liblogos interface header
|
||||
if(_liblogos_is_source)
|
||||
list(APPEND PLUGIN_SOURCES ${LOGOS_LIBLOGOS_ROOT}/interface.h)
|
||||
else()
|
||||
list(APPEND PLUGIN_SOURCES ${LOGOS_LIBLOGOS_ROOT}/include/interface.h)
|
||||
endif()
|
||||
|
||||
# Add SDK sources (only if source layout, installed layout uses the library)
|
||||
if(_cpp_sdk_is_source)
|
||||
list(APPEND PLUGIN_SOURCES
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api.cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api.h
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_client.cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_client.h
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_consumer.cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_consumer.h
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_provider.cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_provider.h
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/token_manager.cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/token_manager.h
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/module_proxy.cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/module_proxy.h
|
||||
)
|
||||
endif()
|
||||
|
||||
# Create the plugin library
|
||||
add_library(delivery_module_plugin SHARED ${PLUGIN_SOURCES})
|
||||
|
||||
# Set output name without lib prefix
|
||||
set_target_properties(delivery_module_plugin PROPERTIES
|
||||
PREFIX "")
|
||||
|
||||
# Ensure generator runs before building the plugin
|
||||
add_dependencies(delivery_module_plugin run_cpp_generator_messaging)
|
||||
|
||||
# Link Qt libraries
|
||||
target_link_libraries(delivery_module_plugin PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Core
|
||||
Qt${QT_VERSION_MAJOR}::RemoteObjects
|
||||
)
|
||||
|
||||
# Link SDK library if using installed layout
|
||||
if(NOT _cpp_sdk_is_source)
|
||||
find_library(LOGOS_SDK_LIB logos_sdk PATHS ${LOGOS_CPP_SDK_ROOT}/lib NO_DEFAULT_PATH REQUIRED)
|
||||
target_link_libraries(delivery_module_plugin PRIVATE ${LOGOS_SDK_LIB})
|
||||
endif()
|
||||
|
||||
# Link to liblogosdelivery on all platforms
|
||||
if(LIBLOGOSDELIVERY_PATH)
|
||||
target_link_libraries(delivery_module_plugin PRIVATE ${LIBLOGOSDELIVERY_PATH})
|
||||
else()
|
||||
message(WARNING "liblogosdelivery not found in ${LIBLOGOSDELIVERY_DIR}. Build or provide it before linking.")
|
||||
endif()
|
||||
|
||||
# Include directories
|
||||
target_include_directories(delivery_module_plugin PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${LIBLOGOSDELIVERY_DIR}
|
||||
)
|
||||
|
||||
# Look for liblogosdelivery.h in logos-delivery
|
||||
if(EXISTS "${LOGOS_DELIVERY_ROOT}/include/liblogosdelivery.h")
|
||||
target_include_directories(delivery_module_plugin PRIVATE ${LOGOS_DELIVERY_ROOT}/include)
|
||||
elseif(EXISTS "${LOGOS_DELIVERY_ROOT}/liblogosdelivery/liblogosdelivery.h")
|
||||
target_include_directories(delivery_module_plugin PRIVATE ${LOGOS_DELIVERY_ROOT}/liblogosdelivery)
|
||||
endif()
|
||||
|
||||
# Add include directories based on layout type
|
||||
if(_liblogos_is_source)
|
||||
target_include_directories(delivery_module_plugin PRIVATE ${LOGOS_LIBLOGOS_ROOT})
|
||||
else()
|
||||
target_include_directories(delivery_module_plugin PRIVATE ${LOGOS_LIBLOGOS_ROOT}/include)
|
||||
endif()
|
||||
|
||||
if(_cpp_sdk_is_source)
|
||||
target_include_directories(delivery_module_plugin PRIVATE
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/generated
|
||||
)
|
||||
else()
|
||||
target_include_directories(delivery_module_plugin PRIVATE
|
||||
${LOGOS_CPP_SDK_ROOT}/include
|
||||
${LOGOS_CPP_SDK_ROOT}/include/cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/include/core
|
||||
)
|
||||
endif()
|
||||
|
||||
set_target_properties(delivery_module_plugin PROPERTIES
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/modules"
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/modules"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/modules" # For Windows .dll
|
||||
BUILD_WITH_INSTALL_RPATH TRUE
|
||||
SKIP_BUILD_RPATH FALSE)
|
||||
|
||||
if(APPLE)
|
||||
# Allow unresolved symbols at link time; liblogosdelivery will be provided at runtime
|
||||
target_link_options(delivery_module_plugin PRIVATE -undefined dynamic_lookup)
|
||||
set_target_properties(delivery_module_plugin PROPERTIES
|
||||
INSTALL_RPATH "@loader_path"
|
||||
INSTALL_NAME_DIR "@rpath"
|
||||
BUILD_WITH_INSTALL_NAME_DIR TRUE)
|
||||
|
||||
if(LIBLOGOSDELIVERY_PATH)
|
||||
get_filename_component(LIBLOGOSDELIVERY_FILENAME "${LIBLOGOSDELIVERY_PATH}" NAME)
|
||||
add_custom_command(TARGET delivery_module_plugin PRE_LINK
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${LIBLOGOSDELIVERY_PATH}
|
||||
${CMAKE_BINARY_DIR}/modules/${LIBLOGOSDELIVERY_FILENAME}
|
||||
COMMENT "Copying ${LIBLOGOSDELIVERY_FILENAME} to modules directory"
|
||||
)
|
||||
|
||||
add_custom_command(TARGET delivery_module_plugin POST_BUILD
|
||||
COMMAND install_name_tool -id "@rpath/delivery_module_plugin.dylib" $<TARGET_FILE:delivery_module_plugin>
|
||||
COMMAND install_name_tool -id "@rpath/${LIBLOGOSDELIVERY_FILENAME}" "${CMAKE_BINARY_DIR}/modules/${LIBLOGOSDELIVERY_FILENAME}"
|
||||
COMMAND install_name_tool -change "${LIBLOGOSDELIVERY_PATH}" "@rpath/${LIBLOGOSDELIVERY_FILENAME}" $<TARGET_FILE:delivery_module_plugin>
|
||||
COMMENT "Updating library paths for macOS"
|
||||
)
|
||||
else()
|
||||
add_custom_command(TARGET delivery_module_plugin POST_BUILD
|
||||
COMMAND install_name_tool -id "@rpath/delivery_module_plugin.dylib" $<TARGET_FILE:delivery_module_plugin>
|
||||
COMMENT "Updating library paths for macOS (liblogosdelivery not found)"
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
set_target_properties(delivery_module_plugin PROPERTIES
|
||||
INSTALL_RPATH "$ORIGIN"
|
||||
INSTALL_RPATH_USE_LINK_PATH FALSE)
|
||||
|
||||
if(LIBLOGOSDELIVERY_PATH)
|
||||
get_filename_component(LIBLOGOSDELIVERY_FILENAME "${LIBLOGOSDELIVERY_PATH}" NAME)
|
||||
add_custom_command(TARGET delivery_module_plugin PRE_LINK
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${LIBLOGOSDELIVERY_PATH}
|
||||
${CMAKE_BINARY_DIR}/modules/${LIBLOGOSDELIVERY_FILENAME}
|
||||
COMMENT "Copying ${LIBLOGOSDELIVERY_FILENAME} to modules directory"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
install(TARGETS delivery_module_plugin
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/logos/modules
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}/logos/modules
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/logos/modules
|
||||
)
|
||||
|
||||
install(FILES ${METADATA_JSON}
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/logos-delivery-module
|
||||
)
|
||||
|
||||
install(DIRECTORY "${PLUGINS_OUTPUT_DIR}/"
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/logos-delivery-module/generated
|
||||
OPTIONAL
|
||||
# Define the module
|
||||
logos_module(
|
||||
NAME delivery_module
|
||||
SOURCES
|
||||
src/delivery_module_interface.h
|
||||
src/delivery_module_plugin.h
|
||||
src/delivery_module_plugin.cpp
|
||||
src/api_call_handler.h
|
||||
src/QExpected.h
|
||||
EXTERNAL_LIBS
|
||||
logosdelivery
|
||||
INCLUDE_DIRS
|
||||
lib
|
||||
)
|
||||
|
||||
include(CTest)
|
||||
|
||||
@@ -88,24 +88,115 @@ All dependencies are automatically handled by the Nix flake configuration.
|
||||
|
||||
## Module Interface
|
||||
|
||||
The delivery module provides the following API methods:
|
||||
The delivery module provides the following API methods (all synchronous):
|
||||
|
||||
- `createNode(cfg: QString)` - Initialize the delivery node with JSON configuration
|
||||
- `createNode(cfg: QString)` - Initialize the delivery node with a JSON configuration (call once)
|
||||
- `start()` - Start the delivery node
|
||||
- `stop()` - Stop the delivery node
|
||||
- `send(contentTopic: QString, payload: QString)` - Send a message
|
||||
- `send(contentTopic: QString, payload: QString)` - Send a message (returns a request id)
|
||||
- `subscribe(contentTopic: QString)` - Subscribe to receive messages on a topic
|
||||
- `unsubscribe(contentTopic: QString)` - Unsubscribe from a topic
|
||||
- `getAvailableNodeInfoIDs()` - List queryable node info identifiers
|
||||
- `getNodeInfo(nodeInfoId: QString)` - Retrieve node info by identifier
|
||||
- `getAvailableConfigs()` - Retrieve available configuration parameter descriptions
|
||||
|
||||
### Node Configuration (`createNode`)
|
||||
|
||||
`createNode` accepts a **flat** JSON object whose keys correspond to `WakuNodeConf`
|
||||
field names (camelCase) from
|
||||
[logos-delivery](https://github.com/logos-messaging/logos-delivery).
|
||||
Unknown keys are silently ignored. Every field has a built-in default, so only
|
||||
values that differ from defaults need to be supplied.
|
||||
|
||||
#### Commonly used keys
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|----------------------|------------------|------------|------------------------------------------|
|
||||
| `mode` | string | `"noMode"` | `"Core"`, `"Edge"`, or `"noMode"` |
|
||||
| `preset` | string | `""` | Network preset (`"twn"`, `"logos.dev"`) |
|
||||
| `clusterId` | number (uint16) | `0` | Cluster identifier |
|
||||
| `entryNodes` | array of string | `[]` | Bootstrap peers (enrtree / multiaddress) |
|
||||
| `relay` | boolean | `false` | Enable relay protocol |
|
||||
| `rlnRelay` | boolean | `false` | Enable RLN rate-limit nullifier |
|
||||
| `tcpPort` | number (uint16) | `60000` | P2P TCP listen port |
|
||||
| `numShardsInNetwork` | number (uint16) | `1` | Auto-sharding shard count |
|
||||
| `logLevel` | string | `"INFO"` | `"TRACE"`, `"DEBUG"`, `"INFO"`, `"WARN"` |
|
||||
| `logFormat` | string | `"TEXT"` | `"TEXT"` or `"JSON"` |
|
||||
| `maxMessageSize` | string | `"150KiB"` | Maximum message payload size |
|
||||
|
||||
#### Presets
|
||||
|
||||
Using a `preset` populates cluster ID, entry nodes, sharding, RLN, and other
|
||||
network-specific defaults automatically. Individual keys supplied alongside a
|
||||
preset override the preset values.
|
||||
|
||||
- `"twn"` – The RLN-protected Waku Network (cluster 1).
|
||||
- `"logos.dev"` – Logos Dev Network (cluster 2, mix enabled, p2pReliability on,
|
||||
8 auto-shards, built-in bootstrap nodes).
|
||||
|
||||
Minimal example using the `logos.dev` preset:
|
||||
|
||||
```json
|
||||
{
|
||||
"logLevel": "INFO",
|
||||
"mode": "Core",
|
||||
"preset": "logos.dev"
|
||||
}
|
||||
```
|
||||
|
||||
### Content Topics
|
||||
|
||||
Content topics identify message channels for publishing and subscribing. Use a
|
||||
properly structured content topic for your application following the format
|
||||
specified in
|
||||
[LIP-23: Topics](https://lip.logos.co/messaging/informational/23/topics.html#content-topics).
|
||||
|
||||
Example: `"/myapp/1/chat/proto"`
|
||||
|
||||
### Sending Messages (`send`)
|
||||
|
||||
`send(contentTopic, payload)` accepts a content topic and a raw payload string.
|
||||
The plugin converts the payload to UTF-8 bytes, base64-encodes it, and wraps it
|
||||
in a JSON envelope before crossing the FFI boundary:
|
||||
|
||||
```json
|
||||
{ "contentTopic": "<topic>", "payload": "<base64>", "ephemeral": false }
|
||||
```
|
||||
|
||||
The call is synchronous and returns a **request id** on success. The actual
|
||||
network delivery is asynchronous — track results via the emitted events:
|
||||
|
||||
- **`messageError`** – the module could not send the message.
|
||||
- **`messagePropagated`** – the message reached the network but is not yet
|
||||
validated.
|
||||
- **`messageSent`** – the message has been confirmed by the network.
|
||||
|
||||
### Events
|
||||
|
||||
The module emits the following events:
|
||||
Asynchronous events are emitted off-thread as Logos Plugin events. Each event
|
||||
carries a `QVariantList data` with positional values:
|
||||
|
||||
- `deliveryInitialized` - When the node is initialized
|
||||
- `deliveryStarted` - When the node is started
|
||||
- `messageSent` - When a message is successfully sent
|
||||
- `messageReceived` - When a message is received
|
||||
- `messageError` - When an error occurs during message sending
|
||||
- **`messageSent`** – message confirmed by the network
|
||||
- `data[0]` (`QString`): request id
|
||||
- `data[1]` (`QString`): message hash
|
||||
- `data[2]` (`QString`): local timestamp (ISO-8601)
|
||||
- **`messageError`** – send failure
|
||||
- `data[0]` (`QString`): request id
|
||||
- `data[1]` (`QString`): message hash
|
||||
- `data[2]` (`QString`): error message
|
||||
- `data[3]` (`QString`): local timestamp (ISO-8601)
|
||||
- **`messagePropagated`** – message reached the network but not yet validated
|
||||
- `data[0]` (`QString`): request id
|
||||
- `data[1]` (`QString`): message hash
|
||||
- `data[2]` (`QString`): local timestamp (ISO-8601)
|
||||
- **`messageReceived`** – a message arrived on a subscribed topic
|
||||
- `data[0]` (`QString`): message hash
|
||||
- `data[1]` (`QString`): content topic
|
||||
- `data[2]` (`QString`): payload (base64-encoded)
|
||||
- `data[3]` (`QString`): timestamp (nanoseconds since epoch)
|
||||
- **`connectionStateChanged`** – node connectivity change
|
||||
- `data[0]` (`QString`): connection status
|
||||
- `data[1]` (`QString`): local timestamp (ISO-8601)
|
||||
|
||||
## Architecture
|
||||
|
||||
|
||||
Generated
+1788
-71
File diff suppressed because it is too large
Load Diff
@@ -2,76 +2,37 @@
|
||||
description = "Logos Delivery Module";
|
||||
|
||||
inputs = {
|
||||
# Follow the same nixpkgs as logos-liblogos to ensure compatibility
|
||||
nixpkgs.follows = "logos-liblogos/nixpkgs";
|
||||
logos-cpp-sdk.url = "github:logos-co/logos-cpp-sdk?ref=feat/logos-result";
|
||||
logos-liblogos.url = "github:logos-co/logos-liblogos";
|
||||
logos-module-builder.url = "github:logos-co/logos-module-builder";
|
||||
nix-bundle-lgx.url = "github:logos-co/nix-bundle-lgx";
|
||||
logos-delivery.url = "git+https://github.com/logos-messaging/logos-delivery?submodules=1";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, logos-cpp-sdk, logos-liblogos, logos-delivery }:
|
||||
let
|
||||
systems = [ "aarch64-darwin" "x86_64-darwin" "aarch64-linux" "x86_64-linux" ];
|
||||
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f {
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
logosSdk = logos-cpp-sdk.packages.${system}.default;
|
||||
logosLiblogos = logos-liblogos.packages.${system}.default;
|
||||
logosDelivery = (logos-delivery.packages.${system}.liblogosdelivery).overrideAttrs (old: {
|
||||
NIMFLAGS = (old.NIMFLAGS or "") + " -d:postgres -d:nimDebugDlOpen -d:chronicles_colors:none ";
|
||||
});
|
||||
});
|
||||
in
|
||||
{
|
||||
packages = forAllSystems ({ pkgs, logosSdk, logosLiblogos, logosDelivery }:
|
||||
let
|
||||
# Common configuration
|
||||
common = import ./nix/default.nix { inherit pkgs logosSdk logosLiblogos logosDelivery; };
|
||||
src = ./.;
|
||||
|
||||
# Library package (plugin + libcodex)
|
||||
lib = import ./nix/lib.nix { inherit pkgs common src logosDelivery; };
|
||||
|
||||
# Include package (generated headers from plugin)
|
||||
include = import ./nix/header.nix { inherit pkgs common src lib logosSdk logosDelivery; };
|
||||
|
||||
# Combined package
|
||||
combined = pkgs.symlinkJoin {
|
||||
name = "logos-delivery-module";
|
||||
paths = [ lib include ];
|
||||
};
|
||||
in
|
||||
{
|
||||
# Individual outputs
|
||||
lib = lib;
|
||||
include = include;
|
||||
|
||||
# Default package (combined)
|
||||
default = combined;
|
||||
}
|
||||
);
|
||||
|
||||
devShells = forAllSystems ({ pkgs, logosSdk, logosLiblogos, logosDelivery }: {
|
||||
default = pkgs.mkShell {
|
||||
nativeBuildInputs = [
|
||||
pkgs.cmake
|
||||
pkgs.ninja
|
||||
pkgs.pkg-config
|
||||
];
|
||||
buildInputs = [
|
||||
pkgs.qt6.qtbase
|
||||
pkgs.qt6.qtremoteobjects
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
export LOGOS_CPP_SDK_ROOT="${logosSdk}"
|
||||
export LOGOS_LIBLOGOS_ROOT="${logosLiblogos}"
|
||||
export LOGOS_DELIVERY_ROOT="${logosDelivery}"
|
||||
echo "Logos Delivery Module development environment"
|
||||
echo "LOGOS_CPP_SDK_ROOT: $LOGOS_CPP_SDK_ROOT"
|
||||
echo "LOGOS_LIBLOGOS_ROOT: $LOGOS_LIBLOGOS_ROOT"
|
||||
echo "LOGOS_DELIVERY_ROOT: $LOGOS_DELIVERY_ROOT"
|
||||
'';
|
||||
};
|
||||
});
|
||||
outputs = inputs@{ logos-module-builder, ... }:
|
||||
logos-module-builder.lib.mkLogosModule {
|
||||
src = ./.;
|
||||
configFile = ./metadata.json;
|
||||
flakeInputs = inputs;
|
||||
externalLibInputs = {
|
||||
delivery = inputs.logos-delivery;
|
||||
};
|
||||
# TODO: The module builder copies libwaku.h from the flake output instead of
|
||||
# liblogosdelivery.h from the source. This workaround copies the correct header.
|
||||
# Should be fixed in logos-module-builder (e.g. header_path in metadata.json).
|
||||
preConfigure = ''
|
||||
mkdir -p lib
|
||||
for f in $(find /nix/store -maxdepth 5 -name "liblogosdelivery.h" 2>/dev/null); do
|
||||
cp "$f" lib/ 2>/dev/null || true
|
||||
done
|
||||
'';
|
||||
# Bundle runtime libraries alongside the plugin.
|
||||
postInstall = ''
|
||||
# Use pkg-config to locate the exact libpq from the build environment
|
||||
LIBPQ_LIBDIR=$(pkg-config --variable=libdir libpq 2>/dev/null || true)
|
||||
if [ -n "$LIBPQ_LIBDIR" ] && [ -d "$LIBPQ_LIBDIR" ]; then
|
||||
for f in "$LIBPQ_LIBDIR"/libpq.*; do
|
||||
[ -f "$f" ] && cp -L "$f" $out/lib/ 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
+34
-19
@@ -1,20 +1,35 @@
|
||||
{
|
||||
"name": "delivery_module",
|
||||
"version": "1.0.0",
|
||||
"description": "Logos Delivery Module - High-level message-delivery API",
|
||||
"author": "Logos Core Team",
|
||||
"type": "core",
|
||||
"category": "protocol",
|
||||
"main": "delivery_module_plugin",
|
||||
"dependencies": [],
|
||||
"include": [
|
||||
"liblogosdelivery.so",
|
||||
"liblogosdelivery.dylib",
|
||||
"liblogosdelivery.dll",
|
||||
"libpq.so",
|
||||
"libpq.so.5",
|
||||
"libpq.dylib",
|
||||
"libpq.5.dylib",
|
||||
"libpq.dll"],
|
||||
"capabilities": []
|
||||
}
|
||||
"name": "delivery_module",
|
||||
"version": "1.0.0",
|
||||
"description": "Logos Delivery Module - High-level message-delivery API",
|
||||
"author": "Logos Core Team",
|
||||
"type": "core",
|
||||
"category": "protocol",
|
||||
"main": "delivery_module_plugin",
|
||||
"dependencies": [],
|
||||
"include": [
|
||||
"liblogosdelivery.so",
|
||||
"liblogosdelivery.dylib",
|
||||
"liblogosdelivery.dll",
|
||||
"libpq.so",
|
||||
"libpq.so.5",
|
||||
"libpq.dylib",
|
||||
"libpq.5.dylib",
|
||||
"libpq.dll"
|
||||
],
|
||||
"capabilities": [],
|
||||
"nix": {
|
||||
"packages": {
|
||||
"runtime": ["postgresql"]
|
||||
},
|
||||
"external_libraries": [
|
||||
{
|
||||
"name": "delivery",
|
||||
"build_command": "true"
|
||||
}
|
||||
],
|
||||
"cmake": {
|
||||
"extra_include_dirs": ["lib"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# Common build configuration shared across all packages
|
||||
{ pkgs, logosSdk, logosLiblogos, logosDelivery }:
|
||||
|
||||
{
|
||||
pname = "logos-delivery-module";
|
||||
version = "1.0.0";
|
||||
|
||||
# Common native build inputs
|
||||
nativeBuildInputs = [
|
||||
pkgs.cmake
|
||||
pkgs.ninja
|
||||
pkgs.pkg-config
|
||||
pkgs.qt6.wrapQtAppsNoGuiHook
|
||||
];
|
||||
|
||||
# Common runtime dependencies
|
||||
buildInputs = [
|
||||
pkgs.qt6.qtbase
|
||||
pkgs.qt6.qtremoteobjects
|
||||
pkgs.postgresql
|
||||
];
|
||||
|
||||
# Common CMake flags
|
||||
cmakeFlags = [
|
||||
"-GNinja"
|
||||
"-DBUILD_TESTING=ON"
|
||||
"-DLOGOS_CPP_SDK_ROOT=${logosSdk}"
|
||||
"-DLOGOS_LIBLOGOS_ROOT=${logosLiblogos}"
|
||||
"-DLOGOS_DELIVERY_ROOT=${logosDelivery}"
|
||||
"-DLOGOS_MESSAGING_MODULE_USE_VENDOR=OFF"
|
||||
];
|
||||
|
||||
# Environment variables
|
||||
env = {
|
||||
LOGOS_CPP_SDK_ROOT = "${logosSdk}";
|
||||
LOGOS_LIBLOGOS_ROOT = "${logosLiblogos}";
|
||||
LOGOS_DELIVERY_ROOT = "${logosDelivery}";
|
||||
};
|
||||
|
||||
# Metadata
|
||||
meta = with pkgs.lib; {
|
||||
description = "Logos Delivery Module - Provides Logos Delivery communication capabilities";
|
||||
platforms = platforms.unix;
|
||||
};
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
# Generates headers from the messaging module plugin using logos-cpp-generator
|
||||
{ pkgs, common, src, lib, logosSdk, logosDelivery }:
|
||||
|
||||
pkgs.stdenv.mkDerivation {
|
||||
pname = "${common.pname}-headers";
|
||||
version = common.version;
|
||||
|
||||
inherit src;
|
||||
inherit (common) meta;
|
||||
|
||||
# We need the generator and the built plugin
|
||||
nativeBuildInputs = [ logosSdk ];
|
||||
buildInputs = [ pkgs.qt6.qtbase pkgs.qt6.qtremoteobjects ];
|
||||
|
||||
# No configure phase needed
|
||||
dontConfigure = true;
|
||||
dontWrapQtApps = true;
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
# Create output directory for generated headers
|
||||
mkdir -p ./generated_headers
|
||||
|
||||
# Determine platform-specific library extension
|
||||
if [ -f "${lib}/lib/delivery_module_plugin.dylib" ]; then
|
||||
PLUGIN_FILE="${lib}/lib/delivery_module_plugin.dylib"
|
||||
elif [ -f "${lib}/lib/delivery_module_plugin.so" ]; then
|
||||
PLUGIN_FILE="${lib}/lib/delivery_module_plugin.so"
|
||||
else
|
||||
echo "Error: No delivery_module_plugin library file found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set library path so the plugin can find liblogosdelivery when loaded
|
||||
if [ "$(uname -s)" = "Darwin" ]; then
|
||||
export DYLD_LIBRARY_PATH="${lib}/lib:''${DYLD_LIBRARY_PATH:-}"
|
||||
else
|
||||
export LD_LIBRARY_PATH="${lib}/lib:${pkgs.qt6.qtbase}/lib:${pkgs.qt6.qtremoteobjects}/lib:''${LD_LIBRARY_PATH:-}"
|
||||
fi
|
||||
|
||||
# Run logos-cpp-generator on the built plugin with --module-only flag
|
||||
echo "Running logos-cpp-generator on $PLUGIN_FILE"
|
||||
echo "Library path: ${lib}/lib"
|
||||
ls -la "${lib}/lib"
|
||||
logos-cpp-generator "$PLUGIN_FILE" --output-dir ./generated_headers --module-only || {
|
||||
echo "Warning: logos-cpp-generator failed, this may be expected if the module has no public API"
|
||||
# Create a marker file to indicate attempt was made
|
||||
touch ./generated_headers/.no-api
|
||||
}
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
# Install generated headers
|
||||
mkdir -p $out/include
|
||||
|
||||
# Copy all generated files to include/ if they exist
|
||||
if [ -d ./generated_headers ] && [ "$(ls -A ./generated_headers 2>/dev/null)" ]; then
|
||||
echo "Copying generated headers..."
|
||||
ls -la ./generated_headers
|
||||
cp -r ./generated_headers/. $out/include/
|
||||
else
|
||||
echo "Warning: No generated headers found, creating empty include directory"
|
||||
# Create a placeholder file to indicate headers should be generated from metadata
|
||||
echo "# Generated headers from metadata.json" > $out/include/.generated
|
||||
fi
|
||||
|
||||
# Copy header from logos-delivery
|
||||
echo "Copying header from logos-delivery..."
|
||||
if [ -d "${logosDelivery}/include" ]; then
|
||||
echo "Found include directory in logos-delivery"
|
||||
cp -r "${logosDelivery}/include"/. $out/include/
|
||||
else
|
||||
echo "Warning: No include directory found in logos-delivery"
|
||||
fi
|
||||
|
||||
echo "Copied include files:"
|
||||
ls -la $out/include/
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
}
|
||||
-148
@@ -1,148 +0,0 @@
|
||||
# Builds the logos-delivery-module library
|
||||
{ pkgs, common, src, logosDelivery }:
|
||||
|
||||
pkgs.stdenv.mkDerivation {
|
||||
pname = "${common.pname}-lib";
|
||||
version = common.version;
|
||||
|
||||
inherit src;
|
||||
inherit (common) nativeBuildInputs buildInputs cmakeFlags meta env;
|
||||
|
||||
doCheck = true;
|
||||
checkPhase = ''
|
||||
runHook preCheck
|
||||
ctest --output-on-failure
|
||||
runHook postCheck
|
||||
'';
|
||||
|
||||
# Determine platform-specific library extension
|
||||
libdeliveryLib = if pkgs.stdenv.hostPlatform.isDarwin then "liblogosdelivery.dylib" else "liblogosdelivery.so";
|
||||
libpqPattern = if pkgs.stdenv.hostPlatform.isDarwin then "libpq*.dylib" else "libpq.so*";
|
||||
|
||||
postInstall = ''
|
||||
mkdir -p $out/lib
|
||||
|
||||
# Copy libpq from PostgreSQL so it ships with the module runtime libs
|
||||
for pq in ${pkgs.lib.getLib pkgs.postgresql}/lib/''${libpqPattern}; do
|
||||
if [ -e "$pq" ]; then
|
||||
cp -L "$pq" "$out/lib/$(basename "$pq")"
|
||||
fi
|
||||
done
|
||||
|
||||
# Normalize libpq naming for runtime loaders
|
||||
if [ -f "$out/lib/libpq.5.dylib" ] && [ ! -e "$out/lib/libpq.dylib" ]; then
|
||||
ln -s libpq.5.dylib "$out/lib/libpq.dylib"
|
||||
fi
|
||||
|
||||
if [ -f "$out/lib/libpq.so.5" ] && [ ! -e "$out/lib/libpq.so" ]; then
|
||||
ln -s libpq.so.5 "$out/lib/libpq.so"
|
||||
fi
|
||||
|
||||
# Copy liblogosdelivery directly from the delivery package
|
||||
if [ -f "${logosDelivery}/bin/''${libdeliveryLib}" ]; then
|
||||
cp "${logosDelivery}/bin/''${libdeliveryLib}" "$out/lib/''${libdeliveryLib}"
|
||||
elif [ -f "$out/share/logos-delivery-module/generated/''${libdeliveryLib}" ]; then
|
||||
cp "$out/share/logos-delivery-module/generated/''${libdeliveryLib}" "$out/lib/''${libdeliveryLib}"
|
||||
fi
|
||||
|
||||
# Fix the install name of liblogosdelivery on macOS
|
||||
${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isDarwin ''
|
||||
if [ -f "$out/lib/''${libdeliveryLib}" ]; then
|
||||
${pkgs.darwin.cctools}/bin/install_name_tool -id "@rpath/''${libdeliveryLib}" "$out/lib/''${libdeliveryLib}"
|
||||
# Ensure @rpath lookups resolve against the library's own directory
|
||||
${pkgs.darwin.cctools}/bin/install_name_tool -add_rpath "@loader_path" "$out/lib/''${libdeliveryLib}" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
if [ -f "$out/lib/libpq.dylib" ]; then
|
||||
${pkgs.darwin.cctools}/bin/install_name_tool -id "@loader_path/libpq.dylib" "$out/lib/libpq.dylib" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
if [ -f "$out/lib/libpq.5.dylib" ]; then
|
||||
${pkgs.darwin.cctools}/bin/install_name_tool -id "@loader_path/libpq.5.dylib" "$out/lib/libpq.5.dylib" 2>/dev/null || true
|
||||
fi
|
||||
''}
|
||||
|
||||
# Ensure Linux runtime lookup can find adjacent shared libraries
|
||||
${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isLinux ''
|
||||
if [ -f "$out/lib/''${libdeliveryLib}" ]; then
|
||||
chmod 755 -R $out/lib
|
||||
${pkgs.patchelf}/bin/patchelf --set-rpath '$ORIGIN' "$out/lib/''${libdeliveryLib}"
|
||||
${pkgs.patchelf}/bin/patchelf --add-needed libpq.so.5 "$out/lib/''${libdeliveryLib}" 2>/dev/null || true
|
||||
fi
|
||||
''}
|
||||
|
||||
# Copy the storage module plugin from the installed location
|
||||
if [ -f "$out/lib/logos/modules/delivery_module_plugin.dylib" ]; then
|
||||
cp "$out/lib/logos/modules/delivery_module_plugin.dylib" "$out/lib/"
|
||||
|
||||
# Fix the plugin's reference to liblogosdelivery on macOS
|
||||
${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isDarwin ''
|
||||
# Find what liblogosdelivery path the plugin is referencing and change it to @rpath
|
||||
for dep in $(${pkgs.darwin.cctools}/bin/otool -L "$out/lib/delivery_module_plugin.dylib" | grep liblogosdelivery | awk '{print $1}'); do
|
||||
${pkgs.darwin.cctools}/bin/install_name_tool -change "$dep" "@rpath/''${libdeliveryLib}" "$out/lib/delivery_module_plugin.dylib"
|
||||
done
|
||||
# Ensure plugin resolves @rpath entries from its own location
|
||||
${pkgs.darwin.cctools}/bin/install_name_tool -add_rpath "@loader_path" "$out/lib/delivery_module_plugin.dylib" 2>/dev/null || true
|
||||
|
||||
# If plugin references libpq directly, make it resolve next to the plugin
|
||||
for dep in $(${pkgs.darwin.cctools}/bin/otool -L "$out/lib/delivery_module_plugin.dylib" | grep libpq | awk '{print $1}'); do
|
||||
${pkgs.darwin.cctools}/bin/install_name_tool -change "$dep" "@loader_path/libpq.dylib" "$out/lib/delivery_module_plugin.dylib" 2>/dev/null || true
|
||||
done
|
||||
''}
|
||||
elif [ -f "$out/lib/logos/modules/delivery_module_plugin.so" ]; then
|
||||
cp "$out/lib/logos/modules/delivery_module_plugin.so" "$out/lib/"
|
||||
|
||||
${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isLinux ''
|
||||
${pkgs.patchelf}/bin/patchelf --set-rpath '$ORIGIN' "$out/lib/delivery_module_plugin.so"
|
||||
${pkgs.patchelf}/bin/patchelf --add-needed libpq.so.5 "$out/lib/delivery_module_plugin.so" 2>/dev/null || true
|
||||
''}
|
||||
else
|
||||
echo "Error: No delivery_module_plugin library file found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Remove the nested structure we don't want
|
||||
rm -rf "$out/lib/logos" 2>/dev/null || true
|
||||
rm -rf "$out/share" 2>/dev/null || true
|
||||
|
||||
# Assert runtime packaging/fixups are in place
|
||||
if [ ! -e "$out/lib/libpq.dylib" ] && [ ! -e "$out/lib/libpq.so" ] && [ ! -e "$out/lib/libpq.so.5" ]; then
|
||||
echo "Error: libpq was not packaged into $out/lib"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isDarwin ''
|
||||
if [ ! -f "$out/lib/liblogosdelivery.dylib" ]; then
|
||||
echo "Error: liblogosdelivery.dylib missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! ${pkgs.darwin.cctools}/bin/otool -l "$out/lib/liblogosdelivery.dylib" | grep -A2 LC_RPATH | grep -q '@loader_path'; then
|
||||
echo "Error: liblogosdelivery.dylib is missing LC_RPATH @loader_path"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f "$out/lib/libpq.dylib" ] && ! ${pkgs.darwin.cctools}/bin/otool -D "$out/lib/libpq.dylib" | grep -q '@loader_path/libpq.dylib'; then
|
||||
echo "Error: libpq.dylib install id is not @loader_path/libpq.dylib"
|
||||
exit 1
|
||||
fi
|
||||
''}
|
||||
|
||||
${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isLinux ''
|
||||
if [ ! -f "$out/lib/liblogosdelivery.so" ]; then
|
||||
echo "Error: liblogosdelivery.so missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$(${pkgs.patchelf}/bin/patchelf --print-rpath "$out/lib/liblogosdelivery.so")" != '$ORIGIN' ]; then
|
||||
echo "Error: liblogosdelivery.so rpath is not $ORIGIN"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! ${pkgs.patchelf}/bin/patchelf --print-needed "$out/lib/liblogosdelivery.so" | grep -q '^libpq\.so\.5$'; then
|
||||
echo "Error: liblogosdelivery.so is missing NEEDED libpq.so.5"
|
||||
exit 1
|
||||
fi
|
||||
''}
|
||||
'';
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include "interface.h"
|
||||
#include "QExpected.h"
|
||||
#include "logos_types.h"
|
||||
|
||||
class DeliveryModuleInterface : public PluginInterface
|
||||
{
|
||||
@@ -11,12 +11,14 @@ public:
|
||||
Q_INVOKABLE virtual bool createNode(const QString &cfg) = 0;
|
||||
Q_INVOKABLE virtual bool start() = 0;
|
||||
Q_INVOKABLE virtual bool stop() = 0;
|
||||
Q_INVOKABLE virtual QExpected<QString> send(const QString &contentTopic, const QString &payload) = 0;
|
||||
Q_INVOKABLE virtual LogosResult send(const QString &contentTopic, const QString &payload) = 0;
|
||||
Q_INVOKABLE virtual bool subscribe(const QString &contentTopic) = 0;
|
||||
Q_INVOKABLE virtual bool unsubscribe(const QString &contentTopic) = 0;
|
||||
Q_INVOKABLE virtual QString getAvailableNodeInfoIDs() = 0;
|
||||
Q_INVOKABLE virtual QString getNodeInfo(const QString &nodeInfoId) = 0;
|
||||
Q_INVOKABLE virtual QString getAvailableConfigs() = 0;
|
||||
|
||||
signals:
|
||||
// for now this is required for events, later it might not be necessary if using a proxy
|
||||
void eventResponse(const QString& eventName, const QVariantList& data);
|
||||
};
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <QJsonObject>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <QJsonArray>
|
||||
#include <semaphore>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -104,6 +105,37 @@ void DeliveryModulePlugin::event_callback(int callerRet, const char* msg, size_t
|
||||
eventData << timestamp;
|
||||
plugin->emitEvent("messagePropagated", eventData);
|
||||
|
||||
} else if (eventType == "message_received") {
|
||||
// MessageReceivedEvent: messageHash, message (WakuMessage)
|
||||
QJsonObject msgObj = jsonObj["message"].toObject();
|
||||
QVariantList eventData;
|
||||
eventData << jsonObj["messageHash"].toString();
|
||||
eventData << msgObj["contentTopic"].toString();
|
||||
|
||||
// The waku API returns payload as a JSON byte array (e.g. [106,106,106,106]).
|
||||
// Convert it to a base64 string to match the documented event contract.
|
||||
QJsonValue payloadValue = msgObj["payload"];
|
||||
if (payloadValue.isArray()) {
|
||||
QJsonArray payloadArray = payloadValue.toArray();
|
||||
QByteArray payloadBytes;
|
||||
payloadBytes.reserve(payloadArray.size());
|
||||
for (const QJsonValue& val : payloadArray) {
|
||||
payloadBytes.append(static_cast<char>(val.toInt()));
|
||||
}
|
||||
eventData << QString::fromLatin1(payloadBytes.toBase64());
|
||||
} else {
|
||||
eventData << payloadValue.toString();
|
||||
}
|
||||
|
||||
eventData << QString::number(msgObj["timestamp"].toDouble(), 'f', 0);
|
||||
plugin->emitEvent("messageReceived", eventData);
|
||||
|
||||
} else if (eventType == "connection_status_change") {
|
||||
QVariantList eventData;
|
||||
eventData << jsonObj["connectionStatus"].toString();
|
||||
eventData << timestamp;
|
||||
plugin->emitEvent("connectionStateChanged", eventData);
|
||||
|
||||
} else {
|
||||
qWarning() << "DeliveryModulePlugin::event_callback: Unknown event type:" << eventType;
|
||||
}
|
||||
@@ -263,26 +295,26 @@ bool DeliveryModulePlugin::stop()
|
||||
qDebug() << "DeliveryModulePlugin: Messaging stop completed with success: true";
|
||||
return true;
|
||||
}
|
||||
QExpected<QString> DeliveryModulePlugin::send(const QString &contentTopic, const QString &payload)
|
||||
LogosResult DeliveryModulePlugin::send(const QString &contentTopic, const QString &payload)
|
||||
{
|
||||
qDebug() << "DeliveryModulePlugin::send called with contentTopic:" << contentTopic;
|
||||
qDebug() << "DeliveryModulePlugin::send payload:" << payload;
|
||||
|
||||
|
||||
if (!deliveryCtx) {
|
||||
qWarning() << "DeliveryModulePlugin: Cannot send message - context not initialized. Call createNode first.";
|
||||
return QExpected<QString>::err("Context not initialized");
|
||||
return {false, QVariant(), QStringLiteral("Context not initialized")};
|
||||
}
|
||||
|
||||
|
||||
// Construct JSON message according to logosdelivery_send API
|
||||
// The payload should be base64-encoded as per the API spec
|
||||
QJsonObject messageObj;
|
||||
messageObj["contentTopic"] = contentTopic;
|
||||
messageObj["payload"] = QString::fromUtf8(payload.toUtf8().toBase64());
|
||||
messageObj["ephemeral"] = false;
|
||||
|
||||
|
||||
QJsonDocument doc(messageObj);
|
||||
QByteArray messageJson = doc.toJson(QJsonDocument::Compact);
|
||||
|
||||
|
||||
auto outcome = callApiRetValue<QString>(
|
||||
"send",
|
||||
CALLBACK_TIMEOUT,
|
||||
@@ -290,12 +322,12 @@ QExpected<QString> DeliveryModulePlugin::send(const QString &contentTopic, const
|
||||
|
||||
if (outcome.isErr()) {
|
||||
qWarning() << "DeliveryModulePlugin: Send failed for topic:" << contentTopic << ", reason:" << outcome.error();
|
||||
return QExpected<QString>::err(outcome.error());
|
||||
return {false, QVariant(), outcome.error()};
|
||||
}
|
||||
|
||||
const QString responseMessage = outcome.value();
|
||||
qDebug() << "DeliveryModulePlugin: Send initiated for topic:" << contentTopic << ", with success: true";
|
||||
return QExpected<QString>::ok(responseMessage);
|
||||
return {true, responseMessage};
|
||||
}
|
||||
|
||||
bool DeliveryModulePlugin::subscribe(const QString &contentTopic)
|
||||
@@ -349,3 +381,72 @@ bool DeliveryModulePlugin::unsubscribe(const QString &contentTopic)
|
||||
qDebug() << "DeliveryModulePlugin: Unsubscribe completed for topic:" << contentTopic << " with success: true";
|
||||
return true;
|
||||
}
|
||||
|
||||
QString DeliveryModulePlugin::version() const {
|
||||
QString moduleVersion = "1.0.0";
|
||||
if (!deliveryCtx) {
|
||||
qWarning() << "DeliveryModulePlugin: Cannot subscribe - context not initialized. Call createNode first.";
|
||||
return moduleVersion + " (liblogosdelivery version unknown, context not initialized)";
|
||||
}
|
||||
|
||||
auto attributeName = "Version";
|
||||
auto liblogosDeliveryVersion = callApiRetValue<QString>(
|
||||
"get_node_info",
|
||||
CALLBACK_TIMEOUT,
|
||||
bindApiCall(logosdelivery_get_node_info, deliveryCtx, attributeName));
|
||||
|
||||
if (liblogosDeliveryVersion.isErr()) {
|
||||
qWarning() << "DeliveryModulePlugin: Get node info failed getting version, reason:" <<
|
||||
liblogosDeliveryVersion.error();
|
||||
return moduleVersion + " (liblogosdelivery version unknown)";
|
||||
}
|
||||
|
||||
const QString version = liblogosDeliveryVersion.value();
|
||||
qDebug() << "DeliveryModulePlugin: Get node info completed for attribute:" <<
|
||||
attributeName << ", with success: " << version;
|
||||
|
||||
return moduleVersion + " (liblogosdelivery version: " + version + ")";
|
||||
}
|
||||
|
||||
QString DeliveryModulePlugin::getAvailableNodeInfoIDs() {
|
||||
auto outcome = callApiRetValue<QString>(
|
||||
"get_available_node_info_ids",
|
||||
CALLBACK_TIMEOUT,
|
||||
bindApiCall(logosdelivery_get_available_node_info_ids, deliveryCtx));
|
||||
|
||||
if (outcome.isErr()) {
|
||||
qWarning() << "DeliveryModulePlugin: Get available node info IDs failed, reason:" << outcome.error();
|
||||
return QString();
|
||||
}
|
||||
|
||||
return outcome.value();
|
||||
}
|
||||
|
||||
QString DeliveryModulePlugin::getNodeInfo(const QString &nodeInfoId) {
|
||||
auto outcome = callApiRetValue<QString>(
|
||||
"get_node_info",
|
||||
CALLBACK_TIMEOUT,
|
||||
bindApiCall(logosdelivery_get_node_info, deliveryCtx, nodeInfoId.toUtf8().constData()));
|
||||
|
||||
if (outcome.isErr()) {
|
||||
qWarning() << "DeliveryModulePlugin: Get node info failed for ID:" << nodeInfoId <<
|
||||
", reason:" << outcome.error();
|
||||
return QString();
|
||||
}
|
||||
|
||||
return outcome.value();
|
||||
}
|
||||
|
||||
QString DeliveryModulePlugin::getAvailableConfigs() {
|
||||
auto outcome = callApiRetValue<QString>(
|
||||
"get_available_configs",
|
||||
CALLBACK_TIMEOUT,
|
||||
bindApiCall(logosdelivery_get_available_configs, deliveryCtx));
|
||||
|
||||
if (outcome.isErr()) {
|
||||
qWarning() << "DeliveryModulePlugin: Get available configs failed, reason:" << outcome.error();
|
||||
return QString();
|
||||
}
|
||||
|
||||
return outcome.value();
|
||||
}
|
||||
|
||||
+223
-13
@@ -7,42 +7,252 @@
|
||||
#include "logos_api.h"
|
||||
#include "logos_api_client.h"
|
||||
|
||||
/**
|
||||
* @brief Concrete Qt plugin implementing the delivery messaging module.
|
||||
*
|
||||
* This class adapts the host plugin API to liblogosdelivery C-FFI calls and
|
||||
* forwards asynchronous events back to the host through Logos API clients.
|
||||
*
|
||||
* Lifecycle contract:
|
||||
* - call @ref createNode exactly once per context
|
||||
* - call @ref start before message operations
|
||||
* - use @ref subscribe / @ref send / @ref unsubscribe as needed
|
||||
* - call @ref stop before shutdown
|
||||
* Notice all of these calls are synchronous.
|
||||
*
|
||||
* Asynchronous events are emitted off thread as Logos Plugin events.
|
||||
* Emitted plugin event contracts (name + `QVariantList data` indices):
|
||||
* - `messageSent` (see `send` method)
|
||||
* - `data[0]` (`QString`): request id
|
||||
* - `data[1]` (`QString`): message hash
|
||||
* - `data[2]` (`QString`): local timestamp (ISO-8601)
|
||||
* - `messageError` (see `send` method)
|
||||
* - `data[0]` (`QString`): request id
|
||||
* - `data[1]` (`QString`): message hash
|
||||
* - `data[2]` (`QString`): error message
|
||||
* - `data[3]` (`QString`): local timestamp (ISO-8601)
|
||||
* - `messagePropagated` (see `send` method)
|
||||
* - `data[0]` (`QString`): request id
|
||||
* - `data[1]` (`QString`): message hash
|
||||
* - `data[2]` (`QString`): local timestamp (ISO-8601)
|
||||
* - `messageReceived` (emitted when a message arrives on a subscribed topic)
|
||||
* - `data[0]` (`QString`): message hash
|
||||
* - `data[1]` (`QString`): content topic
|
||||
* - `data[2]` (`QString`): payload (base64-encoded)
|
||||
* - `data[3]` (`QString`): timestamp (nanoseconds since epoch)
|
||||
* - `connectionStateChanged`
|
||||
* - `data[0]` (`QString`): connection status
|
||||
* - `data[1]` (`QString`): local timestamp (ISO-8601)
|
||||
*
|
||||
* The raw FFI `eventType` values mapped into these plugin events are:
|
||||
* - `message_sent` -> `messageSent`
|
||||
* - `message_error` -> `messageError`
|
||||
* - `message_propagated` -> `messagePropagated`
|
||||
* - `message_received` -> `messageReceived`
|
||||
* - `connection_status_change` -> `connectionStateChanged`
|
||||
*
|
||||
* As a general concept consider using proper content_topic format for your purpose.
|
||||
* --> https://lip.logos.co/messaging/informational/23/topics.html#content-topics
|
||||
*/
|
||||
class DeliveryModulePlugin : public QObject, public DeliveryModuleInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID DeliveryModuleInterface_iid FILE "../metadata.json")
|
||||
Q_PLUGIN_METADATA(IID DeliveryModuleInterface_iid FILE "metadata.json")
|
||||
Q_INTERFACES(DeliveryModuleInterface PluginInterface)
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs the plugin with no active delivery context.
|
||||
*/
|
||||
DeliveryModulePlugin();
|
||||
|
||||
/**
|
||||
* @brief Destroys the plugin and releases owned resources.
|
||||
*
|
||||
* If present, the owned `LogosAPI` instance is deleted and the underlying
|
||||
* liblogosdelivery context is destroyed.
|
||||
*/
|
||||
virtual ~DeliveryModulePlugin();
|
||||
|
||||
/**
|
||||
* @brief Creates a liblogosdelivery node from a WakuNodeConf JSON document.
|
||||
*
|
||||
* The JSON is parsed by logos-delivery (liblogosdelivery folder) side and maps to
|
||||
* `WakuNodeConf` from `tools/confutils/cli_args.nim`
|
||||
* (https://github.com/logos-messaging/logos-delivery).
|
||||
*
|
||||
* The configuration is a **flat** JSON object whose keys correspond to
|
||||
* `WakuNodeConf` Nim field names (camelCase). Unknown keys are silently
|
||||
* ignored. Every field has a built-in default, so only the values that
|
||||
* differ from defaults need to be supplied.
|
||||
*
|
||||
* ## Commonly used keys
|
||||
* | Key | Type | Default | Description |
|
||||
* |----------------------|------------------|------------|---------------------------------------------|
|
||||
* | `mode` | string | `"noMode"` | `"Core"`, `"Edge"`, or `"noMode"` |
|
||||
* | `preset` | string | `""` | Network preset (`"twn"`, `"logos.dev"`, …) |
|
||||
* | `clusterId` | number (uint16) | `0` | Cluster identifier |
|
||||
* | `entryNodes` | array of string | `[]` | Bootstrap peers (enrtree / multiaddress) |
|
||||
* | `relay` | boolean | `false` | Enable relay protocol |
|
||||
* | `rlnRelay` | boolean | `false` | Enable RLN rate-limit nullifier |
|
||||
* | `tcpPort` | number (uint16) | `60000` | P2P TCP listen port |
|
||||
* | `numShardsInNetwork` | number (uint16) | `1` | Auto-sharding shard count |
|
||||
* | `logLevel` | string | `"INFO"` | `"TRACE"`, `"DEBUG"`, `"INFO"`, `"WARN"`, … |
|
||||
* | `logFormat` | string | `"TEXT"` | `"TEXT"` or `"JSON"` |
|
||||
* | `maxMessageSize` | string | `"150KiB"` | Maximum message payload size |
|
||||
*
|
||||
* ## Presets
|
||||
* Using a `preset` populates cluster ID, entry nodes, sharding, RLN, and
|
||||
* other network-specific defaults automatically. Individual keys supplied
|
||||
* alongside a preset override the preset values.
|
||||
* - `"twn"` – The RLN-protected Waku Network (cluster 1).
|
||||
* - `"logos.dev"` – Logos Dev Network (cluster 2, mix enabled,
|
||||
* p2pReliability on, 8 auto-shards, built-in bootstrap nodes).
|
||||
*
|
||||
* Minimal `logos.dev` example:
|
||||
* @code{.json}
|
||||
* {
|
||||
* "logLevel": "INFO",
|
||||
* "mode": "Core",
|
||||
* "preset": "logos.dev"
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* Full override example:
|
||||
* @code{.json}
|
||||
* {
|
||||
* "mode": "Core",
|
||||
* "clusterId": 42,
|
||||
* "entryNodes": ["enrtree://TREE@nodes.example.com"],
|
||||
* "relay": true,
|
||||
* "tcpPort": 60000,
|
||||
* "numShardsInNetwork": 8,
|
||||
* "maxMessageSize": "150KiB",
|
||||
* "logLevel": "INFO",
|
||||
* "logFormat": "TEXT"
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @param cfg UTF-16 Qt string containing a UTF-8 serializable JSON payload.
|
||||
* @return `true` if context creation succeeds and callback returns `RET_OK`,
|
||||
* otherwise `false`.
|
||||
*/
|
||||
Q_INVOKABLE bool createNode(const QString &cfg) override;
|
||||
Q_INVOKABLE bool start() override;
|
||||
Q_INVOKABLE bool stop() override;
|
||||
Q_INVOKABLE QExpected<QString> send(const QString &contentTopic, const QString &payload) override;
|
||||
Q_INVOKABLE bool subscribe(const QString &contentTopic) override;
|
||||
Q_INVOKABLE bool unsubscribe(const QString &contentTopic) override;
|
||||
QString name() const override { return "delivery_module"; }
|
||||
QString version() const override { return "1.0.0"; }
|
||||
|
||||
// LogosAPI initialization
|
||||
/**
|
||||
* @brief Starts the delivery node.
|
||||
* @return `true` on success; `false` when no context exists or start fails.
|
||||
*/
|
||||
Q_INVOKABLE bool start() override;
|
||||
|
||||
/**
|
||||
* @brief Stops the delivery node.
|
||||
* @return `true` on success; `false` when no context exists or stop fails.
|
||||
*/
|
||||
Q_INVOKABLE bool stop() override;
|
||||
|
||||
/**
|
||||
* @brief Sends a message over the active node.
|
||||
*
|
||||
* This method builds a JSON envelope expected by `logosdelivery_send`:
|
||||
* `{ "contentTopic": string, "payload": base64, "ephemeral": (bool, default: false) }`.
|
||||
*
|
||||
* `send` call validates the input and returns with an associated requestId.
|
||||
* After all the exact send operation is done async and user can expect Message events in response
|
||||
* The requestId helps keep track of send operation results.
|
||||
* - `messageError` emitted in case module can't sent the message
|
||||
* - `messagePropagated` emitted if message has hit the network, you can expect delivery but
|
||||
* module could not validate it yet.
|
||||
* - `messageSent` emitted after the sent message is validated by the network.
|
||||
*
|
||||
* @param contentTopic Destination content topic.
|
||||
* @param payload Raw message bytes represented as QString; converted to UTF-8
|
||||
* bytes and base64-encoded before crossing the FFI boundary.
|
||||
* @return Success with request id, or error details.
|
||||
*/
|
||||
Q_INVOKABLE LogosResult send(const QString &contentTopic, const QString &payload) override;
|
||||
|
||||
/**
|
||||
* @brief Subscribes to the supplied content topic.
|
||||
* @param contentTopic Topic identifier.
|
||||
* @return `true` when subscribed successfully, otherwise `false`.
|
||||
*/
|
||||
Q_INVOKABLE bool subscribe(const QString &contentTopic) override;
|
||||
|
||||
/**
|
||||
* @brief Unsubscribes from the supplied content topic.
|
||||
* @param contentTopic Topic identifier.
|
||||
* @return `true` when unsubscribed successfully, otherwise `false`.
|
||||
*/
|
||||
Q_INVOKABLE bool unsubscribe(const QString &contentTopic) override;
|
||||
Q_INVOKABLE QString getAvailableNodeInfoIDs() override;
|
||||
|
||||
/**
|
||||
* @brief Semantic version of this plugin implementation.
|
||||
* @param nodeInfoId Identifier for the requested node info item.
|
||||
* @return UTF-16 string containing UTF-8 serializable JSON data, or an empty string on error.
|
||||
*/
|
||||
Q_INVOKABLE QString getNodeInfo(const QString &nodeInfoId) override;
|
||||
|
||||
/**
|
||||
* @brief Information about the available configuration parameters to be used in `createNode`.
|
||||
*/
|
||||
Q_INVOKABLE QString getAvailableConfigs() override;
|
||||
|
||||
QString name() const override { return "delivery_module"; }
|
||||
|
||||
QString version() const;
|
||||
|
||||
/**
|
||||
* @brief Injects/replaces the Logos API bridge used for event forwarding.
|
||||
*
|
||||
* Ownership is transferred to this plugin instance.
|
||||
*
|
||||
* @param logosAPIInstance Heap-allocated API object or `nullptr`.
|
||||
*/
|
||||
Q_INVOKABLE void initLogos(LogosAPI* logosAPIInstance);
|
||||
|
||||
signals:
|
||||
// for now this is required for events, later it might not be necessary if using a proxy
|
||||
/**
|
||||
* @brief Module event signal (currently retained for compatibility).
|
||||
* @param eventName Event identifier.
|
||||
* @param data Event payload as positional values.
|
||||
*/
|
||||
void eventResponse(const QString& eventName, const QVariantList& data);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Opaque liblogosdelivery context pointer.
|
||||
*/
|
||||
void* deliveryCtx;
|
||||
|
||||
/**
|
||||
* @brief Serializes node creation to a single in-flight operation.
|
||||
*/
|
||||
std::mutex createNodeMutex;
|
||||
|
||||
// Timeout for callback operations
|
||||
/**
|
||||
* @brief Common timeout for FFI operations that complete via callback.
|
||||
*/
|
||||
static constexpr std::chrono::seconds CALLBACK_TIMEOUT{30};
|
||||
|
||||
// Helper method for emitting events
|
||||
/**
|
||||
* @brief Forwards normalized events to the registered Logos API client.
|
||||
* @param eventName Canonical event name.
|
||||
* @param data Event payload list.
|
||||
*/
|
||||
void emitEvent(const QString& eventName, const QVariantList& data);
|
||||
|
||||
// Static callback functions for liblogosdelivery
|
||||
/**
|
||||
* @brief Global C callback used by liblogosdelivery to report async events.
|
||||
*
|
||||
* Expected event payload format is a JSON document containing an `eventType`
|
||||
* discriminator and event-specific fields.
|
||||
*
|
||||
* @param callerRet FFI return code associated with callback dispatch.
|
||||
* @param msg UTF-8 JSON event payload buffer.
|
||||
* @param len Message length in bytes.
|
||||
* @param userData Opaque pointer expected to be `DeliveryModulePlugin*`.
|
||||
*/
|
||||
static void event_callback(int callerRet, const char* msg, size_t len, void* userData);
|
||||
};
|
||||
|
||||
Vendored
-1
Submodule vendor/logos-cpp-sdk deleted from 30ef7986f4
Vendored
-1
Submodule vendor/logos-delivery deleted from 8e41a27ad2
Vendored
-1
Submodule vendor/logos-liblogos deleted from e3741c01fd
Reference in New Issue
Block a user