Fabiana Cecin 90fa5fa91f
feat: improve config v3 (#4015)
* remove --mode from the CLI
* move WakuMode to the messaging layer
* expose store backend (db url, max connections) and a remote store node on the messaging surface
* wakunode2 with no flags now runs as a full service node (store still opt-in)
* add rateLimitMessagesPerEpoch
* channel rate-limiting auto-enables if epochPeriodSec or messagesPerEpoch is set
* fix JSON conf parser to be generic (works over all config types)
* messaging config = mode + preset + messagingOverrides + channelsOverrides
* add full messaging plus selective kernel config options to MessagingClientConf
* mode (Core/Edge) expands to kernel protocol flags in the messaging layer
* create_node parses the messaging config, drops the flat WakuNodeConf JSON entrypoint
* wire channelsOverrides (segmentation/SDS/rate-limit) into channel creation
* fix liblogosdelivery.h comments and README for the new config shape
* messaging conf tests: switch names, reject-unknown, set-twice, field->kernel
* add kernel log-level, log-format, nodekey to the messaging surface
* Port 0 (ephemeral) default for messaging entry points
* KernelConf alias for WakuNodeConf
* rewrite the FFI examples to the new config shape
* C/C++ examples use preset status.prod
* drop operator-only confs from the examples
* remove duplicate tests & misc test fixes
* Delete p2pReliability from Kernel (Waku) resolver and config (keep preset definition)
* Delete NodeConfig API (deprecation completed by p2pReliability removal from kernel)
* Rename test_messaging_conf.nim to test_conf.nim (tests Logos Delivery config in general)
* Rename messaging_conf_json.nim to logos_delivery_conf_json.nim
* Add logos_delivery_conf.nim (defines LogosDeliveryConf aggregate)
* misc docs/comments cleanups
2026-07-09 12:21:41 -03:00

312 lines
9.2 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>
#include <vector>
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "base64.h"
#include "../../library/liblogosdelivery_kernel.h"
// Shared synchronization variables
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int callback_executed = 0;
void waitForCallback()
{
pthread_mutex_lock(&mutex);
while (!callback_executed)
{
pthread_cond_wait(&cond, &mutex);
}
callback_executed = 0;
pthread_mutex_unlock(&mutex);
}
void signal_cond()
{
pthread_mutex_lock(&mutex);
callback_executed = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
#define WAKU_CALL(call) \
do \
{ \
int ret = call; \
if (ret != 0) \
{ \
std::cout << "Failed the call to: " << #call << ". Code: " << ret << "\n"; \
} \
waitForCallback(); \
} while (0)
struct ConfigNode
{
char host[128];
int port;
char key[128];
int relay;
char peers[2048];
};
// Arguments parsing. Uses POSIX getopt so the example builds on glibc and on
// macOS/BSD alike (argp is a GNU libc extension not available everywhere).
static void parse_args(int argc, char **argv, struct ConfigNode *cfgNode)
{
int opt;
while ((opt = getopt(argc, argv, "h:p:k:r:a:")) != -1)
{
switch (opt)
{
case 'h':
snprintf(cfgNode->host, 128, "%s", optarg);
break;
case 'p':
cfgNode->port = atoi(optarg);
break;
case 'k':
snprintf(cfgNode->key, 128, "%s", optarg);
break;
case 'r':
cfgNode->relay = atoi(optarg);
break;
case 'a':
snprintf(cfgNode->peers, 2048, "%s", optarg);
break;
default:
printf("Wrong parameters\n");
exit(1);
}
}
}
void event_handler(const char *msg, size_t len)
{
printf("Receiving event: %s\n", msg);
}
void handle_error(const char *msg, size_t len)
{
printf("handle_error: %s\n", msg);
exit(1);
}
template <class F>
auto cify(F &&f)
{
static F fn = std::forward<F>(f);
return [](int callerRet, const char *msg, size_t len, void *userData)
{
signal_cond();
return fn(msg, len);
};
}
// Beginning of UI program logic
enum PROGRAM_STATE
{
MAIN_MENU,
SUBSCRIBE_TOPIC_MENU,
CONNECT_TO_OTHER_NODE_MENU,
PUBLISH_MESSAGE_MENU
};
enum PROGRAM_STATE current_state = MAIN_MENU;
void show_main_menu()
{
printf("\nPlease, select an option:\n");
printf("\t1.) Subscribe to topic\n");
printf("\t2.) Connect to other node\n");
printf("\t3.) Publish a message\n");
}
void handle_user_input(void *ctx)
{
char cmd[1024];
memset(cmd, 0, 1024);
int numRead = read(0, cmd, 1024);
if (numRead <= 0)
{
return;
}
switch (atoi(cmd))
{
case SUBSCRIBE_TOPIC_MENU:
{
printf("Indicate the Pubsubtopic to subscribe:\n");
char pubsubTopic[128];
scanf("%127s", pubsubTopic);
WAKU_CALL(waku_relay_subscribe(ctx,
cify([&](const char *msg, size_t len)
{ event_handler(msg, len); }),
nullptr,
pubsubTopic));
printf("The subscription went well\n");
show_main_menu();
}
break;
case CONNECT_TO_OTHER_NODE_MENU:
printf("Connecting to a node. Please indicate the peer Multiaddress:\n");
printf("e.g.: /ip4/127.0.0.1/tcp/60001/p2p/16Uiu2HAmVFXtAfSj4EiR7mL2KvL4EE2wztuQgUSBoj2Jx2KeXFLN\n");
char peerAddr[512];
scanf("%511s", peerAddr);
WAKU_CALL(waku_connect(ctx,
cify([&](const char *msg, size_t len)
{ event_handler(msg, len); }),
nullptr,
peerAddr,
10000 /* timeoutMs */));
show_main_menu();
break;
case PUBLISH_MESSAGE_MENU:
{
printf("Type the message to publish:\n");
char msg[1024];
scanf("%1023s", msg);
char jsonWakuMsg[2048];
std::vector<char> msgPayload;
b64_encode(msg, strlen(msg), msgPayload);
std::string contentTopic;
waku_content_topic(ctx,
cify([&contentTopic](const char *msg, size_t len)
{ contentTopic = msg; }),
nullptr,
"appName",
1,
"contentTopicName",
"encoding");
snprintf(jsonWakuMsg,
2048,
"{\"payload\":\"%s\",\"contentTopic\":\"%s\"}",
msgPayload.data(), contentTopic.c_str());
WAKU_CALL(waku_relay_publish(ctx,
cify([&](const char *msg, size_t len)
{ event_handler(msg, len); }),
nullptr,
"/waku/2/rs/16/32",
jsonWakuMsg,
10000 /*timeout ms*/));
show_main_menu();
}
break;
case MAIN_MENU:
break;
}
}
// End of UI program logic
void show_help_and_exit()
{
printf("Wrong parameters\n");
exit(1);
}
int main(int argc, char **argv)
{
struct ConfigNode cfgNode;
// default values
snprintf(cfgNode.host, 128, "0.0.0.0");
snprintf(cfgNode.key, 128,
"364d111d729a6eb6d2e6113e163f017b5ef03a6f94c9b5b7bb1bb36fa5cb07a9");
cfgNode.port = 60000;
cfgNode.relay = 1;
parse_args(argc, argv, &cfgNode);
char jsonConfig[2048];
snprintf(jsonConfig, 2048, "{ \
\"mode\": \"Core\", \
\"preset\": \"status.prod\", \
\"messagingOverrides\": { \
\"listen-address\": \"%s\", \
\"tcp-port\": %d, \
\"log-level\": \"FATAL\", \
\"discv5-udp-port\": 9999 \
} \
}",
cfgNode.host,
cfgNode.port);
void *ctx =
logosdelivery_create_node(jsonConfig,
cify([](const char *msg, size_t len)
{ std::cout << "logosdelivery_create_node feedback: " << msg << std::endl; }),
nullptr);
waitForCallback();
// example on how to retrieve a value from the `libwaku` callback.
std::string defaultPubsubTopic;
WAKU_CALL(
waku_default_pubsub_topic(
ctx,
cify([&defaultPubsubTopic](const char *msg, size_t len)
{ defaultPubsubTopic = msg; }),
nullptr));
std::cout << "Default pubsub topic: " << defaultPubsubTopic << std::endl;
WAKU_CALL(waku_version(ctx,
cify([&](const char *msg, size_t len)
{ std::cout << "Git Version: " << msg << std::endl; }),
nullptr));
printf("Bind addr: %s:%u\n", cfgNode.host, cfgNode.port);
printf("Waku Relay enabled: %s\n", cfgNode.relay == 1 ? "YES" : "NO");
std::string pubsubTopic;
WAKU_CALL(waku_pubsub_topic(ctx,
cify([&](const char *msg, size_t len)
{ pubsubTopic = msg; }),
nullptr,
"example"));
std::cout << "Custom pubsub topic: " << pubsubTopic << std::endl;
logosdelivery_set_event_callback(ctx,
cify([&](const char *msg, size_t len)
{ event_handler(msg, len); }),
nullptr);
WAKU_CALL(logosdelivery_start_node(ctx,
cify([&](const char *msg, size_t len)
{ event_handler(msg, len); }),
nullptr));
WAKU_CALL(waku_relay_subscribe(ctx,
cify([&](const char *msg, size_t len)
{ event_handler(msg, len); }),
nullptr,
defaultPubsubTopic.c_str()));
show_main_menu();
while (1)
{
handle_user_input(ctx);
}
}