diff --git a/examples/cbindings/README.md b/examples/cbindings/README.md new file mode 100644 index 000000000..5465cf512 --- /dev/null +++ b/examples/cbindings/README.md @@ -0,0 +1,18 @@ +## App description +This is a very simple example that shows how to invoke libwaku functions from a C program. + +## Build +1. Open terminal +2. cd to nwaku root folder +3. make cwaku_example -j8 + +This will create libwaku.so and cwaku_example binary within the build folder. + +## Run +1. Open terminal +2. cd to nwaku root folder +3. export LD_LIBRARY_PATH=build +4. `./build/cwaku_example --host=0.0.0.0 --port=60001` + +Use `./build/cwaku_example --help` to see some other options. + diff --git a/examples/cbindings/waku_example.c b/examples/cbindings/waku_example.c index bbb76c862..b80b9af8f 100644 --- a/examples/cbindings/waku_example.c +++ b/examples/cbindings/waku_example.c @@ -14,7 +14,6 @@ #include "base64.h" #include "../../library/libwaku.h" - // Shared synchronization variables pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; @@ -29,7 +28,6 @@ void waitForCallback() { pthread_mutex_unlock(&mutex); } - #define WAKU_CALL(call) \ do { \ int ret = call; \ @@ -107,6 +105,13 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { return 0; } +void signal_cond() { + pthread_mutex_lock(&mutex); + callback_executed = 1; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); +} + static struct argp argp = { options, parse_opt, args_doc, doc, 0, 0, 0 }; void event_handler(int callerRet, const char* msg, size_t len, void* userData) { @@ -118,10 +123,7 @@ void event_handler(int callerRet, const char* msg, size_t len, void* userData) { printf("Receiving event: %s\n", msg); } - pthread_mutex_lock(&mutex); - callback_executed = 1; - pthread_cond_signal(&cond); - pthread_mutex_unlock(&mutex); + signal_cond(); } void on_event_received(int callerRet, const char* msg, size_t len, void* userData) { @@ -142,6 +144,7 @@ void handle_content_topic(int callerRet, const char* msg, size_t len, void* user contentTopic = malloc(len * sizeof(char) + 1); strcpy(contentTopic, msg); + signal_cond(); } char* publishResponse = NULL; @@ -158,33 +161,30 @@ void handle_publish_ok(int callerRet, const char* msg, size_t len, void* userDat #define MAX_MSG_SIZE 65535 -void publish_message(char* pubsubTopic, const char* msg) { +void publish_message(const char* msg) { char jsonWakuMsg[MAX_MSG_SIZE]; char *msgPayload = b64_encode(msg, strlen(msg)); - WAKU_CALL( waku_content_topic(RET_OK, + WAKU_CALL( waku_content_topic(ctx, "appName", 1, "contentTopicName", "encoding", handle_content_topic, userData) ); - snprintf(jsonWakuMsg, MAX_MSG_SIZE, - "{\"payload\":\"%s\",\"content_topic\":\"%s\"}", + "{\"payload\":\"%s\",\"contentTopic\":\"%s\"}", msgPayload, contentTopic); free(msgPayload); - WAKU_CALL( waku_relay_publish(&ctx, - pubsubTopic, + WAKU_CALL( waku_relay_publish(ctx, + "/waku/2/rs/16/32", jsonWakuMsg, 10000 /*timeout ms*/, event_handler, userData) ); - - printf("waku relay response [%s]\n", publishResponse); } void show_help_and_exit() { @@ -194,20 +194,12 @@ void show_help_and_exit() { void print_default_pubsub_topic(int callerRet, const char* msg, size_t len, void* userData) { printf("Default pubsub topic: %s\n", msg); - - pthread_mutex_lock(&mutex); - callback_executed = 1; - pthread_cond_signal(&cond); - pthread_mutex_unlock(&mutex); + signal_cond(); } void print_waku_version(int callerRet, const char* msg, size_t len, void* userData) { printf("Git Version: %s\n", msg); - - pthread_mutex_lock(&mutex); - callback_executed = 1; - pthread_cond_signal(&cond); - pthread_mutex_unlock(&mutex); + signal_cond(); } // Beginning of UI program logic @@ -236,9 +228,6 @@ void handle_user_input() { return; } - int c; - while ( (c = getchar()) != '\n' && c != EOF ) { } - switch (atoi(cmd)) { case SUBSCRIBE_TOPIC_MENU: @@ -247,7 +236,7 @@ void handle_user_input() { char pubsubTopic[128]; scanf("%127s", pubsubTopic); - WAKU_CALL( waku_relay_subscribe(&ctx, + WAKU_CALL( waku_relay_subscribe(ctx, pubsubTopic, event_handler, userData) ); @@ -262,21 +251,17 @@ void handle_user_input() { printf("e.g.: /ip4/127.0.0.1/tcp/60001/p2p/16Uiu2HAmVFXtAfSj4EiR7mL2KvL4EE2wztuQgUSBoj2Jx2KeXFLN\n"); char peerAddr[512]; scanf("%511s", peerAddr); - WAKU_CALL(waku_connect(&ctx, peerAddr, 10000 /* timeoutMs */, event_handler, userData)); + WAKU_CALL(waku_connect(ctx, peerAddr, 10000 /* timeoutMs */, event_handler, userData)); show_main_menu(); break; case PUBLISH_MESSAGE_MENU: { - printf("Indicate the Pubsubtopic:\n"); - char pubsubTopic[128]; - scanf("%127s", pubsubTopic); - - printf("Type the message tp publish:\n"); + printf("Type the message to publish:\n"); char msg[1024]; scanf("%1023s", msg); - publish_message(pubsubTopic, msg); + publish_message(msg); show_main_menu(); } @@ -311,24 +296,24 @@ int main(int argc, char** argv) { char jsonConfig[5000]; snprintf(jsonConfig, 5000, "{ \ + \"clusterId\": 16, \ + \"shards\": [ 1, 32, 64, 128, 256 ], \ \"listenAddress\": \"%s\", \ \"tcpPort\": %d, \ - \"nodekey\": \"%s\", \ \"relay\": %s, \ \"store\": %s, \ \"storeMessageDbUrl\": \"%s\", \ \"storeMessageRetentionPolicy\": \"%s\", \ \"storeMaxNumDbConnections\": %d , \ - \"logLevel\": \"DEBUG\", \ + \"logLevel\": \"FATAL\", \ \"discv5Discovery\": true, \ \"discv5BootstrapNodes\": \ [\"enr:-QESuEB4Dchgjn7gfAvwB00CxTA-nGiyk-aALI-H4dYSZD3rUk7bZHmP8d2U6xDiQ2vZffpo45Jp7zKNdnwDUx6g4o6XAYJpZIJ2NIJpcIRA4VDAim11bHRpYWRkcnO4XAArNiZub2RlLTAxLmRvLWFtczMud2FrdS5zYW5kYm94LnN0YXR1cy5pbQZ2XwAtNiZub2RlLTAxLmRvLWFtczMud2FrdS5zYW5kYm94LnN0YXR1cy5pbQYfQN4DgnJzkwABCAAAAAEAAgADAAQABQAGAAeJc2VjcDI1NmsxoQOvD3S3jUNICsrOILlmhENiWAMmMVlAl6-Q8wRB7hidY4N0Y3CCdl-DdWRwgiMohXdha3UyDw\", \"enr:-QEkuEBIkb8q8_mrorHndoXH9t5N6ZfD-jehQCrYeoJDPHqT0l0wyaONa2-piRQsi3oVKAzDShDVeoQhy0uwN1xbZfPZAYJpZIJ2NIJpcIQiQlleim11bHRpYWRkcnO4bgA0Ni9ub2RlLTAxLmdjLXVzLWNlbnRyYWwxLWEud2FrdS5zYW5kYm94LnN0YXR1cy5pbQZ2XwA2Ni9ub2RlLTAxLmdjLXVzLWNlbnRyYWwxLWEud2FrdS5zYW5kYm94LnN0YXR1cy5pbQYfQN4DgnJzkwABCAAAAAEAAgADAAQABQAGAAeJc2VjcDI1NmsxoQKnGt-GSgqPSf3IAPM7bFgTlpczpMZZLF3geeoNNsxzSoN0Y3CCdl-DdWRwgiMohXdha3UyDw\"], \ \"discv5UdpPort\": 9999, \ - \"dnsDiscoveryUrl\": \"enrtree://AOGYWMBYOUIMOENHXCHILPKY3ZRFEULMFI4DOM442QSZ73TT2A7VI@test.waku.nodes.status.im\", \ + \"dnsDiscoveryUrl\": \"enrtree://AMOJVZX4V6EXP7NTJPMAYJYST2QP6AJXYW76IU6VGJS7UVSNDYZG4@boot.prod.status.nodes.status.im\", \ \"dnsDiscoveryNameServers\": [\"8.8.8.8\", \"1.0.0.1\"] \ }", cfgNode.host, cfgNode.port, - cfgNode.key, cfgNode.relay ? "true":"false", cfgNode.store ? "true":"false", cfgNode.storeDbUrl, @@ -351,14 +336,6 @@ int main(int argc, char** argv) { WAKU_CALL( waku_listen_addresses(ctx, event_handler, userData) ); - printf("Establishing connection with: %s\n", cfgNode.peers); - - WAKU_CALL( waku_connect(ctx, - cfgNode.peers, - 10000 /* timeoutMs */, - event_handler, - userData) ); - WAKU_CALL( waku_relay_subscribe(ctx, "/waku/2/rs/0/0", event_handler, diff --git a/examples/cpp/README.md b/examples/cpp/README.md new file mode 100644 index 000000000..fa8d246e0 --- /dev/null +++ b/examples/cpp/README.md @@ -0,0 +1,18 @@ +## App description +This is a very simple example that shows how to invoke libwaku functions from a C++ program. + +## Build +1. Open terminal +2. cd to nwaku root folder +3. make cppwaku_example -j8 + +This will create libwaku.so and cppwaku_example binary within the build folder. + +## Run +1. Open terminal +2. cd to nwaku root folder +3. export LD_LIBRARY_PATH=build +4. `./build/cppwaku_example --host=0.0.0.0 --port=60001` + +Use `./build/cppwaku_example --help` to see some other options. + diff --git a/examples/cpp/waku.cpp b/examples/cpp/waku.cpp index 4b601c492..c47877d02 100644 --- a/examples/cpp/waku.cpp +++ b/examples/cpp/waku.cpp @@ -16,12 +16,34 @@ #include "base64.h" #include "../../library/libwaku.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 { @@ -78,6 +100,24 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { return 0; } +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 +auto cify(F&& f) { + static F fn = std::forward(f); + return [](int callerRet, const char* msg, size_t len, void* userData) { + signal_cond(); + return fn(msg, len); + }; +} + static struct argp argp = { options, parse_opt, args_doc, doc, 0, 0, 0 }; // Beginning of UI program logic @@ -98,7 +138,7 @@ void show_main_menu() { printf("\t3.) Publish a message\n"); } -void handle_user_input() { +void handle_user_input(void* ctx) { char cmd[1024]; memset(cmd, 0, 1024); int numRead = read(0, cmd, 1024); @@ -106,9 +146,6 @@ void handle_user_input() { return; } - int c; - while ( (c = getchar()) != '\n' && c != EOF ) { } - switch (atoi(cmd)) { case SUBSCRIBE_TOPIC_MENU: @@ -116,10 +153,14 @@ void handle_user_input() { printf("Indicate the Pubsubtopic to subscribe:\n"); char pubsubTopic[128]; scanf("%127s", pubsubTopic); - // if (!waku_relay_subscribe(pubsubTopic, &mResp)) { - // printf("Error subscribing to PubsubTopic: %s\n", mResp->data); - // } - // printf("Waku Relay subscription response: %s\n", mResp->data); + + WAKU_CALL( waku_relay_subscribe(ctx, + pubsubTopic, + cify([&](const char* msg, size_t len) { + event_handler(msg, len); + }), + nullptr) ); + printf("The subscription went well\n"); show_main_menu(); } @@ -130,41 +171,51 @@ void handle_user_input() { printf("e.g.: /ip4/127.0.0.1/tcp/60001/p2p/16Uiu2HAmVFXtAfSj4EiR7mL2KvL4EE2wztuQgUSBoj2Jx2KeXFLN\n"); char peerAddr[512]; scanf("%511s", peerAddr); - // if (!waku_connect(peerAddr, 10000 /* timeoutMs */, &mResp)) { - // printf("Couldn't connect to the remote peer: %s\n", mResp->data); - // } + WAKU_CALL( waku_connect(ctx, + peerAddr, + 10000 /* timeoutMs */, + cify([&](const char* msg, size_t len) { + event_handler(msg, len); + }), + nullptr)); show_main_menu(); break; case PUBLISH_MESSAGE_MENU: { - printf("Indicate the Pubsubtopic:\n"); - char pubsubTopic[128]; - scanf("%127s", pubsubTopic); - - printf("Type the message tp publish:\n"); + printf("Type the message to publish:\n"); char msg[1024]; scanf("%1023s", msg); - char jsonWakuMsg[1024]; + char jsonWakuMsg[2048]; std::vector msgPayload; b64_encode(msg, strlen(msg), msgPayload); - // waku_content_topic("appName", - // 1, - // "contentTopicName", - // "encoding", - // &mResp); + std::string contentTopic; + waku_content_topic(ctx, + "appName", + 1, + "contentTopicName", + "encoding", + cify([&contentTopic](const char* msg, size_t len) { + contentTopic = msg; + }), + nullptr); - // snprintf(jsonWakuMsg, - // 1024, - // "{\"payload\":\"%s\",\"content_topic\":\"%s\"}", - // msgPayload, mResp->data); + snprintf(jsonWakuMsg, + 2048, + "{\"payload\":\"%s\",\"contentTopic\":\"%s\"}", + msgPayload.data(), contentTopic.c_str()); - // free(msgPayload); + WAKU_CALL( waku_relay_publish(ctx, + "/waku/2/rs/16/32", + jsonWakuMsg, + 10000 /*timeout ms*/, + cify([&](const char* msg, size_t len) { + event_handler(msg, len); + }), + nullptr) ); - // waku_relay_publish(pubsubTopic, jsonWakuMsg, 10000 /*timeout ms*/, &mResp); - // printf("waku relay response [%s]\n", mResp->data); show_main_menu(); } break; @@ -181,23 +232,6 @@ void show_help_and_exit() { exit(1); } -void event_handler(const char* msg, size_t len) { - printf("Receiving message %s\n", msg); -} - -void handle_error(const char* msg, size_t len) { - printf("Error: %s\n", msg); - exit(1); -} - -template -auto cify(F&& f) { - static F fn = std::forward(f); - return [](const char* msg, size_t len) { - return fn(msg, len); - }; -} - int main(int argc, char** argv) { struct ConfigNode cfgNode; // default values @@ -212,60 +246,86 @@ int main(int argc, char** argv) { show_help_and_exit(); } - char jsonConfig[1024]; - snprintf(jsonConfig, 1024, "{ \ + char jsonConfig[2048]; + snprintf(jsonConfig, 2048, "{ \ \"host\": \"%s\", \ \"port\": %d, \ - \"key\": \"%s\", \ - \"relay\": %s, \ - \"logLevel\": \"DEBUG\" \ + \"relay\": true, \ + \"clusterId\": 16, \ + \"shards\": [ 1, 32, 64, 128, 256 ], \ + \"logLevel\": \"FATAL\", \ + \"discv5Discovery\": true, \ + \"discv5BootstrapNodes\": \ + [\"enr:-QESuEB4Dchgjn7gfAvwB00CxTA-nGiyk-aALI-H4dYSZD3rUk7bZHmP8d2U6xDiQ2vZffpo45Jp7zKNdnwDUx6g4o6XAYJpZIJ2NIJpcIRA4VDAim11bHRpYWRkcnO4XAArNiZub2RlLTAxLmRvLWFtczMud2FrdS5zYW5kYm94LnN0YXR1cy5pbQZ2XwAtNiZub2RlLTAxLmRvLWFtczMud2FrdS5zYW5kYm94LnN0YXR1cy5pbQYfQN4DgnJzkwABCAAAAAEAAgADAAQABQAGAAeJc2VjcDI1NmsxoQOvD3S3jUNICsrOILlmhENiWAMmMVlAl6-Q8wRB7hidY4N0Y3CCdl-DdWRwgiMohXdha3UyDw\", \"enr:-QEkuEBIkb8q8_mrorHndoXH9t5N6ZfD-jehQCrYeoJDPHqT0l0wyaONa2-piRQsi3oVKAzDShDVeoQhy0uwN1xbZfPZAYJpZIJ2NIJpcIQiQlleim11bHRpYWRkcnO4bgA0Ni9ub2RlLTAxLmdjLXVzLWNlbnRyYWwxLWEud2FrdS5zYW5kYm94LnN0YXR1cy5pbQZ2XwA2Ni9ub2RlLTAxLmdjLXVzLWNlbnRyYWwxLWEud2FrdS5zYW5kYm94LnN0YXR1cy5pbQYfQN4DgnJzkwABCAAAAAEAAgADAAQABQAGAAeJc2VjcDI1NmsxoQKnGt-GSgqPSf3IAPM7bFgTlpczpMZZLF3geeoNNsxzSoN0Y3CCdl-DdWRwgiMohXdha3UyDw\"], \ + \"discv5UdpPort\": 9999, \ + \"dnsDiscoveryUrl\": \"enrtree://AMOJVZX4V6EXP7NTJPMAYJYST2QP6AJXYW76IU6VGJS7UVSNDYZG4@boot.prod.status.nodes.status.im\", \ + \"dnsDiscoveryNameServers\": [\"8.8.8.8\", \"1.0.0.1\"] \ }", cfgNode.host, - cfgNode.port, - cfgNode.key, - cfgNode.relay ? "true":"false"); + cfgNode.port); - WAKU_CALL(waku_new(jsonConfig, cify([](const char* msg, size_t len) { - std::cout << "Error: " << msg << std::endl; - exit(1); - }))); + void* ctx = + waku_new(jsonConfig, + cify([](const char* msg, size_t len) { + std::cout << "waku_new 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(cify([&defaultPubsubTopic](const char* msg, size_t len) { - defaultPubsubTopic = msg; - }))); + 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(cify([&](const char* msg, size_t len) { - std::cout << "Git Version: " << msg << 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("example", cify([&](const char* msg, size_t len) { - pubsubTopic = msg; - }))); + WAKU_CALL(waku_pubsub_topic(ctx, + "example", + cify([&](const char* msg, size_t len) { + pubsubTopic = msg; + }), + nullptr)); std::cout << "Custom pubsub topic: " << pubsubTopic << std::endl; - waku_set_event_callback(event_handler); - waku_start(); + waku_set_event_callback(ctx, + cify([&](const char* msg, size_t len) { + event_handler(msg, len); + }), + nullptr); - WAKU_CALL( waku_connect(cfgNode.peers, - 10000 /* timeoutMs */, - handle_error) ); + WAKU_CALL( waku_start(ctx, + cify([&](const char* msg, size_t len) { + event_handler(msg, len); + }), + nullptr)); - WAKU_CALL( waku_relay_subscribe(defaultPubsubTopic.c_str(), - handle_error) ); - - std::cout << "Establishing connection with: " << cfgNode.peers << std::endl; - WAKU_CALL(waku_connect(cfgNode.peers, 10000 /* timeoutMs */, handle_error)); + WAKU_CALL( waku_relay_subscribe(ctx, + defaultPubsubTopic.c_str(), + cify([&](const char* msg, size_t len) { + event_handler(msg, len); + }), + nullptr) ); show_main_menu(); while(1) { - handle_user_input(); + handle_user_input(ctx); } } diff --git a/library/libwaku.nim b/library/libwaku.nim index 23600aca4..050395bc5 100644 --- a/library/libwaku.nim +++ b/library/libwaku.nim @@ -42,7 +42,8 @@ import template checkLibwakuParams*( ctx: ptr WakuContext, callback: WakuCallBack, userData: pointer ) = - ctx[].userData = userData + if not isNil(ctx): + ctx[].userData = userData if isNil(callback): return RET_MISSING_CALLBACK