feat: generate the C header instead of hand-writing it

The hand-written liblogosdelivery.h / _kernel.h declared the pre-CBOR
string ABI, so they lied about the real one -- a C consumer would link
against signatures that no longer exist. genBindings already produces the
Rust bindings from the Nim source; this adds the C target on the same
footing.

liblogosdeliveryGenBindingsC emits library/c_bindings/: logosdelivery.h
covering the whole surface (messaging, channels and the waku_* kernel
procs in one file), plus the nim_ffi_cbor.h / _prelude.h helpers that
marshal the CBOR payloads. Params ride as CBOR blobs, matching the
library's default ABI and what the Rust crate does internally; the typed
C ABI (abi=c) stays available per-proc for later.

The two hand-written headers are deleted and nix packaging ships the
generated ones. The C examples target the old string ABI and removed
headers, so they no longer compile; each is annotated as awaiting a port
rather than left with a dangling include that pretends to work.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ivan FB 2026-07-16 11:33:20 +02:00
parent 1ef53c9506
commit 047b709c55
No known key found for this signature in database
GPG Key ID: DF0C67A04C543270
10 changed files with 6225 additions and 397 deletions

View File

@ -63,12 +63,19 @@ build/
## Library Headers
The C API is tiered across two headers (one library, two stability promises):
- `library/liblogosdelivery.h` - stable, supported Messaging / Reliable
Channels API. This is the front door for consumers.
- `library/liblogosdelivery_kernel.h` - advanced, low-level kernel API
(`waku_*`). "Use at your own risk", may change at any time. Including it is
a deliberate opt-in; it pulls in `liblogosdelivery.h` for shared types.
The C header is generated from the Nim source by nim-ffi, not hand-written:
nimble liblogosdeliveryGenBindingsC
This emits `library/c_bindings/`:
- `logosdelivery.h` - the full C API (Messaging, Reliable Channels and the
low-level `waku_*` kernel procs, in one file).
- `nim_ffi_cbor.h` / `nim_ffi_prelude.h` - request/response payloads cross the
boundary as CBOR blobs (the library's default ABI), and these helpers encode
and decode them. `logosdelivery.h` includes them.
Regenerate whenever the `{.ffi.}` surface changes; the checked-in copy must
match the Nim source.
## Troubleshooting

View File

@ -0,0 +1,47 @@
cmake_minimum_required(VERSION 3.14)
project(logosdelivery_c_bindings C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Locate the repository root (contains ffi.nimble)
set(_search_dir "${CMAKE_CURRENT_SOURCE_DIR}")
set(REPO_ROOT "")
foreach(_i RANGE 10)
if(EXISTS "${_search_dir}/ffi.nimble")
set(REPO_ROOT "${_search_dir}")
break()
endif()
get_filename_component(_search_dir "${_search_dir}" DIRECTORY)
endforeach()
if("${REPO_ROOT}" STREQUAL "")
message(FATAL_ERROR "Cannot find repo root (no ffi.nimble in any ancestor)")
endif()
# Build the Nim dylib + vendored TinyCBOR (shared with the C++ backend).
set(NIM_FFI_LIB logosdelivery)
set(NIM_FFI_SRC library/liblogosdelivery.nim)
include("${REPO_ROOT}/ffi/codegen/templates/nim_ffi_lib.cmake")
find_package(Threads REQUIRED)
add_library(logosdelivery_headers INTERFACE)
target_include_directories(logosdelivery_headers INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}")
target_link_libraries(logosdelivery_headers INTERFACE logosdelivery tinycbor Threads::Threads)
# The generated header is async (no blocking helper), but consumer code that
# waits on a result callback typically uses nanosleep / pthreads, which need a
# POSIX feature level that strict `-std=c11` hides. Define it for consumers.
target_compile_definitions(logosdelivery_headers INTERFACE _POSIX_C_SOURCE=200809L)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/main.c")
add_executable(logosdelivery_example main.c)
target_link_libraries(logosdelivery_example PRIVATE logosdelivery_headers)
add_dependencies(logosdelivery_example logosdelivery_nim_lib)
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_custom_command(TARGET logosdelivery_example POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${logosdelivery_RUNTIME_LIB}"
"$<TARGET_FILE_DIR:logosdelivery_example>"
COMMENT "Staging logosdelivery.dll next to logosdelivery_example.exe")
endif()
endif()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,349 @@
#ifndef NIM_FFI_CBOR_HELPERS_H_INCLUDED
#define NIM_FFI_CBOR_HELPERS_H_INCLUDED
/* Leaf CBOR codecs (scalars, text strings, byte strings) plus the buffer
* drivers. The per-struct / per-container codecs in the library header call
* into these by name (C has no overloading, so each leaf gets a distinct
* nimffi_enc_* / nimffi_dec_* symbol). Guarded so two nim-ffi headers can
* share a translation unit. */
#include "nim_ffi_prelude.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Result delivery callback exported by the Nim dylib: `ret` is 0 on success
* (then `msg`/`len` carry the CBOR response) or non-zero on failure (then
* `msg`/`len` carry the error text, which is NOT NUL-terminated). */
typedef void (*FFICallback)(int ret, const char* msg, size_t len, void* user_data);
/* Return / callback status codes. NIMFFI_RET_OK (0) is success; any non-zero
* value handed to a result callback's `err_code` (or returned by a submit call)
* is a failure. NIMFFI_RET_MISSING_CALLBACK is a special case from the Nim
* dispatcher: the callback will never fire, so the request path must report the
* failure itself.
*
* NIMFFI_RET_STALE_WARN is the one NON-terminal code: nim-ffi delivers it every
* ~5s while a handler is still running (with `msg`/`len` carrying the elapsed
* milliseconds as decimal text), then still ends with a terminal RET_OK/RET_ERR.
* A caller that only wants the final answer must ignore it, not treat it as an
* error. */
#define NIMFFI_RET_OK 0
#define NIMFFI_RET_ERROR 1
#define NIMFFI_RET_MISSING_CALLBACK 2
#define NIMFFI_RET_STALE_WARN 3
/* ── leaf encoders ─────────────────────────────────────────────────────── */
static inline CborError nimffi_enc_bool(CborEncoder* e, const bool* v) {
return cbor_encode_boolean(e, *v);
}
static inline CborError nimffi_enc_i64(CborEncoder* e, const int64_t* v) {
return cbor_encode_int(e, *v);
}
static inline CborError nimffi_enc_i32(CborEncoder* e, const int32_t* v) {
return cbor_encode_int(e, (int64_t)*v);
}
static inline CborError nimffi_enc_i16(CborEncoder* e, const int16_t* v) {
return cbor_encode_int(e, (int64_t)*v);
}
static inline CborError nimffi_enc_i8(CborEncoder* e, const int8_t* v) {
return cbor_encode_int(e, (int64_t)*v);
}
static inline CborError nimffi_enc_u64(CborEncoder* e, const uint64_t* v) {
return cbor_encode_uint(e, *v);
}
static inline CborError nimffi_enc_u32(CborEncoder* e, const uint32_t* v) {
return cbor_encode_uint(e, (uint64_t)*v);
}
static inline CborError nimffi_enc_u16(CborEncoder* e, const uint16_t* v) {
return cbor_encode_uint(e, (uint64_t)*v);
}
static inline CborError nimffi_enc_u8(CborEncoder* e, const uint8_t* v) {
return cbor_encode_uint(e, (uint64_t)*v);
}
static inline CborError nimffi_enc_f64(CborEncoder* e, const double* v) {
return cbor_encode_double(e, *v);
}
static inline CborError nimffi_enc_f32(CborEncoder* e, const float* v) {
return cbor_encode_float(e, *v);
}
static inline CborError nimffi_enc_str(CborEncoder* e, const NimFfiStr* v) {
return cbor_encode_text_string(e, v->data ? v->data : "", v->len);
}
static inline CborError nimffi_enc_bytes(CborEncoder* e, const NimFfiBytes* v) {
return cbor_encode_byte_string(e, v->data, v->len);
}
/* ── leaf decoders ─────────────────────────────────────────────────────── */
/* After reading a leaf, the parser must advance past it; both steps
* short-circuit on the same CborError, so they travel together. */
static inline CborError nimffi_advance_if_ok(CborValue* it, CborError err) {
if (err) {
return err;
}
return cbor_value_advance(it);
}
static inline CborError nimffi_dec_bool(CborValue* it, bool* out) {
if (!cbor_value_is_boolean(it)) {
return CborErrorImproperValue;
}
return nimffi_advance_if_ok(it, cbor_value_get_boolean(it, out));
}
static inline CborError nimffi_dec_i64(CborValue* it, int64_t* out) {
if (!cbor_value_is_integer(it)) {
return CborErrorImproperValue;
}
return nimffi_advance_if_ok(it, cbor_value_get_int64_checked(it, out));
}
static inline CborError nimffi_dec_i32(CborValue* it, int32_t* out) {
int64_t tmp = 0;
CborError err = nimffi_dec_i64(it, &tmp);
if (err) {
return err;
}
if (tmp < INT32_MIN || tmp > INT32_MAX) {
return CborErrorDataTooLarge;
}
*out = (int32_t)tmp;
return CborNoError;
}
static inline CborError nimffi_dec_i16(CborValue* it, int16_t* out) {
int64_t tmp = 0;
CborError err = nimffi_dec_i64(it, &tmp);
if (err) {
return err;
}
if (tmp < INT16_MIN || tmp > INT16_MAX) {
return CborErrorDataTooLarge;
}
*out = (int16_t)tmp;
return CborNoError;
}
static inline CborError nimffi_dec_i8(CborValue* it, int8_t* out) {
int64_t tmp = 0;
CborError err = nimffi_dec_i64(it, &tmp);
if (err) {
return err;
}
if (tmp < INT8_MIN || tmp > INT8_MAX) {
return CborErrorDataTooLarge;
}
*out = (int8_t)tmp;
return CborNoError;
}
static inline CborError nimffi_dec_u64(CborValue* it, uint64_t* out) {
if (!cbor_value_is_unsigned_integer(it)) {
return CborErrorImproperValue;
}
return nimffi_advance_if_ok(it, cbor_value_get_uint64(it, out));
}
static inline CborError nimffi_dec_u32(CborValue* it, uint32_t* out) {
uint64_t tmp = 0;
CborError err = nimffi_dec_u64(it, &tmp);
if (err) {
return err;
}
if (tmp > UINT32_MAX) {
return CborErrorDataTooLarge;
}
*out = (uint32_t)tmp;
return CborNoError;
}
static inline CborError nimffi_dec_u16(CborValue* it, uint16_t* out) {
uint64_t tmp = 0;
CborError err = nimffi_dec_u64(it, &tmp);
if (err) {
return err;
}
if (tmp > UINT16_MAX) {
return CborErrorDataTooLarge;
}
*out = (uint16_t)tmp;
return CborNoError;
}
static inline CborError nimffi_dec_u8(CborValue* it, uint8_t* out) {
uint64_t tmp = 0;
CborError err = nimffi_dec_u64(it, &tmp);
if (err) {
return err;
}
if (tmp > UINT8_MAX) {
return CborErrorDataTooLarge;
}
*out = (uint8_t)tmp;
return CborNoError;
}
static inline CborError nimffi_dec_f64(CborValue* it, double* out) {
if (cbor_value_is_double(it)) {
return nimffi_advance_if_ok(it, cbor_value_get_double(it, out));
}
if (cbor_value_is_float(it)) {
float f = 0.0f;
CborError err = cbor_value_get_float(it, &f);
if (err) {
return err;
}
*out = (double)f;
return cbor_value_advance(it);
}
return CborErrorImproperValue;
}
static inline CborError nimffi_dec_f32(CborValue* it, float* out) {
if (cbor_value_is_float(it)) {
return nimffi_advance_if_ok(it, cbor_value_get_float(it, out));
}
if (cbor_value_is_double(it)) {
double d = 0.0;
CborError err = cbor_value_get_double(it, &d);
if (err) {
return err;
}
*out = (float)d;
return cbor_value_advance(it);
}
return CborErrorImproperValue;
}
static inline CborError nimffi_dec_str(CborValue* it, NimFfiStr* out) {
if (!cbor_value_is_text_string(it)) {
return CborErrorImproperValue;
}
size_t len = 0;
CborError err = cbor_value_get_string_length(it, &len);
if (err) {
return err;
}
if (len == SIZE_MAX) { /* len + 1 would wrap to a 0-byte allocation */
return CborErrorDataTooLarge;
}
/* one extra byte so a NUL-free payload is a valid C string */
out->data = (char*)malloc(len + 1);
if (!out->data) {
return CborErrorOutOfMemory;
}
out->len = len;
size_t copied = len;
err = cbor_value_copy_text_string(it, out->data, &copied, NULL);
if (err) {
free(out->data);
out->data = NULL;
out->len = 0;
return err;
}
out->data[len] = '\0';
return cbor_value_advance(it);
}
static inline CborError nimffi_dec_bytes(CborValue* it, NimFfiBytes* out) {
if (!cbor_value_is_byte_string(it)) {
return CborErrorImproperValue;
}
size_t len = 0;
CborError err = cbor_value_get_string_length(it, &len);
if (err) {
return err;
}
out->data = (uint8_t*)malloc(len ? len : 1);
if (!out->data) {
return CborErrorOutOfMemory;
}
out->len = len;
size_t copied = len;
err = cbor_value_copy_byte_string(it, out->data, &copied, NULL);
if (err) {
free(out->data);
out->data = NULL;
out->len = 0;
return err;
}
return cbor_value_advance(it);
}
/* ── buffer drivers ────────────────────────────────────────────────────── */
typedef CborError (*nimffi_enc_fn)(CborEncoder*, const void*);
typedef CborError (*nimffi_dec_fn)(CborValue*, void*);
static inline char* nimffi_dup_cstr(const char* s) {
size_t n = strlen(s) + 1;
char* p = (char*)malloc(n);
if (p) {
memcpy(p, s, n);
}
return p;
}
/* NUL-terminated copy of a length-delimited (not NUL-terminated) byte run,
* for turning the FFICallback's raw error `msg`/`len` into a C string. */
static inline char* nimffi_dup_cstr_n(const char* s, size_t n) {
char* p = (char*)malloc(n + 1);
if (p) {
if (n > 0) {
memcpy(p, s, n);
}
p[n] = '\0';
}
return p;
}
/* Encode `val` with `fn` into a freshly malloc'd buffer, doubling on overflow.
* Returns 0 and sets out/outlen on success; -1 and *err (heap) on failure. */
static inline int nimffi_encode_to_buf(
nimffi_enc_fn fn, const void* val,
uint8_t** out, size_t* outlen, char** err) {
size_t cap = 4096;
uint8_t* buf = (uint8_t*)malloc(cap);
if (!buf) {
if (err) *err = nimffi_dup_cstr("out of memory");
return -1;
}
for (;;) {
CborEncoder enc;
cbor_encoder_init(&enc, buf, cap, 0);
CborError e = fn(&enc, val);
if (e == CborNoError) {
*outlen = cbor_encoder_get_buffer_size(&enc, buf);
*out = buf;
return 0;
}
if (e == CborErrorOutOfMemory) {
size_t extra = cbor_encoder_get_extra_bytes_needed(&enc);
cap += extra > 0 ? extra : cap;
uint8_t* grown = (uint8_t*)realloc(buf, cap);
if (!grown) {
free(buf);
if (err) *err = nimffi_dup_cstr("out of memory");
return -1;
}
buf = grown;
continue;
}
free(buf);
if (err) *err = nimffi_dup_cstr(cbor_error_string(e));
return -1;
}
}
/* Decode a CBOR buffer into `out` with `fn`. Returns 0 on success; -1 and
* *err (heap) on failure. */
static inline int nimffi_decode_from_buf(
nimffi_dec_fn fn, const uint8_t* buf, size_t len,
void* out, char** err) {
CborParser parser;
CborValue it;
CborError e = cbor_parser_init(buf, len, 0, &parser, &it);
if (e != CborNoError) {
if (err) *err = nimffi_dup_cstr(cbor_error_string(e));
return -1;
}
e = fn(&it, out);
if (e != CborNoError) {
if (err) *err = nimffi_dup_cstr(cbor_error_string(e));
return -1;
}
return 0;
}
#ifdef __cplusplus
}
#endif
#endif /* NIM_FFI_CBOR_HELPERS_H_INCLUDED */

View File

@ -0,0 +1,89 @@
#ifndef NIM_FFI_PRELUDE_H_INCLUDED
#define NIM_FFI_PRELUDE_H_INCLUDED
/* Generated C binding for a nim-ffi library. Requests/responses travel as
* CBOR (encoded with vendored TinyCBOR on this side, matching the Nim-side
* cbor_serial codec on the wire both ends speak RFC 8949).
*
* The API is asynchronous: every method/constructor takes a result callback
* and returns immediately. The callback fires exactly once synchronously on
* a submit-time failure, otherwise from the Nim dispatch thread when the reply
* arrives.
*
* Memory ownership contract:
* - Request-side strings/sequences are *borrowed*: the binding only reads
* them while encoding, so a string literal wrapped with nimffi_str() is
* fine and is never freed by the binding.
* - Response values and error strings passed into a result callback are
* *owned by the binding* and valid only for the duration of that callback;
* the binding reclaims them once the callback returns. The caller never
* frees them. (The generated <lib>_free_<Type>() helpers are internal the
* trampolines use them to reclaim decoded payloads.)
* - A context handle delivered to a constructor callback is the exception:
* ownership transfers to the caller, who releases it with
* <lib>_ctx_destroy(). It is a lifecycle handle, not returned data.
*
* Trust boundary: the decoders assume the CBOR they parse was produced by the
* paired Nim library. They reject malformed input rather than trusting it, but
* they are not hardened against a hostile peer feeding crafted payloads through
* the raw nimffi_decode_from_buf entry point.
*/
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <tinycbor/cbor.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Owned, length-delimited UTF-8 text (Nim `string`/`cstring`). On the request
* side `data` may point at borrowed storage (see nimffi_str); on the response
* side it is heap-allocated and freed by nimffi_free_str. Always NUL-padded by
* one byte after decode so `data` is usable as a C string when it has no
* embedded NULs. */
typedef struct {
char* data;
size_t len;
} NimFfiStr;
/* Owned, length-delimited byte buffer (Nim `seq[byte]`). */
typedef struct {
uint8_t* data;
size_t len;
} NimFfiBytes;
/* Wrap a borrowed C string for use as a request field. The returned view is
* not owned by the binding and must outlive the call that encodes it. */
static inline NimFfiStr nimffi_str(const char* s) {
NimFfiStr v;
v.data = (char*)s;
v.len = s ? strlen(s) : 0;
return v;
}
static inline void nimffi_free_str(NimFfiStr* v) {
if (!v || !v->data) {
return;
}
free(v->data);
v->data = NULL;
v->len = 0;
}
static inline void nimffi_free_bytes(NimFfiBytes* v) {
if (!v || !v->data) {
return;
}
free(v->data);
v->data = NULL;
v->len = 0;
}
#ifdef __cplusplus
}
#endif
#endif /* NIM_FFI_PRELUDE_H_INCLUDED */

View File

@ -1,3 +1,8 @@
/* NOTE: This example targets the pre-CBOR string ABI and the removed
* hand-written headers. The FFI now generates its C header
* (library/c_bindings/logosdelivery.h) and passes requests as CBOR blobs, so
* this example no longer compiles as-is; it awaits a port to the generated
* CBOR ABI. See library/BUILD.md. */
#include "../liblogosdelivery.h"
#include "json_utils.h"
#include <stdio.h>

View File

@ -1,148 +0,0 @@
// Generated manually and inspired by libwaku.h
// Header file for Logos Messaging API (LMAPI) library
#pragma once
#ifndef __liblogosdelivery__
#define __liblogosdelivery__
#include <stddef.h>
#include <stdint.h>
// The possible returned values for the functions that return int
#define RET_OK 0
#define RET_ERR 1
#define RET_MISSING_CALLBACK 2
#ifdef __cplusplus
extern "C"
{
#endif
typedef void (*FFICallBack)(int callerRet, const char *msg, size_t len, void *userData);
// Creates a new instance of the node from the given configuration JSON.
// Returns a pointer to the Context needed by the rest of the API functions.
// The configuration is a JSON object with these optional keys:
// "mode": "Core" | "Edge" (messaging role; defaults to "Core")
// "preset": "<network preset>" (e.g. "twn")
// "messagingOverrides": { ... } (per-field messaging config overrides)
// "channelsOverrides": { ... } (per-field 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.
// Example: {"mode":"Core","messagingOverrides":{"cluster-id":42,"log-level":"INFO"}}
void *logosdelivery_create_node(
const char *configJson,
FFICallBack callback,
void *userData);
// Starts the node.
int logosdelivery_start_node(void *ctx,
FFICallBack callback,
void *userData);
// Stops the node.
int logosdelivery_stop_node(void *ctx,
FFICallBack callback,
void *userData);
// Destroys an instance of a node created with logosdelivery_create_node
int logosdelivery_destroy(void *ctx,
FFICallBack callback,
void *userData);
// Subscribe to a content topic.
// contentTopic: string representing the content topic (e.g., "/myapp/1/chat/proto")
int logosdelivery_subscribe(void *ctx,
FFICallBack callback,
void *userData,
const char *contentTopic);
// Unsubscribe from a content topic.
int logosdelivery_unsubscribe(void *ctx,
FFICallBack callback,
void *userData,
const char *contentTopic);
// Send a message.
// messageJson: JSON string with the following structure:
// {
// "contentTopic": "/myapp/1/chat/proto",
// "payload": "base64-encoded-payload",
// "ephemeral": false
// }
// Returns a request ID that can be used to track the message delivery.
int logosdelivery_send(void *ctx,
FFICallBack callback,
void *userData,
const char *messageJson);
// --- Reliable Channels API (stable surface) ---
// Create a reliable channel. Returns the channel id.
int logosdelivery_channel_create(void *ctx,
FFICallBack callback,
void *userData,
const char *channelId,
const char *contentTopic,
const char *senderId);
// Send a message on a reliable channel.
// messageJson: { "payload": "base64-encoded-payload", "ephemeral": false }
// Returns a request ID that can be used to track delivery.
int logosdelivery_channel_send(void *ctx,
FFICallBack callback,
void *userData,
const char *channelId,
const char *messageJson);
// Close a reliable channel: stops its SDS loops; persisted state survives, so
// re-creating the channel restores it.
int logosdelivery_channel_close(void *ctx,
FFICallBack callback,
void *userData,
const char *channelId);
// Channel lifecycle events are delivered to listeners registered via
// logosdelivery_add_event_listener: "onChannelMessageReceived" (payload
// base64-encoded), "onChannelMessageSent", "onChannelMessageError".
// Registers a callback invoked whenever the named event fires. Listeners are
// per event name; register once per event you care about. Returns the listener
// id (> 0) to pass to logosdelivery_remove_event_listener, or 0 if callback is
// NULL.
// It is crucial that the passed callback is fast, non-blocking and potentially thread-safe.
uint64_t logosdelivery_add_event_listener(void *ctx,
const char *eventName,
FFICallBack callback,
void *userData);
// Unregisters the listener with the given id. Returns RET_OK when a listener
// was removed, RET_ERR otherwise.
int logosdelivery_remove_event_listener(void *ctx,
uint64_t listenerId);
// Retrieves the list of available node info IDs.
int logosdelivery_get_available_node_info_ids(void *ctx,
FFICallBack callback,
void *userData);
// Given a node info ID, retrieves the corresponding info.
int logosdelivery_get_node_info(void *ctx,
FFICallBack callback,
void *userData,
const char *nodeInfoId);
// Retrieves the list of available configurations.
int logosdelivery_get_available_configs(void *ctx,
FFICallBack callback,
void *userData);
// NOTE: the low-level kernel API (waku_*) lives in the separate, advanced
// header liblogosdelivery_kernel.h. It is intentionally not declared here so
// this header only promises the stable Messaging / Reliable Channels surface.
#ifdef __cplusplus
}
#endif
#endif /* __liblogosdelivery__ */

View File

@ -1,241 +0,0 @@
// liblogosdelivery_kernel.h — Kernel / advanced API (low-level, per-protocol).
//
// ⚠️ USE AT YOUR OWN RISK — UNSUPPORTED, UNSTABLE SURFACE.
//
// These `waku_*` functions are the low-level kernel API. They are NOT part of
// the stable, supported Messaging / Reliable Channels surface declared in
// liblogosdelivery.h. They expose per-protocol internals (relay, filter,
// lightpush, store, discovery, peer management) and may change or be removed
// at ANY time, without notice or a deprecation cycle.
//
// Including this header is a deliberate opt-in into the advanced tier. If you
// only need messaging, include liblogosdelivery.h and nothing here.
//
// See https://github.com/logos-messaging/logos-delivery/issues/3851 for the
// tiering rationale.
#pragma once
#ifndef __liblogosdelivery_kernel__
#define __liblogosdelivery_kernel__
// Shared FFICallBack typedef and RET_* return codes live in the stable header.
#include "liblogosdelivery.h"
#ifdef __cplusplus
extern "C"
{
#endif
// NOTE: node lifecycle (create / start / stop / destroy) is unified and lives
// only in the stable header. Use logosdelivery_create_node,
// logosdelivery_start_node, logosdelivery_stop_node and logosdelivery_destroy
// (declared in liblogosdelivery.h, included above) regardless of whether you
// drive the node through the messaging surface or this kernel API.
int waku_version(void *ctx,
FFICallBack callback,
void *userData);
// NOTE: event listeners are registered via logosdelivery_add_event_listener
// (declared above) which the waku_* API shares.
int waku_content_topic(void *ctx,
FFICallBack callback,
void *userData,
const char *appName,
unsigned int appVersion,
const char *contentTopicName,
const char *encoding);
int waku_pubsub_topic(void *ctx,
FFICallBack callback,
void *userData,
const char *topicName);
int waku_default_pubsub_topic(void *ctx,
FFICallBack callback,
void *userData);
int waku_relay_publish(void *ctx,
FFICallBack callback,
void *userData,
const char *pubSubTopic,
const char *jsonWakuMessage,
unsigned int timeoutMs);
int waku_lightpush_publish(void *ctx,
FFICallBack callback,
void *userData,
const char *pubSubTopic,
const char *jsonWakuMessage);
int waku_relay_subscribe(void *ctx,
FFICallBack callback,
void *userData,
const char *pubSubTopic);
int waku_relay_add_protected_shard(void *ctx,
FFICallBack callback,
void *userData,
int clusterId,
int shardId,
char *publicKey);
int waku_relay_unsubscribe(void *ctx,
FFICallBack callback,
void *userData,
const char *pubSubTopic);
int waku_filter_subscribe(void *ctx,
FFICallBack callback,
void *userData,
const char *pubSubTopic,
const char *contentTopics);
int waku_filter_unsubscribe(void *ctx,
FFICallBack callback,
void *userData,
const char *pubSubTopic,
const char *contentTopics);
int waku_filter_unsubscribe_all(void *ctx,
FFICallBack callback,
void *userData);
int waku_relay_get_num_connected_peers(void *ctx,
FFICallBack callback,
void *userData,
const char *pubSubTopic);
int waku_relay_get_connected_peers(void *ctx,
FFICallBack callback,
void *userData,
const char *pubSubTopic);
int waku_relay_get_num_peers_in_mesh(void *ctx,
FFICallBack callback,
void *userData,
const char *pubSubTopic);
int waku_relay_get_peers_in_mesh(void *ctx,
FFICallBack callback,
void *userData,
const char *pubSubTopic);
int waku_store_query(void *ctx,
FFICallBack callback,
void *userData,
const char *jsonQuery,
const char *peerAddr,
int timeoutMs);
int waku_connect(void *ctx,
FFICallBack callback,
void *userData,
const char *peerMultiAddr,
unsigned int timeoutMs);
int waku_disconnect_peer_by_id(void *ctx,
FFICallBack callback,
void *userData,
const char *peerId);
int waku_disconnect_all_peers(void *ctx,
FFICallBack callback,
void *userData);
int waku_dial_peer(void *ctx,
FFICallBack callback,
void *userData,
const char *peerMultiAddr,
const char *protocol,
int timeoutMs);
int waku_dial_peer_by_id(void *ctx,
FFICallBack callback,
void *userData,
const char *peerId,
const char *protocol,
int timeoutMs);
int waku_get_peerids_from_peerstore(void *ctx,
FFICallBack callback,
void *userData);
int waku_get_connected_peers_info(void *ctx,
FFICallBack callback,
void *userData);
int waku_get_peerids_by_protocol(void *ctx,
FFICallBack callback,
void *userData,
const char *protocol);
int waku_listen_addresses(void *ctx,
FFICallBack callback,
void *userData);
int waku_get_connected_peers(void *ctx,
FFICallBack callback,
void *userData);
// Returns a list of multiaddress given a url to a DNS discoverable ENR tree
// Parameters
// char* entTreeUrl: URL containing a discoverable ENR tree
// char* nameDnsServer: The nameserver to resolve the ENR tree url.
// int timeoutMs: Timeout value in milliseconds to execute the call.
int waku_dns_discovery(void *ctx,
FFICallBack callback,
void *userData,
const char *entTreeUrl,
const char *nameDnsServer,
int timeoutMs);
// Updates the bootnode list used for discovering new peers via DiscoveryV5
// bootnodes - JSON array containing the bootnode ENRs i.e. `["enr:...", "enr:..."]`
int waku_discv5_update_bootnodes(void *ctx,
FFICallBack callback,
void *userData,
char *bootnodes);
int waku_start_discv5(void *ctx,
FFICallBack callback,
void *userData);
int waku_stop_discv5(void *ctx,
FFICallBack callback,
void *userData);
// Retrieves the ENR information
int waku_get_my_enr(void *ctx,
FFICallBack callback,
void *userData);
int waku_get_my_peerid(void *ctx,
FFICallBack callback,
void *userData);
int waku_get_metrics(void *ctx,
FFICallBack callback,
void *userData);
int waku_peer_exchange_request(void *ctx,
FFICallBack callback,
void *userData,
int numPeers);
int waku_ping_peer(void *ctx,
FFICallBack callback,
void *userData,
const char *peerAddr,
int timeoutMs);
int waku_is_online(void *ctx,
FFICallBack callback,
void *userData);
#ifdef __cplusplus
}
#endif
#endif /* __liblogosdelivery_kernel__ */

View File

@ -512,6 +512,15 @@ task liblogosdeliveryGenBindingsRust, "Emit the Rust bindings for liblogosdelive
"-d:ffiSrcPath=library/liblogosdelivery.nim " & getMyCPU() & getNimParams() &
" --compileOnly library/liblogosdelivery.nim"
task liblogosdeliveryGenBindingsC, "Emit the C header for liblogosdelivery":
# Replaces the hand-written liblogosdelivery.h; params ride as CBOR blobs
# (the library's default ABI), so the emitted nim_ffi_cbor.h helpers marshal
# them. --compileOnly for the same reason as the Rust task.
exec "nim c --threads:on --mm:refc --skipParentCfg:off -d:discv5_protocol_id=d5waku " &
"-d:ffiGenBindings -d:targetLang=c -d:ffiOutputDir=library/c_bindings " &
"-d:ffiSrcPath=library/liblogosdelivery.nim " & getMyCPU() & getNimParams() &
" --compileOnly library/liblogosdelivery.nim"
### Formatting tasks
task nphchanges, "Run nph on .nim/.nims/.nimble files changed on this branch/PR":

View File

@ -139,8 +139,9 @@ pkgs.stdenv.mkDerivation {
mkdir -p $out/lib $out/include
cp build/liblogosdelivery.${libExt} $out/lib/ 2>/dev/null || true
cp build/liblogosdelivery.a $out/lib/ 2>/dev/null || true
cp library/liblogosdelivery.h $out/include/ 2>/dev/null || true
cp library/liblogosdelivery_kernel.h $out/include/ 2>/dev/null || true
cp library/c_bindings/logosdelivery.h $out/include/ 2>/dev/null || true
cp library/c_bindings/nim_ffi_cbor.h $out/include/ 2>/dev/null || true
cp library/c_bindings/nim_ffi_prelude.h $out/include/ 2>/dev/null || true
runHook postInstall
'';