2
0
mirror of https://github.com/boostorg/redis.git synced 2026-01-19 04:42:09 +00:00

Fixes documentation and some examples.

This commit is contained in:
Marcelo Zimbres
2022-04-07 21:08:03 +02:00
parent 577c6d35fb
commit 46b86c20e5
10 changed files with 174 additions and 166 deletions

View File

@@ -112,6 +112,11 @@ struct assigner2<0> {
} // detail
/** @brief Return a specific adapter from the tuple.
*
* \param t A tuple of response adapters.
* \return The adapter that corresponds to type T.
*/
template <class T, class Tuple>
auto& get(Tuple& t)
{
@@ -129,27 +134,34 @@ using adapters_array_t =
std::tuple_size<Tuple>::value>;
template <class Tuple>
adapters_array_t<Tuple>
make_adapters_array(Tuple& t)
adapters_array_t<Tuple> make_adapters_array(Tuple& t)
{
adapters_array_t<Tuple> ret;
detail::assigner<std::tuple_size<Tuple>::value - 1>::assign(ret, t);
return ret;
}
/** @brief Transaforms a tuple of responses.
*
* @return Transaforms a tuple of responses into a tuple of adapters.
*/
template <class Tuple>
using adapters_t =
boost::mp11::mp_unique<
using adapters_tuple_t =
boost::mp11::mp_rename<
boost::mp11::mp_transform<
response_traits_t, Tuple>,
std::tuple>>;
std::tuple>;
/** @brief Make a tuple of adapters.
*
* \param t Tuple of responses.
* \return Tuple of adapters.
*/
template <class Tuple>
auto
make_adapters_tuple(Tuple& t)
{
adapters_t<Tuple> ret;
adapters_tuple_t<Tuple> ret;
detail::assigner2<std::tuple_size<Tuple>::value - 1>::assign(ret, t);
return ret;
}

View File

@@ -459,40 +459,35 @@
The only thing users have to care about is with the implementation
of the \c receiver class, everything else will be done
automatically by the client class. To simplify it even further
users can (but don't have to) use a base class that abstracts most
of the complexity away. The general form of a receiver looks like
this
automatically by the client class. The general form of a receiver
looks like this
@code
class myreceiver : public receiver_base<T1, T2, T3, ...> {
class receiver {
public:
int to_index_impl(command cmd) override
void on_resp3(command cmd, node<boost::string_view> const& nd, boost::system::error_code& ec)
{
// Directs responses to the desired types.
switch (cmd) {
case cmd1: return index_of<T1>();
case cmd2: return index_of<T2>();
case cmd3: return index_of<T3>();
...
default: return -1; // Ignore a command.
}
// Called when a new chunck of user data becomes available.
}
void on_read_impl(command cmd) override
void on_read(command cmd)
{
// Called when the response is received. Response available with get<T1>().
// Called when done with a response. It is read for use.
}
void on_push_impl() override
void on_write(std::size_t n)
{
// Called when a request has been writen to the socket.
}
void on_push()
{
// Called when a server push is received. Response available with get<T1>().
// Called when a server push is received.
}
};
@endcode
Where \c T1, \c T2 etc. are any of the response types discussed in \ref low-level-api. Sending
commands is also similar to what has been discussed there.
Sending commands is also similar to what has been discussed there.
@code
void foo(client<net::ip::tcp::socket>& db)
@@ -511,50 +506,50 @@
request/response protocol, which means clients must wait for the
response to a command before proceeding with the next one.
\subsection high-level-transaction Transactions
\subsection high-level-responses Responses
Aedis won't pass the responses of \c multi or any other
commands inside the transaction to the user, only the final result
i.e. the response to \c exec. The reason
for this behaviour is that unless there is a programming error,
the response to the individual commands that precede \c exec
can't fail, they will always be "QUEUED", or as quoted form the
Redis documentation https://redis.io/topics/transactions:
> Redis commands can fail only if called with a wrong syntax (and
> the problem is not detectable during the command queueing),
> or against keys holding the wrong data type: this means that in
> practical terms a failing command is the result of a programming
> errors, and a kind of error that is very likely to be detected
> during development, and not in production.
\subsection high-level-receiver Receiver
Just as users can implement their own adapter for the low-level API,
they can also implement their own Receiver for the high-level API.
For example
Aedis also provides some facilities to use use custom responses with the
high-level API. Assume for example you have many different custom
response types \c T1, \c T2 etc, a receiver that makes use of this looks
like
@code
struct receiver {
void on_resp3(command cmd, type t, std::size_t aggregate_size, std::size_t depth, char const* data, std::size_t size, boost::system::error_code&)
{
std::cout << "Resp3 data received" << std::endl;
}
using responses_tuple_type = std::tuple<T1, T2, T3>;
using adapters_tuple_type = adapters_t<responses_tuple_type>;
void on_push()
class myreceiver {
public:
myreceiver(...) : adapters_(make_adapters_tuple(resps_)) , {}
void
on_resp3( command cmd, node<boost::string_view> const& nd, boost::system::error_code& ec)
{
std::cout << "on_push: " << std::endl;
// Direct the responses to the desired adapter.
switch (cmd) {
case cmd1: adapter::get<T1>(adapters_)(nd, ec);
case cmd2: adapter::get<T2>(adapters_)(nd, ec);
case cmd3: adapter::get<T2>(adapters_)(nd, ec);
default:;
}
}
void on_read(command cmd)
{
std::cout << "on_read: " << cmd << std::endl;
switch (cmd) {
case cmd1: // Data on std::get<T1>(resps_); break;
case cmd2: // Data on std::get<T2>(resps_); break;
case cmd3: // Data on std::get<T3>(resps_); break;
default:;
}
}
void on_write(std::size_t n)
{
std::cout << "on_write: " << n << std::endl;
}
void on_write(std::size_t n) { ... }
void on_push() { ... }
private:
responses_tuple_type resps_;
adapters_tuple_type adapters_;
};
@endcode
@@ -576,9 +571,8 @@
@li high_level/stl_containers.cpp: Shows how to read responses in STL containers.
@li high_level/serialization.cpp: Shows how to de/serialize your own non-aggregate data-structures.
@li high_level/subscriber.cpp: Shows how channel subscription works at a high level. See also https://redis.io/topics/pubsub.
@li high_level/receiver.cpp: Customization point for users that want to de/serialize their own data-structures like containers for example.
\b Servers
\b Asynchronous \b Servers
@li high_level/chat_room.cpp: Shows how to build a scalable chat room that scales to millions of users.
@li high_level/echo_server.cpp: Shows the basic principles behind asynchronous communication with a database in an asynchronous server. In this case, the server is a proxy between the user and Redis.

View File

@@ -823,7 +823,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = include/aedis examples
INPUT = aedis examples
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses

View File

@@ -15,10 +15,9 @@
namespace net = boost::asio;
using aedis::resp3::node;
using aedis::redis::command;
using aedis::generic::client;
using aedis::adapter::adapt;
using client_type = client<net::ip::tcp::socket, command>;
using aedis::redis::command;
using client_type = aedis::generic::client<net::ip::tcp::socket, command>;
using response_type = std::vector<node<std::string>>;
using adapter_type = aedis::adapter::response_traits_t<response_type>;
@@ -31,24 +30,12 @@ void print_aggregate(response_type const& v)
std::cout << "\n";
}
struct myreceiver {
private:
response_type resp_;
adapter_type adapter_;
client_type* db_;
struct receiver {
public:
myreceiver(client_type& db)
receiver(client_type& db)
: adapter_{adapt(resp_)}
, db_{&db} {}
void on_write(std::size_t n)
{
std::cout << "Number of bytes written: " << n << std::endl;
}
void on_push() { }
void on_resp3(command cmd, node<boost::string_view> const& nd, boost::system::error_code& ec)
{
adapter_(nd, ec);
@@ -94,13 +81,25 @@ public:
resp_.clear();
}
void on_write(std::size_t n)
{
std::cout << "Number of bytes written: " << n << std::endl;
}
void on_push() { }
private:
response_type resp_;
adapter_type adapter_;
client_type* db_;
};
int main()
{
net::io_context ioc;
client_type db{ioc.get_executor()};
myreceiver recv{db};
receiver recv{db};
db.async_run(
recv,

View File

@@ -5,8 +5,8 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <iostream>
#include <vector>
#include <iostream>
#include <boost/asio/signal_set.hpp>
@@ -17,36 +17,22 @@
namespace net = boost::asio;
using aedis::resp3::node;
using aedis::adapter::adapt;
using aedis::redis::command;
using aedis::generic::client;
using aedis::adapter::adapt;
using aedis::user_session;
using aedis::user_session_base;
using client_type = client<net::ip::tcp::socket, command>;
using response_type = std::vector<node<std::string>>;
using adapter_type = aedis::adapter::response_traits_t<response_type>;
class myreceiver {
private:
response_type resp_;
adapter_type adapter_;
std::shared_ptr<client_type> db_;
std::vector<std::shared_ptr<user_session_base>> sessions_;
class receiver {
public:
myreceiver(std::shared_ptr<client_type> db)
receiver(std::shared_ptr<client_type> db)
: adapter_{adapt(resp_)}
, db_{db}
{}
void on_push()
{
for (auto& session: sessions_)
session->deliver(resp_.at(3).value);
resp_.clear();
}
void on_resp3(command cmd, node<boost::string_view> const& nd, boost::system::error_code& ec)
{
adapter_(nd, ec);
@@ -74,15 +60,29 @@ public:
std::cout << "Number of bytes written: " << n << std::endl;
}
void on_push()
{
for (auto& session: sessions_)
session->deliver(resp_.at(3).value);
resp_.clear();
}
auto add(std::shared_ptr<user_session_base> session)
{ sessions_.push_back(session); }
private:
response_type resp_;
adapter_type adapter_;
std::shared_ptr<client_type> db_;
std::vector<std::shared_ptr<user_session_base>> sessions_;
};
net::awaitable<void>
listener(
std::shared_ptr<net::ip::tcp::acceptor> acc,
std::shared_ptr<client_type> db,
std::shared_ptr<myreceiver> recv)
std::shared_ptr<receiver> recv)
{
auto on_user_msg = [db](std::string const& msg)
{
@@ -104,7 +104,7 @@ int main()
net::io_context ioc{1};
auto db = std::make_shared<client_type>(ioc.get_executor());
auto recv = std::make_shared<myreceiver>(db);
auto recv = std::make_shared<receiver>(db);
db->async_run(
*recv,

View File

@@ -18,10 +18,10 @@
#include "user_session.hpp"
namespace net = boost::asio;
using aedis::redis::command;
using aedis::resp3::node;
using aedis::generic::client;
using aedis::adapter::adapt;
using aedis::redis::command;
using aedis::generic::client;
using aedis::user_session;
using aedis::user_session_base;
using client_type = client<net::ip::tcp::socket, command>;
@@ -29,11 +29,6 @@ using response_type = std::vector<node<std::string>>;
using adapter_type = aedis::adapter::response_traits_t<response_type>;
class myreceiver {
private:
response_type resp_;
adapter_type adapter_;
std::queue<std::shared_ptr<user_session_base>> sessions_;
public:
myreceiver()
: adapter_{adapt(resp_)}
@@ -71,6 +66,11 @@ public:
void add_user_session(std::shared_ptr<user_session_base> session)
{ sessions_.push(session); }
private:
response_type resp_;
adapter_type adapter_;
std::queue<std::shared_ptr<user_session_base>> sessions_;
};
net::awaitable<void>

View File

@@ -26,13 +26,6 @@ public:
: adapter_{adapt(resp_)}
, db_{&db} {}
void on_write(std::size_t n)
{
std::cout << "Number of bytes written: " << n << std::endl;
}
void on_push() { }
void on_resp3(command cmd, node<boost::string_view> const& nd, boost::system::error_code& ec)
{
adapter_(nd, ec);
@@ -54,6 +47,13 @@ public:
}
}
void on_write(std::size_t n)
{
std::cout << "Number of bytes written: " << n << std::endl;
}
void on_push() { }
private:
response_type resp_;
adapter_type adapter_;

View File

@@ -20,20 +20,20 @@ struct mystruct {
namespace net = boost::asio;
namespace adapter = aedis::adapter;
using aedis::resp3::node;
using aedis::redis::command;
using aedis::adapter::adapters_t;
using aedis::adapter::adapters_tuple_t;
using aedis::adapter::make_adapters_tuple;
using aedis::adapter::get;
using aedis::redis::command;
using aedis::generic::client;
using client_type = client<net::ip::tcp::socket, command>;
using responses_type =
using responses_tuple_type =
std::tuple<
boost::optional<mystruct>, // get
std::list<mystruct>, // lrange
std::set<mystruct>, // smembers
std::map<std::string, mystruct> // hgetall
boost::optional<mystruct>,
std::list<mystruct>,
std::set<mystruct>,
std::map<std::string, mystruct>
>;
using adapters_type = adapters_t<responses_type>;
using adapters_tuple_type = adapters_tuple_t<responses_tuple_type>;
std::ostream& operator<<(std::ostream& os, mystruct const& obj)
{
@@ -59,14 +59,9 @@ void from_string(mystruct& obj, boost::string_view sv, boost::system::error_code
obj.b = 2;
}
class myreceiver {
private:
responses_type resps_;
adapters_type adapters_;
client_type* db_;
class receiver {
public:
myreceiver(client_type& db)
receiver(client_type& db)
: adapters_(make_adapters_tuple(resps_))
, db_{&db} {}
@@ -77,10 +72,10 @@ public:
boost::system::error_code& ec)
{
switch (cmd) {
case command::get: adapter::get<boost::optional<mystruct>>(adapters_)(nd, ec);
case command::lrange: adapter::get<std::list<mystruct>>(adapters_)(nd, ec);
case command::smembers: adapter::get<std::set<mystruct>>(adapters_)(nd, ec);
case command::hgetall: adapter::get<std::map<std::string, mystruct>>(adapters_)(nd, ec);
case command::get: adapter::get<boost::optional<mystruct>>(adapters_)(nd, ec); break;
case command::lrange: adapter::get<std::list<mystruct>>(adapters_)(nd, ec); break;
case command::smembers: adapter::get<std::set<mystruct>>(adapters_)(nd, ec); break;
case command::hgetall: adapter::get<std::map<std::string, mystruct>>(adapters_)(nd, ec); break;
default:; // Ignore
}
}
@@ -153,15 +148,24 @@ public:
}
}
void on_write(std::size_t n) { }
void on_write(std::size_t n)
{
std::cout << "Number of bytes written: " << n << std::endl;
}
void on_push() { }
private:
responses_tuple_type resps_;
adapters_tuple_type adapters_;
client_type* db_;
};
int main()
{
net::io_context ioc;
client_type db(ioc.get_executor());
myreceiver recv{db};
receiver recv{db};
db.async_run(
recv,

View File

@@ -18,16 +18,16 @@ using aedis::resp3::node;
using aedis::redis::command;
using aedis::generic::client;
using aedis::adapter::adapt;
using aedis::adapter::adapters_t;
using aedis::adapter::adapters_tuple_t;
using aedis::adapter::make_adapters_tuple;
using client_type = client<net::ip::tcp::socket, command>;
using responses_type =
using responses_tuple_type =
std::tuple<
std::list<int>,
boost::optional<std::set<std::string>>,
std::vector<node<std::string>>
>;
using adapters_type = adapters_t<responses_type>;
using adapters_tuple_type = adapters_tuple_t<responses_tuple_type>;
template <class Container>
void print_and_clear(Container& cont)
@@ -51,19 +51,12 @@ public:
boost::system::error_code& ec)
{
switch (cmd) {
case command::lrange: adapter::get<std::list<int>>(adapters_)(nd, ec);
case command::smembers: adapter::get<boost::optional<std::set<std::string>>>(adapters_)(nd, ec);
case command::lrange: adapter::get<std::list<int>>(adapters_)(nd, ec); break;
case command::smembers: adapter::get<boost::optional<std::set<std::string>>>(adapters_)(nd, ec); break;
default:;
}
}
void on_write(std::size_t n)
{
std::cout << "Number of bytes written: " << n << std::endl;
}
void on_push() { }
void on_read(command cmd)
{
switch (cmd) {
@@ -105,9 +98,16 @@ public:
}
}
void on_write(std::size_t n)
{
std::cout << "Number of bytes written: " << n << std::endl;
}
void on_push() { }
private:
responses_type resps_;
adapters_type adapters_;
responses_tuple_type resps_;
adapters_tuple_type adapters_;
client_type* db_;
};

View File

@@ -41,27 +41,11 @@ public:
: adapter_{adapt(resp_)}
, db_{&db} {}
void on_write(std::size_t n)
{
std::cout << "Number of bytes written: " << n << std::endl;
}
void on_resp3(command cmd, node<boost::string_view> const& nd, boost::system::error_code& ec)
{
adapter_(nd, ec);
}
void on_push()
{
std::cout
<< "Event: " << resp_.at(1).value << "\n"
<< "Channel: " << resp_.at(2).value << "\n"
<< "Message: " << resp_.at(3).value << "\n"
<< std::endl;
resp_.clear();
}
void on_read(command cmd)
{
switch (cmd) {
@@ -74,6 +58,22 @@ public:
resp_.clear();
}
void on_write(std::size_t n)
{
std::cout << "Number of bytes written: " << n << std::endl;
}
void on_push()
{
std::cout
<< "Event: " << resp_.at(1).value << "\n"
<< "Channel: " << resp_.at(2).value << "\n"
<< "Message: " << resp_.at(3).value << "\n"
<< std::endl;
resp_.clear();
}
private:
response_type resp_;
adapter_type adapter_;
@@ -93,4 +93,3 @@ int main()
ioc.run();
}