From cc034e569363214396cb51e8b2e9dfa504bc0ea6 Mon Sep 17 00:00:00 2001 From: Marcelo Zimbres Date: Sat, 9 Jan 2021 18:56:19 +0100 Subject: [PATCH] Removes redundant examples. --- Makefile | 3 - README.md | 108 +++++++++++++++++------------------ examples/async_basic.cpp | 75 ++++++++++++------------ examples/async_responses.cpp | 65 --------------------- examples/sync_basic.cpp | 35 +++++------- examples/sync_events.cpp | 65 --------------------- include/aedis/request.hpp | 10 ++++ include/aedis/version.hpp | 2 +- 8 files changed, 114 insertions(+), 249 deletions(-) delete mode 100644 examples/async_responses.cpp delete mode 100644 examples/sync_events.cpp diff --git a/Makefile b/Makefile index 55475188..d0922f97 100644 --- a/Makefile +++ b/Makefile @@ -23,12 +23,9 @@ LDFLAGS += -pthread examples = examples += sync_basic -examples += sync_responses -examples += sync_events examples += async_basic examples += async_reconnect examples += async_all_hashes -examples += async_responses examples += async_events examples += async_pubsub diff --git a/README.md b/README.md index f050a19d..50c93af2 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,20 @@ # Aedis -Aedis is a low level redis client designed for scalability and to -provide an easy and intuitive interface. Some of the supported -features are +Aedis is a low level redis client designed for scalability and +performance while providing an easy and intuitive interface. Some of +the supported features are -* TLS, RESP3 and STL containers +* TLS, RESP3 and STL containers. * Pipelines (essential for performance). * Coroutines, futures and callbacks. -At the moment the biggest missing parts is the Attribute data type as +At the moment the biggest missing part is the Attribute data type as its specification seems to be incomplete and I found no way to test them. ## Tutorial -Sending a command to a redis server is as simple as +Sending a command to a redis server is done as follows ```cpp resp::request req; @@ -26,55 +26,56 @@ Sending a command to a redis server is as simple as co_await resp::async_write(socket, req); ``` -where `socket` is a tcp socket. Whereas reading looks like the -following +where `socket` is a tcp socket. Reading on the other hand looks like +the following + ```cpp resp::response_set res; co_await resp::async_read(socket, buffer, res); ``` -Where the response type above depends on which command is being -expected. +The response type above depends on which command is being expected. +This library also offers the synchronous functions to parse `RESP`, in +this tutorial however we will focus in async code. -A complete synchronous example can be seem bellow +A complete example can be seem bellow ```cpp -int main() +net::awaitable example() { try { - resp::request req; - req.hello(); - req.set("Password", {"12345"}); - req.get("Password"); - req.quit(); + auto ex = co_await this_coro::executor; - net::io_context ioc {1}; - tcp::resolver resv(ioc); - tcp::socket socket {ioc}; - net::connect(socket, resv.resolve("127.0.0.1", "6379")); - resp::write(socket, req); + resp::request p; + p.hello(); + p.rpush("list", {1, 2, 3}); + p.lrange("list"); + p.quit(); + + tcp::resolver resv(ex); + tcp_socket socket {ex}; + co_await net::async_connect(socket, resv.resolve("127.0.0.1", "6379")); + co_await net::async_write(socket, net::buffer(p.payload)); std::string buffer; - for (;;) { - switch (req.events.front().first) { - case resp::command::hello: - { - resp::response_flat_map res; - resp::read(socket, buffer, res); - } break; - case resp::command::get: - { - resp::response_blob_string res; - resp::read(socket, buffer, res); - } break; - default: - { - resp::response_ignore res; - resp::read(socket, buffer, res); - } - } - req.events.pop(); - } + resp::response_flat_map hello; + co_await resp::async_read(socket, buffer, hello); + + resp::response_number rpush; + co_await resp::async_read(socket, buffer, rpush); + std::cout << rpush.result << std::endl; + + resp::response_list lrange; + co_await resp::async_read(socket, buffer, lrange); + print(lrange.result); + + resp::response_simple_string quit; + co_await resp::async_read(socket, buffer, quit); + std::cout << quit.result << std::endl; + + resp::response_ignore eof; + co_await resp::async_read(socket, buffer, eof); + } catch (std::exception const& e) { std::cerr << e.what() << std::endl; } @@ -82,33 +83,28 @@ int main() ``` The important things to notice above are -* After connecting RESP3 requires the `hello` comand to be sent. +* After connecting RESP3 requires the `hello` command to be sent. * Many commands are sent in the same request, the so called pipeline. * Keep reading from the socket until it is closed by the redis server as requested by `quit`. -* The response is parsed in an appropriate buffer. - -It is trivial to rewrite the example above to use coroutines, see -`examples/async_basic.cpp`. From now on we will use themas this is how -most people will be writting async servers in C++. +* The response is parsed directly in a buffer that is suitable to the + application. ### Response buffer To communicate efficiently with redis it is necessary to understand -the possible response types. RESP3 spcifies the following data types +the possible response types. RESP3 specifies the following data types `simple string`, `Simple error`, `number`, `double`, `bool`, `big number`, `null`, `blob error`, `verbatim string`, `blob string`, -`streamed string part`. - -These data types may come in different aggregate types `array`, -`push`, `set`, `map`, `attribute`. Aedis provides appropriate response -types for each of them. +`streamed string part`. These data types may come in different +aggregate types `array`, `push`, `set`, `map`, `attribute`. Aedis +provides appropriate response types for each of them. ### Events The request type used above keeps a `std::queue` of commands in the -order they are expected to arrive. In addition to that you can -specify your own events +order they are expected to arrive. In addition to that you can specify +your own events ```cpp enum class myevents diff --git a/examples/async_basic.cpp b/examples/async_basic.cpp index 22473014..d3b56b15 100644 --- a/examples/async_basic.cpp +++ b/examples/async_basic.cpp @@ -5,53 +5,54 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -#include #include namespace net = aedis::net; -namespace this_coro = net::this_coro; -using namespace aedis; + +namespace net = aedis::net; +using tcp = net::ip::tcp; using tcp_socket = net::use_awaitable_t<>::as_default_on_t; -net::awaitable example1() +namespace this_coro = net::this_coro; + +using namespace net; +using namespace aedis; + +net::awaitable example() { try { - resp::request req; - req.hello(); - req.set("Password", {"12345"}); - req.get("Password"); - req.quit(); - auto ex = co_await this_coro::executor; + + resp::request p; + p.hello(); + p.rpush("list", {1, 2, 3}); + p.lrange("list"); + p.quit(); + tcp::resolver resv(ex); - auto const r = resv.resolve("127.0.0.1", "6379"); tcp_socket socket {ex}; - co_await async_connect(socket, r); - co_await async_write(socket, req); + co_await net::async_connect(socket, resv.resolve("127.0.0.1", "6379")); + co_await net::async_write(socket, net::buffer(p.payload)); std::string buffer; - for (;;) { - switch (req.events.front().first) { - case resp::command::hello: - { - resp::response_flat_map res; - co_await resp::async_read(socket, buffer, res); - print(res.result); - } break; - case resp::command::get: - { - resp::response_blob_string res; - co_await resp::async_read(socket, buffer, res); - std::cout << "get: " << res.result << std::endl; - } break; - default: - { - resp::response_ignore res; - co_await resp::async_read(socket, buffer, res); - } - } - req.events.pop(); - } + resp::response_flat_map hello; + co_await resp::async_read(socket, buffer, hello); + + resp::response_number rpush; + co_await resp::async_read(socket, buffer, rpush); + std::cout << rpush.result << std::endl; + + resp::response_list lrange; + co_await resp::async_read(socket, buffer, lrange); + print(lrange.result); + + resp::response_simple_string quit; + co_await resp::async_read(socket, buffer, quit); + std::cout << quit.result << std::endl; + + resp::response_ignore eof; + co_await resp::async_read(socket, buffer, eof); + } catch (std::exception const& e) { std::cerr << e.what() << std::endl; } @@ -59,8 +60,8 @@ net::awaitable example1() int main() { - net::io_context ioc {1}; - net::co_spawn(ioc, example1(), net::detached); + io_context ioc {1}; + co_spawn(ioc, example(), detached); ioc.run(); } diff --git a/examples/async_responses.cpp b/examples/async_responses.cpp deleted file mode 100644 index ad406ff7..00000000 --- a/examples/async_responses.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (c) 2019 - 2020 Marcelo Zimbres Silva (mzimbres at gmail dot com) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include - -namespace net = aedis::net; - -namespace net = aedis::net; -using tcp = net::ip::tcp; -using tcp_socket = net::use_awaitable_t<>::as_default_on_t; - -namespace this_coro = net::this_coro; - -using namespace net; -using namespace aedis; - -net::awaitable example() -{ - try { - resp::request p; - p.hello(); - p.rpush("list", {1, 2, 3}); - p.lrange("list"); - p.quit(); - - auto ex = co_await this_coro::executor; - tcp::resolver resv(ex); - tcp_socket socket {ex}; - co_await net::async_connect(socket, resv.resolve("127.0.0.1", "6379")); - co_await net::async_write(socket, net::buffer(p.payload)); - - std::string buffer; - resp::response_ignore hello; - co_await resp::async_read(socket, buffer, hello); - - resp::response_number list_size; - co_await resp::async_read(socket, buffer, list_size); - std::cout << list_size.result << std::endl; - - resp::response_list list; - co_await resp::async_read(socket, buffer, list); - print(list.result); - - resp::response_simple_string ok; - co_await resp::async_read(socket, buffer, ok); - std::cout << ok.result << std::endl; - - resp::response_ignore noop; - co_await resp::async_read(socket, buffer, noop); - - } catch (std::exception const& e) { - std::cerr << e.what() << std::endl; - } -} - -int main() -{ - io_context ioc {1}; - co_spawn(ioc, example(), detached); - ioc.run(); -} diff --git a/examples/sync_basic.cpp b/examples/sync_basic.cpp index e95fa925..e948785f 100644 --- a/examples/sync_basic.cpp +++ b/examples/sync_basic.cpp @@ -26,28 +26,19 @@ int main() resp::write(socket, req); std::string buffer; - for (;;) { - switch (req.events.front().first) { - case resp::command::hello: - { - resp::response_flat_map res; - resp::read(socket, buffer, res); - print(res.result); - } break; - case resp::command::get: - { - resp::response_blob_string res; - resp::read(socket, buffer, res); - std::cout << "get: " << res.result << std::endl; - } break; - default: - { - resp::response_ignore res; - resp::read(socket, buffer, res); - } - } - req.events.pop(); - } + resp::response_flat_map hello; + resp::read(socket, buffer, hello); + print(hello.result); + + resp::response_simple_string set; + resp::read(socket, buffer, set); + + resp::response_blob_string get; + resp::read(socket, buffer, get); + std::cout << "get: " << get.result << std::endl; + + resp::response_ignore quit; + resp::read(socket, buffer, quit); } catch (std::exception const& e) { std::cerr << e.what() << std::endl; } diff --git a/examples/sync_events.cpp b/examples/sync_events.cpp deleted file mode 100644 index 2d2bd478..00000000 --- a/examples/sync_events.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (c) 2019 - 2020 Marcelo Zimbres Silva (mzimbres at gmail dot com) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include - -namespace net = aedis::net; - -using namespace net; -using namespace aedis; - -enum class myevents -{ ignore -, interesting1 -, interesting2 -}; - -int main() -{ - try { - resp::request req; - req.hello(); - req.rpush("list", {1, 2, 3}); - req.lrange("list", 0, -1, myevents::interesting1); - req.sadd("set", std::set{3, 4, 5}); - req.smembers("set", myevents::interesting2); - req.quit(); - - io_context ioc {1}; - tcp::resolver resv(ioc); - tcp::socket socket {ioc}; - net::connect(socket, resv.resolve("127.0.0.1", "6379")); - resp::write(socket, req); - - std::string buffer; - for (;;) { - switch (req.events.front().second) { - case myevents::interesting1: - { - resp::response_list res; - resp::read(socket, buffer, res); - print(res.result); - } break; - case myevents::interesting2: - { - resp::response_set res; - resp::read(socket, buffer, res); - print(res.result); - } break; - default: - { - resp::response_ignore res; - resp::read(socket, buffer, res); - } - } - req.events.pop(); - } - } catch (std::exception const& e) { - std::cerr << e.what() << std::endl; - } -} - diff --git a/include/aedis/request.hpp b/include/aedis/request.hpp index 3bd4a120..38b3714d 100644 --- a/include/aedis/request.hpp +++ b/include/aedis/request.hpp @@ -136,6 +136,7 @@ enum class command , bgrewriteaof , bgsave , bitcount +, client , del , exec , expire @@ -677,6 +678,15 @@ public: resp::assemble(payload, "SDIFF", {key}, std::cbegin(l), std::cend(l)); events.push({command::scard, e}); } + + auto + client( + std::string_view parameters, + Event e = Event::ignore) + { + resp::assemble(payload, "CLIENT", {parameters}); + events.push({command::client, e}); + } }; } // resp diff --git a/include/aedis/version.hpp b/include/aedis/version.hpp index 725133aa..a0854981 100644 --- a/include/aedis/version.hpp +++ b/include/aedis/version.hpp @@ -6,5 +6,5 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -#define AEDIS_VERSION 1.0.0 +#define AEDIS_VERSION 2