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

Some refactoring and reorganization.

This commit is contained in:
Marcelo Zimbres
2022-01-29 11:45:31 +01:00
parent 8bd0230f46
commit 8c099bfed3
39 changed files with 666 additions and 426 deletions

View File

@@ -1,7 +1 @@
CC=/opt/gcc-10.2.0/bin/gcc-10.2.0 CXX=/opt/gcc-10.2.0/bin/g++-10.2.0 CXXFLAGS="-std=c++20 -fcoroutines -g -Wall -Wno-subobject-linkage -Werror" ./configure --with-boost=/opt/boost_1_78_0 --with-boost-libdir=/opt/boost_1_78_0/lib
CPPFLAGS="-std=c++20 -fcoroutines -g -Wall -Wno-subobject-linkage -Werror"
BOOST_LDFLAGS = -L/opt/boost_1_78_0/lib
BOOST_CPPFLAGS = -I/opt/boost_1_78_0/include
export CPPFLAGS="$(BOOST_CPPFLAGS) $(CPPFLAGS)"
export LDFLAGS="$(BOOST_LDFLAGS)"
See file:///tmp/aedis/html/installation.html

View File

@@ -1,102 +1,62 @@
ACLOCAL_AMFLAGS = -I m4
AUTOMAKE_OPTIONS = subdir-objects
ACLOCAL_AMFLAGS = -I m4
AM_COLOR_TESTS = always
DISTCHECK_CONFIGURE_FLAGS = CPPFLAGS="$(BOOST_CPPFLAGS) $(CPPFLAGS)" LDFLAGS="$(BOOST_LDFLAGS)"
MY_CPPFLAGS =
MY_CPPFLAGS += $(BOOST_CPPFLAGS)
MY_CPPFLAGS += -I$(top_srcdir)/
AM_CPPFLAGS =
AM_CPPFLAGS += $(BOOST_CPPFLAGS)
MY_LDADD =
MY_LDADD += -lpthread
AM_LDFLAGS =
AM_LDFLAGS += -pthread
check_PROGRAMS =
check_PROGRAMS += intro
intro_SOURCES = $(top_srcdir)/examples/intro.cpp
intro_CPPFLAGS = $(MY_CPPFLAGS)
intro_LDADD = $(MY_LDADD)
check_PROGRAMS += sets
sets_SOURCES = $(top_srcdir)/examples/sets.cpp
sets_CPPFLAGS = $(MY_CPPFLAGS)
sets_LDADD = $(MY_LDADD)
check_PROGRAMS += hashes
hashes_SOURCES = $(top_srcdir)/examples/hashes.cpp
hashes_CPPFLAGS = $(MY_CPPFLAGS)
hashes_LDADD = $(MY_LDADD)
check_PROGRAMS += serialization
serialization_SOURCES = $(top_srcdir)/examples/serialization.cpp
serialization_CPPFLAGS = $(MY_CPPFLAGS)
serialization_LDADD = $(MY_LDADD)
check_PROGRAMS += nested_response
nested_response_SOURCES = $(top_srcdir)/examples/nested_response.cpp
nested_response_CPPFLAGS = $(MY_CPPFLAGS)
nested_response_LDADD = $(MY_LDADD)
check_PROGRAMS += lists
lists_SOURCES = $(top_srcdir)/examples/lists.cpp
lists_CPPFLAGS = $(MY_CPPFLAGS)
lists_LDADD = $(MY_LDADD)
check_PROGRAMS += key_expiration
key_expiration_SOURCES = $(top_srcdir)/examples/key_expiration.cpp
key_expiration_CPPFLAGS = $(MY_CPPFLAGS)
key_expiration_LDADD = $(MY_LDADD)
check_PROGRAMS += response_adapter
response_adapter_SOURCES = $(top_srcdir)/examples/response_adapter.cpp
response_adapter_CPPFLAGS = $(MY_CPPFLAGS)
response_adapter_LDADD = $(MY_LDADD)
check_PROGRAMS += sync
sync_SOURCES = $(top_srcdir)/examples/sync.cpp
sync_CPPFLAGS = $(MY_CPPFLAGS)
sync_LDADD = $(MY_LDADD)
check_PROGRAMS += redis_client
redis_client_SOURCES = $(top_srcdir)/examples/redis_client.cpp
redis_client_CPPFLAGS = $(MY_CPPFLAGS)
redis_client_LDADD = $(MY_LDADD)
check_PROGRAMS += commands
commands_SOURCES = $(top_srcdir)/tools/commands.cpp
commands_CPPFLAGS = $(MY_CPPFLAGS)
commands_LDADD = $(MY_LDADD)
check_PROGRAMS += test_offline
test_offline_SOURCES = $(top_srcdir)/tests/offline.cpp
test_offline_CPPFLAGS = $(MY_CPPFLAGS)
test_offline_LDADD = $(MY_LDADD)
check_PROGRAMS += test_online
test_online_SOURCES = $(top_srcdir)/tests/online.cpp
test_online_CPPFLAGS = $(MY_CPPFLAGS)
test_online_LDADD = $(MY_LDADD)
EXTRA_PROGRAMS =
EXTRA_PROGRAMS += subscriber
subscriber_SOURCES = $(top_srcdir)/examples/subscriber.cpp
subscriber_CPPFLAGS = $(MY_CPPFLAGS)
subscriber_LDADD = $(MY_LDADD)
EXTRA_PROGRAMS += echo_server
echo_server_SOURCES = $(top_srcdir)/examples/echo_server.cpp
echo_server_CPPFLAGS = $(MY_CPPFLAGS)
echo_server_LDADD = $(MY_LDADD)
EXTRA_PROGRAMS += chat_room
EXTRA_PROGRAMS += commands
.PHONY: all
all: $(check_PROGRAMS) $(EXTRA_PROGRAMS)
intro_SOURCES = $(top_srcdir)/examples/intro.cpp
sets_SOURCES = $(top_srcdir)/examples/sets.cpp
hashes_SOURCES = $(top_srcdir)/examples/hashes.cpp
serialization_SOURCES = $(top_srcdir)/examples/serialization.cpp
nested_response_SOURCES = $(top_srcdir)/examples/nested_response.cpp
lists_SOURCES = $(top_srcdir)/examples/lists.cpp
key_expiration_SOURCES = $(top_srcdir)/examples/key_expiration.cpp
response_adapter_SOURCES = $(top_srcdir)/examples/response_adapter.cpp
sync_SOURCES = $(top_srcdir)/examples/sync.cpp
redis_client_SOURCES = $(top_srcdir)/examples/redis_client.cpp
commands_SOURCES = $(top_srcdir)/tools/commands.cpp
test_offline_SOURCES = $(top_srcdir)/tests/offline.cpp
test_online_SOURCES = $(top_srcdir)/tests/online.cpp
subscriber_SOURCES = $(top_srcdir)/examples/subscriber.cpp
echo_server_SOURCES = $(top_srcdir)/examples/echo_server.cpp
chat_room_SOURCES = $(top_srcdir)/examples/chat_room.cpp
chat_room_CPPFLAGS = $(MY_CPPFLAGS)
chat_room_LDADD = $(MY_LDADD)
nobase_nodist_include_HEADERS =\
$(top_srcdir)/aedis/config.hpp
nobase_include_HEADERS =\
$(top_srcdir)/aedis/src.hpp\
$(top_srcdir)/aedis/net.hpp\
$(top_srcdir)/aedis/command.hpp\
$(top_srcdir)/aedis/redis/command.hpp\
$(top_srcdir)/aedis/sentinel/command.hpp\
$(top_srcdir)/aedis/aedis.hpp\
$(top_srcdir)/aedis/resp3/adapter/detail/adapters.hpp\
$(top_srcdir)/aedis/resp3/adapter/error.hpp\
@@ -104,26 +64,24 @@ nobase_include_HEADERS =\
$(top_srcdir)/aedis/resp3/detail/composer.hpp\
$(top_srcdir)/aedis/resp3/detail/read_ops.hpp\
$(top_srcdir)/aedis/resp3/detail/parser.hpp\
$(top_srcdir)/aedis/resp3/client.hpp\
$(top_srcdir)/aedis/resp3/serializer.hpp\
$(top_srcdir)/aedis/resp3/response_traits.hpp\
$(top_srcdir)/aedis/resp3/node.hpp\
$(top_srcdir)/aedis/resp3/error.hpp\
$(top_srcdir)/aedis/resp3/type.hpp\
$(top_srcdir)/aedis/resp3/read.hpp\
$(top_srcdir)/aedis/impl/command.ipp\
$(top_srcdir)/aedis/redis/impl/command.ipp\
$(top_srcdir)/aedis/sentinel/impl/command.ipp\
$(top_srcdir)/aedis/resp3/detail/impl/parser.ipp\
$(top_srcdir)/aedis/resp3/impl/type.ipp\
$(top_srcdir)/aedis/resp3/impl/client.ipp\
$(top_srcdir)/aedis/resp3/impl/node.ipp
$(top_srcdir)/aedis/resp3/impl/node.ipp\
$(top_srcdir)/aedis/redis/experimental/client.hpp\
$(top_srcdir)/aedis/redis/experimental/impl/client.ipp
nobase_noinst_HEADERS =\
$(top_srcdir)/examples/utils.ipp\
$(top_srcdir)/examples/lib/responses.ipp\
$(top_srcdir)/examples/lib/net_utils.hpp\
$(top_srcdir)/examples/lib/responses.hpp\
$(top_srcdir)/examples/lib/user_session.hpp\
$(top_srcdir)/examples/lib/user_session.ipp\
$(top_srcdir)/examples/src.hpp\
$(top_srcdir)/tests/check.hpp\
$(top_srcdir)/tests/test_stream.hpp
@@ -138,23 +96,9 @@ EXTRA_DIST += $(top_srcdir)/doc/htmlfooter.html
EXTRA_DIST += $(top_srcdir)/doc/htmlheader.html
CLEANFILES =
#CLEANFILES += Makefile.dep
.PHONY: doc
doc:
rm -rf /tmp/aedis
doxygen doc/Doxyfile
.PHONY: deb
deb: dist
export CPPFLAGS="$(BOOST_CPPFLAGS) $(CPPFLAGS)" &&\
export LDFLAGS="$(BOOST_LDFLAGS)" &&\
rm -rf tmp &&\
mkdir tmp &&\
mv $(distdir).tar.gz $(distdir)-1.tar.gz &&\
mv $(distdir)-1.tar.gz tmp &&\
cd tmp &&\
ln $(distdir)-1.tar.gz $(PACKAGE)_$(VERSION).orig.tar.gz &&\
tar -xvvzf $(distdir)-1.tar.gz &&\
cd $(distdir)/debian; debuild --no-sign -j1

View File

@@ -7,46 +7,44 @@
#pragma once
#include <aedis/net.hpp>
#include <aedis/command.hpp>
#include <aedis/config.hpp>
#include <aedis/redis/command.hpp>
#include <aedis/sentinel/command.hpp>
#include <aedis/resp3/type.hpp>
#include <aedis/resp3/read.hpp>
#include <aedis/resp3/adapt.hpp>
#include <aedis/resp3/error.hpp>
#include <aedis/resp3/serializer.hpp>
#include <aedis/resp3/response_traits.hpp>
#include <aedis/resp3/client.hpp>
#include <aedis/redis/experimental/client.hpp>
/** \mainpage
Introduction
- \subpage overview
- \subpage installation
- \subpage examples
Reference
- \subpage enums
- \subpage classes
- \subpage functions
- \subpage operators
*
* \b Overview
*
* Aedis is low-level redis client built on top of Boost.Asio that
* implements communication with a Redis server over its native
* protocol RESP3. It has first-class support for STL containers and
* C++ built in types. You will be able to implement your own redis
* client or use a general purpose provided by the library. For more
* information about Redis see https://redis.io/
*
* \b Using \b Aedis
*
* - \subpage installation
* - \subpage examples
*
* \b Reference
*
* - \subpage enums
* - \subpage classes
* - \subpage functions
* - \subpage operators
*/
//---------------------------------------------------------
// Pages
/** \page overview Overview
*
* Aedis provides low-level communication with a Redis server over
* its native protocol RESP3. Some of its featues are
*
* - First class support to STL containers and C++ built-in types.
* - Support for pipelining, transactions and TLS.
* - Serialization and de-serialization of your own types.
* - First class support to async programming through ASIO.
*/
/** \page examples Examples
*
\b Basics: Focuses on small code snippets that show basic usage of
@@ -67,7 +65,8 @@
Shows how to read responses to commands that cannot be
translated in a C++ built-in type like std::string or STL
containers.
containers, for example all commands contained in a transaction
will be nested by Redis in a single response.
- subscriber.cpp
@@ -77,11 +76,6 @@
Shows hot to use the Aedis synchronous api.
- redis_client.cpp
Shows how to use and experimental high level redis client that
keeps a long lasting connections to a redis server.
\b STL \b Containers: Many of the Redis data structures can be
directly translated in to STL containers, below you will find some
example code. For a list of Redis data types see
@@ -119,6 +113,12 @@
servers that interact with users and Redis asynchronously over
long lasting connections using a higher level API.
- redis_client.cpp
Shows how to use and experimental high level redis client that
keeps a long lasting connections to a redis server. This is the
starting point for the next examples.
- echo_server.cpp
Shows the basic principles behind asynchronous communication
@@ -133,18 +133,84 @@
/** \page installation Installation
*
* This library is header only. To install it run
* \section Requirements
*
* ```cpp
* To use Aedis you will need
*
* Required
*
* - \b C++20 with \b coroutine support.
* - \b Boost \b 1.78 or greater.
* - \b Redis \b server.
* - \b Bash to configure that package for installation.
*
* Optional
*
* - \b Redis \b Sentinel \b server: used in some examples..
* - \b Redis \b client: used in some examples.
* - \b Make to build the examples and tests.
*
* \section Installing
*
* Download
*
* Get the latest release and follow the steps
*
* ```bash
* # Download the libray on github.
* $ wget github-link
*
* # Uncompress the tarball and cd into the dir
* $ tar -xzvf aedis-1.0.0.tar.gz && cd aedis-1.0.0
*
* # Run configure with appropriate C++ flags and your boost installation, for example
* $ CXXFLAGS="-std=c++20 -fcoroutines -g -Wall -Wno-subobject-linkage"\
* ./configure --prefix=/opt/aedis-1.0.0 --with-boost=/opt/boost_1_78_0 --with-boost-libdir=/opt/boost_1_78_0/lib
*
* ```
*
* Install
*
* ```bash
* # Optional: Build aedis examples.
* $ make examples
*
* # Optional: Test aedis in your machine.
* $ make check
*
* # Install the aedis.
* $ sudo make install
* ```
*
* or copy the include folder to the location you want. You will
* also need to include the following header in one of your source
* files e.g. `aedis.cpp`
* \section using Using Aedis
*
* This library in not header-only. You have to include the following
* header
*
* ```cpp
* #include <aedis/impl/src.hpp>
* #include <aedis/src.hpp>
* ```
*
* in exactly one source file in your applications.
*
* \section Developers
*
* Aedis uses Autotools for its build system. To generate the build
* system run
*
* ```bash
* $ autoreconf -i
* ```
*
* After that you will have a config in the project dir that you can
* run as explained above, for example, to use a compiler other that
* the system compiler use
*
* ```bash
* CC=/opt/gcc-10.2.0/bin/gcc-10.2.0\
* CXX=/opt/gcc-10.2.0/bin/g++-10.2.0\
* CXXFLAGS="-std=c++20 -fcoroutines -g -Wall -Wno-subobject-linkage -Werror"\
* ./configure ...
* ```
*/

View File

@@ -7,6 +7,8 @@
#pragma once
#define AEDIS_VERSION @PACKAGE_VERSION@
#include <boost/asio.hpp>
namespace aedis {

View File

@@ -8,8 +8,12 @@
#pragma once
#include <ostream>
#include <string>
#include <aedis/resp3/serializer.hpp>
namespace aedis {
namespace redis {
/** \brief Redis commands.
* \ingroup enums
@@ -451,4 +455,16 @@ std::ostream& operator<<(std::ostream& os, command c);
*/
bool has_push_response(command cmd);
/** \brief Creates a serializer for a \c std::string.
* \ingroup functions
* \param storage The string.
*/
template <class CharT, class Traits, class Allocator>
resp3::serializer<std::string, command>
make_serializer(std::basic_string<CharT, Traits, Allocator>& storage)
{
return resp3::serializer<std::basic_string<CharT, Traits, Allocator>, command>(storage);
}
} // redis
} // aedis

View File

@@ -11,6 +11,7 @@
#include <functional>
#include <aedis/aedis.hpp>
#include <aedis/redis/command.hpp>
namespace aedis {
namespace resp3 {
@@ -25,10 +26,10 @@ namespace experimental {
class client : public std::enable_shared_from_this<client> {
public:
/// The response adapter type.
using adapter_type = std::function<void(command, type, std::size_t, std::size_t, char const*, std::size_t, std::error_code&)>;
using adapter_type = std::function<void(redis::command, type, std::size_t, std::size_t, char const*, std::size_t, std::error_code&)>;
/// The type of the message callback.
using on_message_type = std::function<void(std::error_code ec, command)>;
using on_message_type = std::function<void(std::error_code ec, redis::command)>;
private:
using tcp_socket = net::use_awaitable_t<>::as_default_on_t<net::ip::tcp::socket>;
@@ -46,7 +47,7 @@ private:
std::string requests_;
// The commands contained in the requests.
std::queue<command> commands_;
std::queue<redis::command> commands_;
// Info about the requests.
std::queue<request_info> req_info_;
@@ -103,7 +104,7 @@ public:
* \sa serializer.hpp
*/
template <class... Ts>
void send(command cmd, Ts const&... args);
void send(redis::command cmd, Ts const&... args);
/// Sets the response adapter.
void set_adapter(adapter_type adapter);
@@ -113,11 +114,11 @@ public:
};
template <class... Ts>
void client::send(command cmd, Ts const&... args)
void client::send(redis::command cmd, Ts const&... args)
{
auto const can_write = prepare_next();
auto sr = make_serializer<command>(requests_);
auto sr = redis::make_serializer(requests_);
auto const before = std::size(requests_);
sr.push(cmd, args...);
auto const after = std::size(requests_);

View File

@@ -7,7 +7,7 @@
#pragma once
#include <aedis/resp3/client.hpp>
#include <aedis/redis/experimental/client.hpp>
#include <boost/asio/experimental/awaitable_operators.hpp>
@@ -40,11 +40,11 @@ net::awaitable<void> client::reader()
auto const t = co_await async_read_type(socket_, net::dynamic_buffer(buffer));
if (t == type::push) {
auto adapter = [this](type t, std::size_t aggregate_size, std::size_t depth, char const* data, std::size_t size, std::error_code& ec)
{adapter_(command::unknown, t, aggregate_size, depth, data, size, ec);};
{adapter_(redis::command::unknown, t, aggregate_size, depth, data, size, ec);};
boost::system::error_code ec;
co_await resp3::async_read(socket_, net::dynamic_buffer(buffer), adapter, net::redirect_error(net::use_awaitable, ec));
on_msg_(ec, command::unknown);
on_msg_(ec, redis::command::unknown);
} else {
auto adapter = [this](type t, std::size_t aggregate_size, std::size_t depth, char const* data, std::size_t size, std::error_code& ec)
{adapter_(commands_.front(), t, aggregate_size, depth, data, size, ec);};
@@ -89,13 +89,13 @@ net::awaitable<void> client::writer()
net::awaitable<void> client::say_hello()
{
std::string request;
auto sr = make_serializer<command>(request);
sr.push(command::hello, 3);
auto sr = redis::make_serializer(request);
sr.push(redis::command::hello, 3);
co_await net::async_write(socket_, net::buffer(request));
std::string buffer;
auto adapter = [this](type t, std::size_t aggregate_size, std::size_t depth, char const* data, std::size_t size, std::error_code& ec)
{adapter_(command::hello, t, aggregate_size, depth, data, size, ec);};
{adapter_(redis::command::hello, t, aggregate_size, depth, data, size, ec);};
co_await resp3::async_read(socket_, net::dynamic_buffer(buffer), adapter);
}

View File

@@ -1,15 +1,14 @@
/* Copyright (c) 2019 - 2021 Marcelo Zimbres Silva (mzimbres at gmail dot com)
/* Copyright (c) 2019 Marcelo Zimbres Silva (mzimbres@gmail.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 <aedis/command.hpp>
#include <cassert>
#include <aedis/redis/command.hpp>
namespace aedis {
namespace redis {
char const* to_string(command c)
{
@@ -242,4 +241,5 @@ bool has_push_response(command cmd)
}
}
} // redis
} // aedis

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2019 - 2021 Marcelo Zimbres Silva (mzimbres at gmail dot com)
/* Copyright (c) 2019 Marcelo Zimbres Silva (mzimbres@gmail.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
@@ -16,7 +16,6 @@
#include <vector>
#include <charconv>
#include <aedis/command.hpp>
#include <aedis/resp3/type.hpp>
#include <aedis/resp3/node.hpp>
#include <aedis/resp3/serializer.hpp>
@@ -85,7 +84,7 @@ private:
Container* result_;
public:
general(Container& c = nullptr): result_(&c) {}
general(Container* c = nullptr): result_(c) {}
/** @brief Function called by the parser when new data has been processed.
*
@@ -122,7 +121,7 @@ private:
Node* result_;
public:
adapter_node(Node& t) : result_(&t) {}
adapter_node(Node* t = nullptr) : result_(t) {}
void
operator()(
@@ -147,7 +146,7 @@ private:
T* result_;
public:
simple(T& t) : result_(&t) {}
simple(T* t = nullptr) : result_(t) {}
void
operator()(
@@ -166,12 +165,6 @@ public:
}
assert(aggregate_size == 1);
if (depth != 0) {
ec == adapter::error::nested_unsupported;
return;
}
from_string(*result_, data, data_size, ec);
}
};
@@ -182,7 +175,7 @@ private:
std::optional<T>* result_;
public:
simple_optional(std::optional<T>& o) : result_(&o) {}
simple_optional(std::optional<T>* o = nullptr) : result_(o) {}
void
operator()(
@@ -226,7 +219,7 @@ private:
Container* result_;
public:
vector(Container& v) : result_{&v} {}
vector(Container* v = nullptr) : result_{v} {}
void
operator()(type t,
@@ -239,7 +232,7 @@ public:
set_on_resp3_error(t, ec);
if (is_aggregate(t)) {
if (depth != 0 || i_ != -1) {
if (i_ != -1) {
ec == adapter::error::nested_unsupported;
return;
}
@@ -248,11 +241,6 @@ public:
result_->resize(m * aggregate_size);
++i_;
} else {
if (depth != 1) {
ec == adapter::error::nested_unsupported;
return;
}
assert(aggregate_size == 1);
from_string(result_->at(i_), data, data_size, ec);
@@ -267,7 +255,7 @@ private:
Container* result_;
public:
list(Container& ref): result_(&ref) {}
list(Container* ref = nullptr): result_(ref) {}
void
operator()(type t,
@@ -306,9 +294,9 @@ private:
Container::iterator hint_;
public:
set(Container& c)
: result_(&c)
, hint_(std::end(c))
set(Container* c = nullptr)
: result_(c)
, hint_(std::end(*c))
{}
void
@@ -350,9 +338,9 @@ private:
bool on_key_ = true;
public:
map(Container& c)
: result_(&c)
, current_(std::end(c))
map(Container* c = nullptr)
: result_(c)
, current_(std::end(*c))
{}
void

View File

@@ -11,8 +11,6 @@
#include <string_view>
#include <utility>
#include <aedis/command.hpp>
namespace aedis {
namespace resp3 {
namespace detail {

View File

@@ -8,9 +8,9 @@
#pragma once
#include <string_view>
#include <aedis/net.hpp>
#include <aedis/resp3/detail/parser.hpp>
#include <aedis/config.hpp>
#include <aedis/resp3/detail/parser.hpp>
#include <boost/core/ignore_unused.hpp>
namespace aedis {

View File

@@ -7,7 +7,7 @@
#pragma once
#include <aedis/net.hpp>
#include <aedis/config.hpp>
#include <aedis/resp3/type.hpp>
#include <aedis/resp3/adapt.hpp>
#include <aedis/resp3/response_traits.hpp>

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2019 - 2021 Marcelo Zimbres Silva (mzimbres at gmail dot com)
/* Copyright (c) 2019 Marcelo Zimbres Silva (mzimbres@gmail.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
@@ -7,7 +7,6 @@
#pragma once
#include <aedis/command.hpp>
#include <aedis/resp3/type.hpp>
#include <aedis/resp3/adapter/detail/adapters.hpp>
@@ -21,7 +20,8 @@
namespace aedis {
namespace resp3 {
/* \brief Traits class for response objects.
/** \brief Traits class for response objects.
* \ingroup classes
*/
template <class T>
struct response_traits
@@ -33,7 +33,7 @@ struct response_traits
using adapter_type = adapter::detail::simple<response_type>;
/// Returns an adapter for the reponse r
static auto adapt(response_type& r) noexcept { return adapter_type{r}; }
static auto adapt(response_type& r) noexcept { return adapter_type{&r}; }
};
template <class T>
@@ -41,7 +41,7 @@ struct response_traits<std::optional<T>>
{
using response_type = std::optional<T>;
using adapter_type = adapter::detail::simple_optional<typename response_type::value_type>;
static auto adapt(response_type& i) noexcept { return adapter_type{i}; }
static auto adapt(response_type& i) noexcept { return adapter_type{&i}; }
};
template <class T, class Allocator>
@@ -49,7 +49,7 @@ struct response_traits<std::vector<T, Allocator>>
{
using response_type = std::vector<T, Allocator>;
using adapter_type = adapter::detail::vector<response_type>;
static auto adapt(response_type& v) noexcept { return adapter_type{v}; }
static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
};
template <>
@@ -57,7 +57,7 @@ struct response_traits<node>
{
using response_type = node;
using adapter_type = adapter::detail::adapter_node<response_type>;
static auto adapt(response_type& v) noexcept { return adapter_type{v}; }
static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
};
template <class Allocator>
@@ -65,7 +65,7 @@ struct response_traits<std::vector<node, Allocator>>
{
using response_type = std::vector<node, Allocator>;
using adapter_type = adapter::detail::general<response_type>;
static auto adapt(response_type& v) noexcept { return adapter_type{v}; }
static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
};
template <class T, class Allocator>
@@ -73,7 +73,7 @@ struct response_traits<std::list<T, Allocator>>
{
using response_type = std::list<T, Allocator>;
using adapter_type = adapter::detail::list<response_type>;
static auto adapt(response_type& v) noexcept { return adapter_type{v}; }
static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
};
template <class T, class Allocator>
@@ -81,7 +81,7 @@ struct response_traits<std::deque<T, Allocator>>
{
using response_type = std::deque<T, Allocator>;
using adapter_type = adapter::detail::list<response_type>;
static auto adapt(response_type& v) noexcept { return adapter_type{v}; }
static auto adapt(response_type& v) noexcept { return adapter_type{&v}; }
};
template <class Key, class Compare, class Allocator>
@@ -89,7 +89,7 @@ struct response_traits<std::set<Key, Compare, Allocator>>
{
using response_type = std::set<Key, Compare, Allocator>;
using adapter_type = adapter::detail::set<response_type>;
static auto adapt(response_type& s) noexcept { return adapter_type{s}; }
static auto adapt(response_type& s) noexcept { return adapter_type{&s}; }
};
template <class Key, class Hash, class KeyEqual, class Allocator>
@@ -97,7 +97,7 @@ struct response_traits<std::unordered_set<Key, Hash, KeyEqual, Allocator>>
{
using response_type = std::unordered_set<Key, Hash, KeyEqual, Allocator>;
using adapter_type = adapter::detail::set<response_type>;
static auto adapt(response_type& s) noexcept { return adapter_type{s}; }
static auto adapt(response_type& s) noexcept { return adapter_type{&s}; }
};
template <class Key, class T, class Compare, class Allocator>
@@ -105,7 +105,7 @@ struct response_traits<std::map<Key, T, Compare, Allocator>>
{
using response_type = std::map<Key, T, Compare, Allocator>;
using adapter_type = adapter::detail::map<response_type>;
static auto adapt(response_type& s) noexcept { return adapter_type{s}; }
static auto adapt(response_type& s) noexcept { return adapter_type{&s}; }
};
template <class Key, class Hash, class KeyEqual, class Allocator>
@@ -113,7 +113,7 @@ struct response_traits<std::unordered_map<Key, Hash, KeyEqual, Allocator>>
{
using response_type = std::unordered_map<Key, Hash, KeyEqual, Allocator>;
using adapter_type = adapter::detail::map<response_type>;
static auto adapt(response_type& s) noexcept { return adapter_type{s}; }
static auto adapt(response_type& s) noexcept { return adapter_type{&s}; }
};
template <>

View File

@@ -7,9 +7,6 @@
#pragma once
#include <string>
#include <aedis/command.hpp>
#include <aedis/resp3/detail/composer.hpp>
namespace aedis {
@@ -159,15 +156,5 @@ public:
}
};
/** \brief Creates a serializer for a \c std::string.
* \ingroup functions
* \param storage The string.
*/
template<class Command>
auto make_serializer(std::string& storage)
{
return serializer<std::string, Command>(storage);
}
} // resp3
} // aedis

View File

@@ -0,0 +1,63 @@
/* Copyright (c) 2019 Marcelo Zimbres Silva (mzimbres@gmail.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/.
*/
#pragma once
#include <ostream>
namespace aedis {
namespace sentinel {
/** \brief Sentinel commands.
* \ingroup enums
*
* For a full list of commands see https://redis.io/topics/sentinel
*
* \remark The list of commands below are read from Redis with the
* help of the command \c command.
*/
enum class command {
acl,
auth,
client,
command,
hello,
info,
ping,
psubscribe,
publish,
punsubscribe,
role,
sentinel,
shutdown,
subscribe,
unsubscribe,
unknown
};
/** \brief Converts a sentinel command to a string
* \ingroup functions
*
* \param c The command to convert.
*/
char const* to_string(command c);
/** \brief Write the text for a sentinel command name to an output stream.
* \ingroup operators
*
* \param os Output stream.
* \param c Sentinel command
*/
std::ostream& operator<<(std::ostream& os, command c);
/** \brief Returns true for sentinel commands with push response.
* \ingroup functions
*/
bool has_push_response(command cmd);
} // sentinel
} // aedis

View File

@@ -0,0 +1,56 @@
/* Copyright (c) 2019 Marcelo Zimbres Silva (mzimbres@gmail.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 <aedis/sentinel/command.hpp>
namespace aedis {
namespace sentinel {
char const* to_string(command c)
{
static char const* table[] = {
"ACL",
"AUTH",
"CLIENT",
"COMMAND",
"HELLO",
"INFO",
"PING",
"PSUBSCRIBE",
"PUBLISH",
"PUNSUBSCRIBE",
"ROLE",
"SENTINEL",
"SHUTDOWN",
"SUBSCRIBE",
"UNSUBSCRIBE",
};
return table[static_cast<int>(c)];
}
std::ostream& operator<<(std::ostream& os, command c)
{
os << to_string(c);
return os;
}
bool has_push_response(command cmd)
{
switch (cmd) {
case command::subscribe:
case command::unsubscribe:
case command::psubscribe:
return true;
default:
return false;
}
}
} // sentinel
} // aedis

View File

@@ -7,8 +7,9 @@
// Include this file in no more than one source file in your application.
#include <aedis/impl/command.ipp>
#include <aedis/redis/impl/command.ipp>
#include <aedis/sentinel/impl/command.ipp>
#include <aedis/resp3/impl/type.ipp>
#include <aedis/resp3/impl/node.ipp>
#include <aedis/resp3/impl/client.ipp>
#include <aedis/redis/experimental/impl/client.ipp>
#include <aedis/resp3/detail/impl/parser.ipp>

View File

@@ -1,5 +1,5 @@
AC_PREREQ([2.69])
AC_INIT([aedis], [1.0.0], [mzimbres@gmail.com])
AC_INIT([aedis], [0.1.0], [mzimbres@gmail.com])
AC_CONFIG_MACRO_DIR([m4])
#AC_CONFIG_SRCDIR([src/aedis.cpp])
AC_CONFIG_HEADERS([config.h])
@@ -18,5 +18,5 @@ AC_CHECK_HEADER_STDBOOL
AC_TYPE_UINT64_T
AC_CHECK_TYPES([ptrdiff_t])
AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([Makefile aedis/config.hpp])
AC_OUTPUT

View File

@@ -8,15 +8,14 @@
#include <iostream>
#include <vector>
#include <aedis/src.hpp>
#include <aedis/aedis.hpp>
#include <aedis/src.hpp>
#include "lib/user_session.hpp"
#include "lib/responses.hpp"
#include "src.hpp"
namespace net = aedis::net;
using aedis::command;
using aedis::redis::command;
using aedis::user_session;
using aedis::user_session_base;
using aedis::resp3::experimental::client;

View File

@@ -8,15 +8,14 @@
#include <iostream>
#include <queue>
#include <aedis/src.hpp>
#include <aedis/aedis.hpp>
#include <aedis/src.hpp>
#include "lib/user_session.hpp"
#include "lib/responses.hpp"
#include "src.hpp"
namespace net = aedis::net;
using aedis::command;
using aedis::redis::command;
using aedis::user_session;
using aedis::user_session_base;
using aedis::resp3::experimental::client;

View File

@@ -10,13 +10,14 @@
#include <map>
#include <unordered_map>
#include <aedis/src.hpp>
#include <aedis/aedis.hpp>
#include "utils.ipp"
#include <aedis/src.hpp>
#include "lib/net_utils.hpp"
namespace resp3 = aedis::resp3;
using aedis::command;
using resp3::make_serializer;
using aedis::redis::command;
using aedis::redis::make_serializer;
using resp3::adapt;
namespace net = aedis::net;
@@ -38,7 +39,7 @@ net::awaitable<void> containers()
// Creates and sends the request.
std::string request;
auto sr = make_serializer<command>(request);
auto sr = make_serializer(request);
sr.push(command::hello, 3);
sr.push(command::flushall);
sr.push_range(command::hset, "key", std::cbegin(map), std::cend(map));

View File

@@ -6,14 +6,15 @@
*/
#include <iostream>
#include <aedis/src.hpp>
#include <aedis/aedis.hpp>
#include "utils.ipp"
#include <aedis/aedis.hpp>
#include <aedis/src.hpp>
#include "lib/net_utils.hpp"
namespace resp3 = aedis::resp3;
using aedis::command;
using resp3::make_serializer;
using aedis::redis::command;
using aedis::redis::make_serializer;
using resp3::adapt;
namespace net = aedis::net;
@@ -38,7 +39,7 @@ net::awaitable<void> ping()
// Creates and sends the request.
std::string request;
auto sr = make_serializer<command>(request);
auto sr = make_serializer(request);
sr.push(command::hello, 3);
sr.push(command::flushall);
sr.push(command::ping);

View File

@@ -11,11 +11,12 @@
#include <aedis/src.hpp>
#include <aedis/aedis.hpp>
#include "utils.ipp"
#include "lib/net_utils.hpp"
namespace resp3 = aedis::resp3;
using aedis::command;
using resp3::make_serializer;
using aedis::redis::command;
using aedis::redis::make_serializer;
using resp3::adapt;
using resp3::node;
@@ -33,7 +34,7 @@ net::awaitable<void> key_expiration()
// Creates and sends the first request.
std::string request;
auto sr = make_serializer<command>(request);
auto sr = make_serializer(request);
sr.push(command::hello, 3);
sr.push(command::flushall);
sr.push(command::set, "key", "Some payload", "EX", "2");

View File

@@ -5,7 +5,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <aedis/net.hpp>
#include <aedis/config.hpp>
using tcp_socket = aedis::net::use_awaitable_t<>::as_default_on_t<aedis::net::ip::tcp::socket>;
using tcp_resolver = aedis::net::use_awaitable_t<>::as_default_on_t<aedis::net::ip::tcp::resolver>;

View File

@@ -10,7 +10,7 @@
#include <aedis/aedis.hpp>
namespace net = aedis::net;
using aedis::command;
using aedis::redis::command;
using aedis::resp3::adapt;
using aedis::resp3::response_traits;
using aedis::resp3::type;
@@ -31,15 +31,40 @@ private:
response_traits<std::vector<node>>::adapter_type general_adapter_;
public:
adapter_wrapper(responses& resps);
adapter_wrapper(responses& resps)
: number_adapter_{adapt(resps.number)}
, str_adapter_{adapt(resps.simple_string)}
, general_adapter_{adapt(resps.general)}
{}
void operator()(
void
operator()(
command cmd,
type t,
std::size_t aggregate_size,
std::size_t depth,
char const* data,
std::size_t size,
std::error_code& ec);
std::error_code& ec)
{
// Handles only the commands we are interested in the examples and
// ignores the rest.
switch (cmd) {
case command::quit:
case command::ping:
str_adapter_(t, aggregate_size, depth, data, size, ec);
return;
case command::incr:
number_adapter_(t, aggregate_size, depth, data, size, ec);
return;
case command::unknown:
general_adapter_(t, aggregate_size, depth, data, size, ec);
return;
default: {} // Ignore.
}
}
};

View File

@@ -1,49 +0,0 @@
/* Copyright (c) 2019 Marcelo Zimbres Silva (mzimbres@gmail.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 "responses.hpp"
namespace net = aedis::net;
using aedis::command;
using aedis::resp3::adapt;
using aedis::resp3::response_traits;
using aedis::resp3::type;
adapter_wrapper::adapter_wrapper(responses& resps)
: number_adapter_{adapt(resps.number)}
, str_adapter_{adapt(resps.simple_string)}
, general_adapter_{adapt(resps.general)}
{}
void adapter_wrapper::operator()(
command cmd,
type t,
std::size_t aggregate_size,
std::size_t depth,
char const* data,
std::size_t size,
std::error_code& ec)
{
// Handles only the commands we are interested in the examples and
// ignores the rest.
switch (cmd) {
case command::quit:
case command::ping:
str_adapter_(t, aggregate_size, depth, data, size, ec);
return;
case command::incr:
number_adapter_(t, aggregate_size, depth, data, size, ec);
return;
case command::unknown:
general_adapter_(t, aggregate_size, depth, data, size, ec);
return;
default: {} // Ignore.
}
}

View File

@@ -9,7 +9,7 @@
#include <functional>
#include <aedis/net.hpp>
#include <aedis/config.hpp>
// An example user session.
@@ -26,14 +26,66 @@ class user_session:
public user_session_base,
public std::enable_shared_from_this<user_session> {
public:
user_session(net::ip::tcp::socket socket);
void start(std::function<void(std::string const&)> on_msg);
void deliver(std::string const& msg);
user_session(net::ip::tcp::socket socket)
: socket_(std::move(socket))
, timer_(socket_.get_executor())
{ timer_.expires_at(std::chrono::steady_clock::time_point::max()); }
void start(std::function<void(std::string const&)> on_msg)
{
co_spawn(socket_.get_executor(),
[self = shared_from_this(), on_msg]{ return self->reader(on_msg); },
net::detached);
co_spawn(socket_.get_executor(),
[self = shared_from_this()]{ return self->writer(); },
net::detached);
}
void deliver(std::string const& msg)
{
write_msgs_.push_back(msg);
timer_.cancel_one();
}
private:
net::awaitable<void> reader(std::function<void(std::string const&)> on_msg);
net::awaitable<void> writer();
void stop();
net::awaitable<void>
reader(std::function<void(std::string const&)> on_msg)
{
try {
for (std::string msg;;) {
auto const n = co_await net::async_read_until(socket_, net::dynamic_buffer(msg, 1024), "\n", net::use_awaitable);
on_msg(msg);
msg.erase(0, n);
}
} catch (std::exception&) {
stop();
}
}
net::awaitable<void> writer()
{
try {
while (socket_.is_open()) {
if (write_msgs_.empty()) {
boost::system::error_code ec;
co_await timer_.async_wait(redirect_error(net::use_awaitable, ec));
} else {
co_await net::async_write(socket_, net::buffer(write_msgs_.front()), net::use_awaitable);
write_msgs_.pop_front();
}
}
} catch (std::exception&) {
stop();
}
}
void stop()
{
socket_.close();
timer_.cancel();
}
net::ip::tcp::socket socket_;
net::steady_timer timer_;
std::deque<std::string> write_msgs_;

View File

@@ -1,72 +0,0 @@
/* Copyright (c) 2019 Marcelo Zimbres Silva (mzimbres@gmail.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 "user_session.hpp"
namespace aedis
{
user_session::user_session(net::ip::tcp::socket socket)
: socket_(std::move(socket))
, timer_(socket_.get_executor())
{ timer_.expires_at(std::chrono::steady_clock::time_point::max()); }
net::awaitable<void> user_session::writer()
{
try {
while (socket_.is_open()) {
if (write_msgs_.empty()) {
boost::system::error_code ec;
co_await timer_.async_wait(redirect_error(net::use_awaitable, ec));
} else {
co_await net::async_write(socket_, net::buffer(write_msgs_.front()), net::use_awaitable);
write_msgs_.pop_front();
}
}
} catch (std::exception&) {
stop();
}
}
void user_session::stop()
{
socket_.close();
timer_.cancel();
}
void user_session::deliver(std::string const& msg)
{
write_msgs_.push_back(msg);
timer_.cancel_one();
}
void user_session::start(std::function<void(std::string const&)> on_msg)
{
co_spawn(socket_.get_executor(),
[self = shared_from_this(), on_msg]{ return self->reader(on_msg); },
net::detached);
co_spawn(socket_.get_executor(),
[self = shared_from_this()]{ return self->writer(); },
net::detached);
}
net::awaitable<void>
user_session::reader(std::function<void(std::string const&)> on_msg)
{
try {
for (std::string msg;;) {
auto const n = co_await net::async_read_until(socket_, net::dynamic_buffer(msg, 1024), "\n", net::use_awaitable);
on_msg(msg);
msg.erase(0, n);
}
} catch (std::exception&) {
stop();
}
}
} // aedis

View File

@@ -11,13 +11,14 @@
#include <list>
#include <deque>
#include <aedis/src.hpp>
#include <aedis/aedis.hpp>
#include "utils.ipp"
#include <aedis/src.hpp>
#include "lib/net_utils.hpp"
namespace resp3 = aedis::resp3;
using aedis::command;
using resp3::make_serializer;
using aedis::redis::command;
using aedis::redis::make_serializer;
using resp3::adapt;
namespace net = aedis::net;
@@ -42,7 +43,7 @@ net::awaitable<void> ping()
// Creates and sends the request.
auto vec = {1, 2, 3, 4, 5, 6};
std::string request;
auto sr = make_serializer<command>(request);
auto sr = make_serializer(request);
sr.push(command::hello, 3);
sr.push(command::flushall);
sr.push_range(command::rpush, "key", std::cbegin(vec), std::cend(vec));

View File

@@ -6,46 +6,72 @@
*/
#include <iostream>
#include <vector>
#include <tuple>
#include <array>
#include <boost/mp11.hpp>
#include <aedis/src.hpp>
#include <aedis/aedis.hpp>
#include "utils.ipp"
#include <aedis/src.hpp>
#include "lib/net_utils.hpp"
namespace resp3 = aedis::resp3;
using aedis::command;
using resp3::make_serializer;
using aedis::redis::command;
using aedis::redis::make_serializer;
using resp3::adapt;
using resp3::node;
using resp3::is_aggregate;
using resp3::response_traits;
using resp3::type;
namespace net = aedis::net;
using net::async_write;
using net::buffer;
using net::dynamic_buffer;
/// Shows how to read nested responses.
net::awaitable<void> nested_response()
// Reads the response to a transaction in a general format that is
// suitable for all kinds of responses, but which users will most
// likely have to convert into their own desired format.
net::awaitable<void> nested_response1()
{
try {
auto socket = co_await connect();
auto list = {"one", "two", "three"};
std::string request;
auto sr = make_serializer<command>(request);
auto sr = make_serializer(request);
sr.push(command::hello, 3);
sr.push(command::flushall);
sr.push(command::multi);
sr.push(command::ping, "Some message");
sr.push(command::incr, "incr-key");
sr.push_range(command::rpush, "list-key", std::cbegin(list), std::cend(list));
sr.push(command::lrange, "list-key", 0, -1);
sr.push(command::exec);
sr.push(command::quit);
co_await async_write(socket, buffer(request));
// Expected responses.
node ping;
std::vector<node> hello;
std::vector<node> exec;
// Reads the response.
std::string buffer;
co_await resp3::async_read(socket, dynamic_buffer(buffer), adapt(hello));
co_await resp3::async_read(socket, dynamic_buffer(buffer));
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // hello
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // flushall
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // multi
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // ping
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // incr
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // rpush
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // lrange
co_await resp3::async_read(socket, dynamic_buffer(buffer), adapt(exec));
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // quit
// Prints the response.
for (auto const& e: hello) std::cout << e << "\n";
std::cout << "General format:\n";
for (auto const& e: exec) std::cout << e << "\n";
} catch (std::exception const& e) {
std::cerr << e.what() << std::endl;
@@ -53,9 +79,148 @@ net::awaitable<void> nested_response()
}
}
template <std::size_t N>
struct helper {
template <class T1, class T2>
static void assign(T1& dest, T2& from)
{
dest[N].template emplace<N>(adapt(std::get<N>(from)));
helper<N - 1>::assign(dest, from);
}
};
template <>
struct helper<0> {
template <class T1, class T2>
static void assign(T1& dest, T2& from)
{
dest[0] = adapt(std::get<0>(from));
}
};
// Same as above but parses the responses directly in their final data
// structures.
//
// WARNING: This example is not interesting for most users, it is an
// adavanced feature meant for people with strong performance need.
template <class T>
using response_traits_t = typename response_traits<T>::adapter_type;
// Adapts the responses above to a read operation.
template <class Tuple>
class flat_transaction_adapter {
private:
using variant_type =
boost::mp11::mp_rename<boost::mp11::mp_transform<response_traits_t, Tuple>, std::variant>;
std::size_t i_ = 0;
std::size_t aggregate_size_ = 0;
std::array<variant_type, std::tuple_size<Tuple>::value> adapters_;
public:
flat_transaction_adapter(Tuple& r)
{ helper<std::tuple_size<Tuple>::value - 1>::assign(adapters_, r); }
void count(type t, std::size_t aggregate_size, std::size_t depth)
{
if (depth == 1) {
if (is_aggregate(t))
aggregate_size_ = aggregate_size;
else
++i_;
return;
}
if (--aggregate_size_ == 0)
++i_;
}
void
operator()(
type t,
std::size_t aggregate_size,
std::size_t depth,
char const* data,
std::size_t size,
std::error_code& ec)
{
if (depth == 0) {
// aggregate_size must be equal to the tuple size. Check
// this and add a new error code.
return; // We are interested in the size of the transaction.
}
std::visit([&](auto& arg){arg(t, aggregate_size, depth, data, size, ec);}, adapters_[i_]);
count(t, aggregate_size, depth);
}
};
template <class Tuple>
auto make_adapter(Tuple& t)
{
return flat_transaction_adapter<Tuple>(t);
}
net::awaitable<void> nested_response2()
{
try {
auto socket = co_await connect();
auto list = {"one", "two", "three"};
std::string request;
auto sr = make_serializer(request);
sr.push(command::hello, 3);
sr.push(command::flushall);
// Adds a transaction
sr.push(command::multi);
sr.push(command::ping, "Some message");
sr.push(command::incr, "incr1-key");
sr.push_range(command::rpush, "list-key", std::cbegin(list), std::cend(list));
sr.push(command::lrange, "list-key", 0, -1);
sr.push(command::incr, "incr2-key");
sr.push(command::exec);
sr.push(command::quit);
co_await async_write(socket, buffer(request));
// Expected responses.
std::tuple<std::string, int, int, std::vector<std::string>, int> execs;
// Reads the response.
std::string buffer;
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // hello
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // flushall
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // multi
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // ping
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // incr
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // rpush
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // lrange
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // incr
co_await resp3::async_read(socket, dynamic_buffer(buffer), make_adapter(execs));
co_await resp3::async_read(socket, dynamic_buffer(buffer)); // quit
// Prints the response to the transaction.
std::cout << "ping: " << std::get<0>(execs) << "\n";
std::cout << "incr1: " << std::get<1>(execs) << "\n";
std::cout << "rpush: " << std::get<2>(execs) << "\n";
std::cout << "lrange: ";
for (auto const& e: std::get<3>(execs)) std::cout << e << " ";
std::cout << "\n";
std::cout << "incr2: " << std::get<4>(execs) << "\n";
} catch (std::exception const& e) {
std::cerr << e.what() << std::endl;
exit(EXIT_FAILURE);
}
}
int main()
{
net::io_context ioc;
co_spawn(ioc, nested_response(), net::detached);
co_spawn(ioc, nested_response1(), net::detached);
co_spawn(ioc, nested_response2(), net::detached);
ioc.run();
}

View File

@@ -11,10 +11,9 @@
#include <aedis/src.hpp>
#include "lib/responses.hpp"
#include "src.hpp"
namespace net = aedis::net;
using aedis::command;
using aedis::redis::command;
using aedis::resp3::experimental::client;
int main()

View File

@@ -8,14 +8,15 @@
#include <iostream>
#include <string_view>
#include <aedis/src.hpp>
#include <aedis/aedis.hpp>
#include "utils.ipp"
#include <aedis/src.hpp>
#include "lib/net_utils.hpp"
namespace resp3 = aedis::resp3;
using aedis::command;
using aedis::redis::command;
using resp3::type;
using resp3::make_serializer;
using aedis::redis::make_serializer;
using resp3::adapt;
namespace net = aedis::net;
@@ -57,7 +58,7 @@ net::awaitable<void> adapter_example()
// Creates and sends the request.
std::string request;
auto sr = make_serializer<command>(request);
auto sr = make_serializer(request);
sr.push(command::hello, 3);
sr.push(command::flushall);
sr.push_range(command::rpush, "key", std::cbegin(list), std::cend(list));

View File

@@ -9,13 +9,14 @@
#include <iostream>
#include <charconv>
#include <aedis/src.hpp>
#include <aedis/aedis.hpp>
#include "utils.ipp"
#include <aedis/src.hpp>
#include "lib/net_utils.hpp"
namespace resp3 = aedis::resp3;
using aedis::command;
using resp3::make_serializer;
using aedis::redis::make_serializer;
using aedis::redis::command;
using resp3::adapt;
namespace net = aedis::net;
@@ -81,7 +82,7 @@ net::awaitable<void> serialization()
mydata obj{21, 22};
std::string request;
auto sr = make_serializer<command>(request);
auto sr = make_serializer(request);
sr.push(command::hello, 3);
sr.push(command::flushall);
sr.push(command::set, "key", obj);

View File

@@ -10,13 +10,14 @@
#include <vector>
#include <unordered_map>
#include <aedis/src.hpp>
#include <aedis/aedis.hpp>
#include "utils.ipp"
#include <aedis/src.hpp>
#include "lib/net_utils.hpp"
namespace resp3 = aedis::resp3;
using aedis::command;
using resp3::make_serializer;
using aedis::redis::command;
using aedis::redis::make_serializer;
using resp3::adapt;
namespace net = aedis::net;
@@ -36,7 +37,7 @@ net::awaitable<void> containers()
// Creates and sends the request.
std::string request;
auto sr = make_serializer<command>(request);
auto sr = make_serializer(request);
sr.push(command::hello, 3);
sr.push(command::flushall);
sr.push_range(command::sadd, "key", std::cbegin(set), std::cend(set));

View File

@@ -1,4 +0,0 @@
#pragma once
#include "lib/user_session.ipp"
#include "lib/responses.ipp"

View File

@@ -8,13 +8,14 @@
#include <iostream>
#include <chrono>
#include <aedis/src.hpp>
#include <aedis/aedis.hpp>
#include "utils.ipp"
#include <aedis/src.hpp>
#include "lib/net_utils.hpp"
namespace resp3 = aedis::resp3;
using aedis::command;
using resp3::make_serializer;
using aedis::redis::command;
using aedis::redis::make_serializer;
using resp3::adapt;
using resp3::node;
@@ -48,7 +49,7 @@ net::awaitable<void> subscriber()
auto socket = co_await connect();
std::string request;
auto sr = make_serializer<command>(request);
auto sr = make_serializer(request);
sr.push(command::hello, "3");
sr.push(command::subscribe, "channel1", "channel2");
co_await async_write(socket, buffer(request));

View File

@@ -7,12 +7,12 @@
#include <iostream>
#include <aedis/src.hpp>
#include <aedis/aedis.hpp>
#include <aedis/src.hpp>
namespace resp3 = aedis::resp3;
using aedis::command;
using aedis::resp3::make_serializer;
using aedis::redis::command;
using aedis::redis::make_serializer;
using aedis::resp3::adapt;
using aedis::resp3::node;
@@ -34,7 +34,7 @@ int main()
connect(socket, res);
std::string request;
auto sr = make_serializer<command>(request);
auto sr = make_serializer(request);
sr.push(command::hello, 3);
sr.push(command::command);
sr.push(command::quit);

View File

@@ -8,8 +8,8 @@
#include <iostream>
#include <map>
#include <aedis/src.hpp>
#include <aedis/aedis.hpp>
#include <aedis/src.hpp>
#include "test_stream.hpp"
#include "check.hpp"
@@ -22,6 +22,8 @@ namespace this_coro = net::this_coro;
using namespace aedis;
using namespace aedis::resp3;
using aedis::redis::command;
using aedis::redis::make_serializer;
std::vector<node> gresp;
@@ -37,7 +39,7 @@ test_general(net::ip::tcp::resolver::results_type const& res)
//----------------------------------
std::string request;
auto sr = make_serializer<command>(request);
auto sr = make_serializer(request);
sr.push(command::hello, 3);
sr.push(command::flushall);
sr.push_range(command::rpush, "a", std::cbegin(list_), std::cend(list_));
@@ -482,7 +484,7 @@ test_set(net::ip::tcp::resolver::results_type const& results)
std::string test_bulk2 = "aaaaa";
std::string request;
auto sr = make_serializer<command>(request);
auto sr = make_serializer(request);
sr.push(command::hello, 3);
sr.push(command::flushall);
sr.push(command::set, "s", test_bulk1);

View File

@@ -9,12 +9,12 @@
#include <algorithm>
#include <cctype>
#include <aedis/src.hpp>
#include <aedis/aedis.hpp>
#include <aedis/src.hpp>
namespace resp3 = aedis::resp3;
using aedis::command;
using resp3::make_serializer;
using aedis::redis::command;
using aedis::redis::make_serializer;
using resp3::adapt;
using resp3::node;
@@ -81,7 +81,7 @@ int main()
connect(socket, res);
std::string request;
auto sr = make_serializer<command>(request);
auto sr = make_serializer(request);
sr.push(command::hello, 3);
sr.push(command::command);
sr.push(command::quit);