Skip to content

Commit

Permalink
Many improvements in the examples.
Browse files Browse the repository at this point in the history
  • Loading branch information
mzimbres committed Dec 2, 2022
1 parent 4ac2509 commit b9a2356
Show file tree
Hide file tree
Showing 18 changed files with 171 additions and 128 deletions.
14 changes: 10 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ write_basic_package_version_file(
COMPATIBILITY AnyNewerVersion
)

find_package(Boost 1.79 REQUIRED)
find_package(Boost 1.80 REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})

find_package(OpenSSL REQUIRED)
Expand All @@ -54,19 +54,25 @@ include_directories(include)
# Main function for the examples.
#=======================================================================

add_library(common STATIC examples/common.cpp)
add_library(common STATIC
examples/common/common.cpp
examples/common/main.cpp
examples/common/aedis.cpp
)
target_compile_features(common PUBLIC cxx_std_20)

# Executables
#=======================================================================

#add_executable(intro_sync examples/intro_sync.cpp) // Uncomment after update to Boost 1.80

add_executable(intro examples/intro.cpp)
target_link_libraries(intro common)
target_compile_features(intro PUBLIC cxx_std_20)
add_test(intro intro)

add_executable(intro_sync examples/intro_sync.cpp)
target_compile_features(intro_sync PUBLIC cxx_std_20)
add_test(intro_sync intro_sync)

add_executable(chat_room examples/chat_room.cpp)
target_compile_features(chat_room PUBLIC cxx_std_20)
target_link_libraries(chat_room common)
Expand Down
48 changes: 23 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,21 @@ Some of its distinctive features are
* Back pressure, cancellation and low latency.

In addition to that, Aedis hides most of the low-level Asio code away
from the user. For example, the coroutine below retrieves Redis hashes
from the user, which in the majority of the case will be concerned
with three library entities

* `aedis::resp3::request`: A container of Redis commands.
* `aedis::adapt()`: A function that adapts data structures to receive Redis responses.
* `aedis::connection`: A connection to the Redis server.

For example, the coroutine below reads Redis [hashes](https://redis.io/docs/data-types/hashes/)
in a `std::map` and quits the connection (see containers.cpp)

```cpp
auto hgetall(std::shared_ptr<connection> conn) -> net::awaitable<void>
{
// A request contains multiple Redis commands.
request req;
req.get_config().cancel_on_connection_lost = true;
req.push("HELLO", 3);
req.push("HGETALL", "hset-key");
req.push("QUIT");
Expand All @@ -39,11 +45,10 @@ auto hgetall(std::shared_ptr<connection> conn) -> net::awaitable<void>
}
```
The execution of `connection::async_exec` as shown above is
triggered by the `connection::async_run` member function, which is
required to be running concurrently for as long as the connection
stands. For example, the code below uses a short-lived connection to
execute the coroutine above
The execution of `connection::async_exec` as shown above must
still be triggered by the `connection::async_run` member function. For
example, the code below uses a short-lived connection to execute the
coroutine above
```cpp
net::awaitable<void> async_main()
Expand All @@ -53,7 +58,7 @@ net::awaitable<void> async_main()
// Resolves and connects (from examples/common.hpp to avoid vebosity)
co_await connect(conn, "127.0.0.1", "6379");
// Runs and executes the request.
// Runs hgetall (previous example).
co_await (conn->async_run() || hgetall(conn));
}
```
Expand All @@ -67,32 +72,25 @@ reading from the socket. The reationale behind this design is
* Support server pushes and requests in the same connection object,
concurrently.

In the following sections we will discuss with more details the main
code entities Aedis users are concerned with, namely

* `aedis::resp3::request`: A container of Redis commands.
* `aedis::adapt()`: A function that adapts data structures to receive Redis responses.
* `aedis::connection`: A connection to the Redis server.

before that however, users might find it helpful to skim over the
examples, to gain a better feeling about the library capabilities.
Before we see with more detail how connections, requests and responses
work, users might find it helpful to skim over the examples, to gain a
better feeling about the library capabilities.

* intro.cpp: The Aedis hello-world program. Sends one command to Redis and quits the connection.
* intro_tls.cpp: Same as intro.cpp but over TLS.
* intro_sync.cpp: Shows how to use the conneciton class synchronously.
* containers.cpp: Shows how to send and receive STL containers and how to use transactions.
* serialization.cpp: Shows how to serialize types using Boost.Json.
* resolve_with_sentinel.cpp: Shows how to resolve a master address using sentinels.
* subscriber.cpp: Shows how to implement pubsub with reconnection re-subscription.
* echo_server.cpp: A simple TCP echo server.
* chat_room.cpp: A command line chat built on Redis pubsub.

The next two examples uses the Aedis low-level API

* low_level_sync.cpp: Sends a ping synchronously.
* low_level_async.cpp: Sends a ping asynchronously
* low_level_sync.cpp: Sends a ping synchronously using the low-level API.
* low_level_async.cpp: Sends a ping asynchronously using the low-level API.

To avoid repetition code that is common to all examples have been
grouped in common.hpp.
grouped in common.hpp. The main function is defined in main.cpp and
used by all examples.

<a name="requests"></a>
### Requests
Expand Down Expand Up @@ -498,7 +496,7 @@ auto async_main() -> net::awaitable<void>
It is important to emphasize that Redis servers use the old
communication protocol RESP2 by default, therefore it is necessary to
send a `HELLO 3` command everytime a connection is established.
Another common scenarios for reconnection is, for example, a failover
Another common scenario for reconnection is, for example, a failover
with sentinels, covered in `resolve_with_sentinel.cpp` example.

#### Execute
Expand Down Expand Up @@ -613,7 +611,7 @@ co_await (conn.async_exec(...) || time.async_wait(...))
should last.
* The cancellation will be ignored if the request has already
been written to the socket.
* It is usually a better idea to have a healthy checker that adding
* It is usually a better idea to have a healthy checker than adding
per request timeout, see subscriber.cpp for an example.
```cpp
Expand Down
4 changes: 2 additions & 2 deletions examples/chat_room.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <aedis.hpp>
#include <unistd.h>

#include "common.hpp"
#include "common/common.hpp"

namespace net = boost::asio;
using namespace net::experimental::awaitable_operators;
Expand Down Expand Up @@ -55,7 +55,7 @@ auto subscriber(std::shared_ptr<connection> conn) -> net::awaitable<void>
co_await conn->async_exec(req);
}

// Called from the main function (see common.cpp)
// Called from the main function (see main.cpp)
auto async_main() -> net::awaitable<void>
{
auto ex = co_await net::this_coro::executor;
Expand Down
8 changes: 8 additions & 0 deletions examples/common/aedis.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/* Copyright (c) 2018-2022 Marcelo Zimbres Silva ([email protected])
*
* Distributed under the Boost Software License, Version 1.0. (See
* accompanying file LICENSE.txt)
*/

#include <aedis.hpp>
#include <aedis/src.hpp>
21 changes: 1 addition & 20 deletions examples/common.cpp → examples/common/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "common.hpp"

#include <boost/asio.hpp>
#if defined(BOOST_ASIO_HAS_CO_AWAIT)
#include <boost/asio/experimental/awaitable_operators.hpp>
#include <iostream>
Expand All @@ -18,9 +19,6 @@ using aedis::resp3::request;
using aedis::adapt;
using aedis::operation;

// Include this in no more than one .cpp file.
#include <aedis/src.hpp>

namespace
{
auto redir(boost::system::error_code& ec)
Expand Down Expand Up @@ -74,21 +72,4 @@ connect(
throw std::runtime_error("Connect timeout");
}

extern net::awaitable<void> async_main();

// Main function used in our examples.
auto main() -> int
{
try {
net::io_context ioc;
net::co_spawn(ioc, async_main(), net::detached);
ioc.run();
} catch (std::exception const& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
}

#else // defined(BOOST_ASIO_HAS_CO_AWAIT)
auto main() -> int {std::cout << "Requires coroutine support." << std::endl; return 0;}
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT)
File renamed without changes.
29 changes: 29 additions & 0 deletions examples/common/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* Copyright (c) 2018-2022 Marcelo Zimbres Silva ([email protected])
*
* Distributed under the Boost Software License, Version 1.0. (See
* accompanying file LICENSE.txt)
*/

#include <iostream>
#include <boost/asio.hpp>
#if defined(BOOST_ASIO_HAS_CO_AWAIT)

namespace net = boost::asio;
extern net::awaitable<void> async_main();

// The main function used in our examples.
auto main() -> int
{
try {
net::io_context ioc;
net::co_spawn(ioc, async_main(), net::detached);
ioc.run();
} catch (std::exception const& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
}

#else // defined(BOOST_ASIO_HAS_CO_AWAIT)
auto main() -> int {std::cout << "Requires coroutine support." << std::endl; return 0;}
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT)
4 changes: 2 additions & 2 deletions examples/containers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <map>
#include <vector>

#include "common.hpp"
#include "common/common.hpp"

namespace net = boost::asio;
using namespace net::experimental::awaitable_operators;
Expand Down Expand Up @@ -92,7 +92,7 @@ auto transaction(std::shared_ptr<connection> conn) -> net::awaitable<void>
print(std::get<1>(std::get<4>(resp)).value());
}

// Called from the main function (see common.cpp)
// Called from the main function (see main.cpp)
net::awaitable<void> async_main()
{
auto conn = std::make_shared<connection>(co_await net::this_coro::executor);
Expand Down
4 changes: 2 additions & 2 deletions examples/echo_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#if defined(BOOST_ASIO_HAS_CO_AWAIT)
#include <boost/asio/experimental/awaitable_operators.hpp>
#include <aedis.hpp>
#include "common.hpp"
#include "common/common.hpp"

namespace net = boost::asio;
using namespace net::experimental::awaitable_operators;
Expand Down Expand Up @@ -44,7 +44,7 @@ auto listener(std::shared_ptr<connection> conn) -> net::awaitable<void>
net::co_spawn(ex, echo_server_session(co_await acc.async_accept(), conn), net::detached);
}

// Called from the main function (see common.cpp)
// Called from the main function (see main.cpp)
auto async_main() -> net::awaitable<void>
{
auto ex = co_await net::this_coro::executor;
Expand Down
6 changes: 3 additions & 3 deletions examples/intro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
#if defined(BOOST_ASIO_HAS_CO_AWAIT)
#include <boost/asio/experimental/awaitable_operators.hpp>
#include <aedis.hpp>
#include "common.hpp"
#include "common/common.hpp"

namespace net = boost::asio;
using namespace net::experimental::awaitable_operators;
using aedis::adapt;
using aedis::resp3::request;

// Called from the main function (see common.cpp)
net::awaitable<void> async_main()
// Called from the main function (see main.cpp)
auto async_main() -> net::awaitable<void>
{
request req;
req.get_config().cancel_on_connection_lost = true;
Expand Down
30 changes: 14 additions & 16 deletions examples/intro_sync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,21 @@
#include <boost/asio.hpp>
#include <aedis.hpp>

// TODO: Fix this after updating to 1.80.

// Include this in no more than one .cpp file.
#include <aedis/src.hpp>

namespace net = boost::asio;
using aedis::adapt;
using aedis::resp3::request;
using connection = aedis::connection<>;
using connection = aedis::connection;

template <class Adapter>
auto exec(connection& conn, request const& req, Adapter adapter, boost::system::error_code& ec)
auto exec(std::shared_ptr<connection> conn, request const& req, Adapter adapter)
{
net::dispatch(
conn.get_executor(),
net::deferred([&]() { return conn.async_exec(req, adapter, net::deferred); }))
(net::redirect_error(net::use_future, ec)).get();
conn->get_executor(),
net::deferred([&]() { return conn->async_exec(req, adapter, net::deferred); }))
(net::use_future).get();
}

auto logger = [](auto const& ec)
Expand All @@ -37,9 +35,12 @@ int main()
try {
net::io_context ioc{1};

connection conn{ioc};
std::thread t{[&]() {
conn.async_run(logger);
auto conn = std::make_shared<connection>(ioc);
net::ip::tcp::resolver resv{ioc};
auto const res = resv.resolve("127.0.0.1", "6379");
net::connect(conn->next_layer(), res);
std::thread t{[conn, &ioc]() {
conn->async_run(logger);
ioc.run();
}};

Expand All @@ -49,13 +50,10 @@ int main()
req.push("PING");
req.push("QUIT");

boost::system::error_code ec;
std::tuple<std::string, aedis::ignore> resp;
exec(conn, req, adapt(resp), ec);
std::tuple<aedis::ignore, std::string, aedis::ignore> resp;
exec(conn, req, adapt(resp));

std::cout
<< "Exec: " << ec.message() << "\n"
<< "Response: " << std::get<0>(resp) << std::endl;
std::cout << "Response: " << std::get<1>(resp) << std::endl;

t.join();
} catch (std::exception const& e) {
Expand Down
3 changes: 2 additions & 1 deletion examples/resolve_with_sentinel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
#if defined(BOOST_ASIO_HAS_CO_AWAIT)
#include <boost/asio/experimental/awaitable_operators.hpp>
#include <aedis.hpp>
#include "common.hpp"

#include "common/common.hpp"

namespace net = boost::asio;
using namespace net::experimental::awaitable_operators;
Expand Down
2 changes: 1 addition & 1 deletion examples/serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
#include <boost/asio/experimental/awaitable_operators.hpp>
#include <boost/json.hpp>
#include <aedis.hpp>
#include "common.hpp"
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <set>
#include <iterator>
#include <string>
#include "common/common.hpp"

// Include this in no more than one .cpp file.
#include <boost/json/src.hpp>
Expand Down
2 changes: 1 addition & 1 deletion examples/subscriber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <boost/asio/experimental/awaitable_operators.hpp>
#include <aedis.hpp>

#include "common.hpp"
#include "common/common.hpp"

namespace net = boost::asio;
using namespace net::experimental::awaitable_operators;
Expand Down
Loading

0 comments on commit b9a2356

Please sign in to comment.