Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add forwarder demo #1669

Merged
merged 2 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions demo/pubsub_forwarder/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
# file was obtained (LICENSE.txt). A copy of the license may also be
# found online at https://opensource.org/licenses/MIT.

cmake_minimum_required(VERSION 3.10)
project(pubsub_forwarder C)

# Find the nng library
find_package(nng REQUIRED)

# Add the executable target
add_executable(pubsub_forwarder pubsub_forwarder.c)

target_compile_options(pubsub_forwarder PRIVATE -Wall -Wextra -Wpedantic -Werror -O2)

# Link against the nng library
target_link_libraries(pubsub_forwarder PRIVATE nng)
62 changes: 62 additions & 0 deletions demo/pubsub_forwarder/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
= PubSub Forwarder

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent documentation for this addition! Thank you very much!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I tried to follow the other demos as an example.

This is a trivial example of a forwarder/proxy for the pub/sub pattern.

The concept is as follows: the forwarder will listen for connections on
both a front-end port and a back-end port. The front-end will act as a
subscriber so that publishers can publish to it. The back-end will act
as a publisher so that subscribers can subscribe to it. The front-end
then forwards to the back end.

== Compiling

CMake with ninja-build is simplest:

[source, bash]
----
cmake -GNinja -B build
cd build
ninja
----

Or if you prefer a traditional approach,
the following is an example typical of UNIX and similar systems like
Linux and macOS may appeal:

[source, bash]
----
export CPPFLAGS="-I /usr/local/include"
export LDFLAGS="-L /usr/local/lib -lnng"
export CC="cc"
${CC} ${CPPFLAGS} pubsub_forwarder.c -o pubsub_forwarder ${LDFLAGS}
----

== Running

An example setup for running this example would involve the following:

. Step 1: Run this example binary (in the background or a terminal, etc)
. Step 2: In a new terminal, run the following

[source, bash]
----
nngcat --sub --dial "tcp://localhost:3328" --quoted
----

. Step 3: In a second terminal, run the same command again to give us two subscribers

[source, bash]
----
nngcat --sub --dial "tcp://localhost:3328" --quoted
----


. In a third terminal, run the following to publish a counter

[source, bash]
----
for n in $(seq 0 99); do nngcat --pub --dial "tcp://localhost:3327" --data "$n"; done
----



86 changes: 86 additions & 0 deletions demo/pubsub_forwarder/pubsub_forwarder.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//

//
// Forwarder example based on https://github.com/C-o-r-E/nng_pubsub_proxy
//
// This example shows how to use raw sockets to set up a forwarder or proxy for pub/sub.
//
// An example setup for running this example would involve the following:
//
// - Run this example binary (in the background or a terminal, etc)
// - In a new terminal, run `nngcat --sub --dial "tcp://localhost:3328" --quoted`
// - In a second terminal, run `nngcat --sub --dial "tcp://localhost:3328" --quoted`
// - In a third terminal, run `for n in $(seq 0 99); do nngcat --pub --dial "tcp://localhost:3327" --data "$n"; done`
//
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

#include <nng/nng.h>
#include <nng/protocol/pubsub0/sub.h>
#include <nng/protocol/pubsub0/pub.h>

#define PROXY_FRONT_URL "tcp://localhost:3327"
#define PROXY_BACK_URL "tcp://localhost:3328"

void panic_on_error(int should_panic, const char* format, ...)
{
if (should_panic)
Copy link
Contributor

@gdamore gdamore Jul 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use clang-format using the .clang-format I've supplied, you'll see that for if statements like this the { should be on the same line.

Again, this is a very minor nit, but I'd be even happier with this if you could make it match the existing style.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do.

{
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
exit(EXIT_FAILURE);
}
}

int main()
{
nng_socket sock_front_end = NNG_SOCKET_INITIALIZER;
nng_socket sock_back_end = NNG_SOCKET_INITIALIZER;
int ret = 0;

/*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a super silly nit, but I don't use these style of block comments anywhere else in this code base.

If you're willing, I'd appreciate if you could convert them to C++ style just for consistency.

I won't hold the PR up for this, because at least on the face of it, it is very nice and I'd like to see it land before the next release, but I will wait to give you a chance to respond (and possibly update) before I merge.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem. Will change them to match

First we need some nng sockets. Not to be confused with network sockets
*/
ret = nng_sub0_open_raw(&sock_front_end);
panic_on_error(ret, "Failed to open front end socket\n");

ret = nng_pub0_open_raw(&sock_back_end);
panic_on_error(ret, "Failed to open back end socket\n");

/*
Now we need to set up a listener for each socket so that they have addresses
*/

nng_listener front_ls = NNG_LISTENER_INITIALIZER;
nng_listener back_ls = NNG_LISTENER_INITIALIZER;

ret = nng_listener_create(&front_ls, sock_front_end, PROXY_FRONT_URL);
panic_on_error(ret, "Failed to create front listener\n");

ret = nng_listener_create(&back_ls, sock_back_end, PROXY_BACK_URL);
panic_on_error(ret, "Failed to create back listener\n");

ret = nng_listener_start(front_ls, 0);
panic_on_error(ret, "Failed to start front listener\n");

ret = nng_listener_start(back_ls, 0);
panic_on_error(ret, "Failed to start back listener\n");

/*
Finally let nng do the forwarding/proxying
*/

ret = nng_device(sock_front_end, sock_back_end);
panic_on_error(ret, "nng_device returned %d: %s\n", ret, nng_strerror(ret));

printf("done");
return 0;
}
Loading