mirror of
https://github.com/boostorg/redis.git
synced 2026-01-19 04:42:09 +00:00
Simplifications.
This commit is contained in:
@@ -83,7 +83,6 @@ nobase_include_HEADERS =\
|
||||
|
||||
nobase_noinst_HEADERS =\
|
||||
$(top_srcdir)/examples/lib/net_utils.hpp\
|
||||
$(top_srcdir)/examples/lib/responses.hpp\
|
||||
$(top_srcdir)/examples/lib/user_session.hpp\
|
||||
$(top_srcdir)/tests/check.hpp\
|
||||
$(top_srcdir)/tests/test_stream.hpp
|
||||
|
||||
54
README.md
54
README.md
@@ -1,53 +1 @@
|
||||
# Aedis
|
||||
|
||||
Aedis is a redis client designed for scalability and performance while
|
||||
providing an easy and intuitive interface.
|
||||
|
||||
## Example
|
||||
|
||||
Lets us see some examples with increasing order of complexity.
|
||||
See the `examples` directory for more examples.
|
||||
|
||||
### Ping
|
||||
|
||||
A very simple example with illustrative purposes. The example above
|
||||
will start writing the `hello` command and proceed reading its
|
||||
response. After that users can add further commands to the queue. See
|
||||
the example directory for a complete example.
|
||||
|
||||
|
||||
```cpp
|
||||
net::awaitable<void> ping2()
|
||||
{
|
||||
auto socket = co_await make_connection();
|
||||
resp3::stream<tcp_socket> stream{std::move(socket)};
|
||||
|
||||
resp3::request req;
|
||||
req.push(command::hello, 3);
|
||||
req.push(command::ping);
|
||||
req.push(command::quit);
|
||||
co_await stream.async_write(req);
|
||||
|
||||
while (!std::empty(req.commands)) {
|
||||
resp3::response resp;
|
||||
co_await stream.async_read(resp);
|
||||
req.commands.pop();
|
||||
std::cout << resp << std::endl;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
This library is header only. To install it run
|
||||
|
||||
```cpp
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
or copy the include folder to where you want. You will also need to include
|
||||
the following header in one of your source files e.g. `aedis.cpp`
|
||||
|
||||
```cpp
|
||||
#include <aedis/impl/src.hpp>
|
||||
```
|
||||
See https://mzimbres.github.io/aedis/
|
||||
|
||||
@@ -162,7 +162,7 @@
|
||||
* - \b Redis-client: used in on example.
|
||||
* - \b Redis \b Sentinel \b server: used in some examples.
|
||||
*
|
||||
* \section Installing
|
||||
* \section Installation
|
||||
*
|
||||
* Get the latest release and follow the steps
|
||||
*
|
||||
@@ -197,6 +197,12 @@
|
||||
* $ make check
|
||||
* ```
|
||||
*
|
||||
* \subsection Windows
|
||||
*
|
||||
* Windows users can use aedis by either adding the project root
|
||||
* directory to their include path or manually copying to another
|
||||
* location.
|
||||
*
|
||||
* \section using Using Aedis
|
||||
*
|
||||
* This library in not header-only. You have to include the following
|
||||
|
||||
@@ -59,11 +59,11 @@ private:
|
||||
// next message in the output queue.
|
||||
net::steady_timer timer_;
|
||||
|
||||
// Response adapter. TODO: Set a default adapter.
|
||||
adapter_type adapter_;
|
||||
// Response adapter.
|
||||
adapter_type adapter_ = [](redis::command, type, std::size_t, std::size_t, char const*, std::size_t, std::error_code&) {};
|
||||
|
||||
// Message callback. TODO: Set a default callback.
|
||||
on_message_type on_msg_;
|
||||
// Message callback.
|
||||
on_message_type on_msg_ = [](std::error_code ec, redis::command) {};
|
||||
|
||||
// A coroutine that keeps reading the socket. When a message
|
||||
// arrives it calls on_message.
|
||||
|
||||
@@ -39,7 +39,13 @@ namespace resp3 {
|
||||
* to_string, which must be made available over ADL.
|
||||
*/
|
||||
|
||||
// TODO: Add an overload for containers.
|
||||
// NOTE: Consider adding an overload for containers.
|
||||
//
|
||||
// TODO: Should we detect any std::pair or tuple in the type in the parameter
|
||||
// pack to calculate the header size correctly?
|
||||
//
|
||||
// NOTE: For some commands like hset it would be a good idea to assert
|
||||
// the value type is a pair.
|
||||
template <class Storage, class Command>
|
||||
class serializer {
|
||||
private:
|
||||
@@ -73,9 +79,6 @@ public:
|
||||
template <class... Ts>
|
||||
void push(Command cmd, Ts const&... args)
|
||||
{
|
||||
// TODO: Should we detect any std::pair in the type in the pack
|
||||
// to calculate the header size correctly?
|
||||
|
||||
auto constexpr pack_size = sizeof...(Ts);
|
||||
detail::add_header(*request_, 1 + pack_size);
|
||||
|
||||
@@ -106,9 +109,6 @@ public:
|
||||
template <class Key, class ForwardIterator>
|
||||
void push_range(Command cmd, Key const& key, ForwardIterator begin, ForwardIterator end)
|
||||
{
|
||||
// Note: For some commands like hset it would helpful to users
|
||||
// to assert the value type is a pair.
|
||||
|
||||
using value_type = typename std::iterator_traits<ForwardIterator>::value_type;
|
||||
|
||||
auto constexpr size = detail::value_type_size<value_type>::size;
|
||||
@@ -141,9 +141,6 @@ public:
|
||||
template <class ForwardIterator>
|
||||
void push_range(Command cmd, ForwardIterator begin, ForwardIterator end)
|
||||
{
|
||||
// Note: For some commands like hset it would be a good idea to assert
|
||||
// the value type is a pair.
|
||||
|
||||
using value_type = typename std::iterator_traits<ForwardIterator>::value_type;
|
||||
|
||||
auto constexpr size = detail::value_type_size<value_type>::size;
|
||||
|
||||
@@ -58,7 +58,7 @@ PROJECT_LOGO =
|
||||
# entered, it will be relative to the location where doxygen was started. If
|
||||
# left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY = /tmp/aedis
|
||||
OUTPUT_DIRECTORY = /home/marcelo/my/aedis-gh-pages
|
||||
|
||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
|
||||
# directories (in 2 levels) under the output directory of each output format and
|
||||
@@ -1170,7 +1170,7 @@ GENERATE_HTML = YES
|
||||
# The default directory is: html.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_OUTPUT = html
|
||||
HTML_OUTPUT = .
|
||||
|
||||
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
|
||||
# generated HTML page (for example: .htm, .php, .asp).
|
||||
|
||||
@@ -12,26 +12,24 @@
|
||||
#include <aedis/src.hpp>
|
||||
|
||||
#include "lib/user_session.hpp"
|
||||
#include "lib/responses.hpp"
|
||||
|
||||
namespace net = aedis::net;
|
||||
using aedis::redis::command;
|
||||
using aedis::resp3::adapt;
|
||||
using aedis::resp3::experimental::client;
|
||||
using aedis::resp3::node;
|
||||
using aedis::resp3::type;
|
||||
using aedis::user_session;
|
||||
using aedis::user_session_base;
|
||||
using aedis::resp3::experimental::client;
|
||||
|
||||
// TODO: Delete sessions that have expired.
|
||||
class receiver : public std::enable_shared_from_this<receiver> {
|
||||
public:
|
||||
private:
|
||||
responses resps_;
|
||||
std::vector<node> resps_;
|
||||
std::vector<std::weak_ptr<user_session_base>> sessions_;
|
||||
|
||||
public:
|
||||
auto get_adapter()
|
||||
{ return adapter_wrapper{resps_}; }
|
||||
|
||||
auto add(std::shared_ptr<user_session_base> session)
|
||||
{ sessions_.push_back(session); }
|
||||
|
||||
void on_message(std::error_code ec, command cmd)
|
||||
{
|
||||
if (ec) {
|
||||
@@ -42,24 +40,33 @@ public:
|
||||
switch (cmd) {
|
||||
case command::incr:
|
||||
{
|
||||
std::cout << "Message so far: " << resps_.number << std::endl;
|
||||
std::cout << "Message so far: " << resps_.front().data << std::endl;
|
||||
} break;
|
||||
case command::unknown: // Push
|
||||
{
|
||||
// TODO: Delete sessions lazily on traversal.
|
||||
for (auto& weak: sessions_) {
|
||||
if (auto session = weak.lock()) {
|
||||
session->deliver(resps_.general.at(3).data);
|
||||
session->deliver(resps_.at(3).data);
|
||||
} else {
|
||||
std::cout << "Session expired." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
resps_.general.clear();
|
||||
} break;
|
||||
default: { /* Ignore */ }
|
||||
}
|
||||
|
||||
resps_.clear();
|
||||
}
|
||||
|
||||
auto get_adapter()
|
||||
{
|
||||
return [adapter = adapt(resps_)](command, type t, std::size_t aggregate_size, std::size_t depth, char const* data, std::size_t size, std::error_code& ec) mutable
|
||||
{ return adapter(t, aggregate_size, depth, data, size, ec); };
|
||||
}
|
||||
|
||||
auto add(std::shared_ptr<user_session_base> session)
|
||||
{ sessions_.push_back(session); }
|
||||
};
|
||||
|
||||
net::awaitable<void> listener()
|
||||
|
||||
@@ -7,31 +7,28 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
#include <aedis/aedis.hpp>
|
||||
#include <aedis/src.hpp>
|
||||
|
||||
#include "lib/user_session.hpp"
|
||||
#include "lib/responses.hpp"
|
||||
|
||||
namespace net = aedis::net;
|
||||
using aedis::redis::command;
|
||||
using aedis::user_session;
|
||||
using aedis::user_session_base;
|
||||
using aedis::resp3::node;
|
||||
using aedis::resp3::adapt;
|
||||
using aedis::resp3::experimental::client;
|
||||
using aedis::resp3::type;
|
||||
|
||||
class receiver : public std::enable_shared_from_this<receiver> {
|
||||
private:
|
||||
responses resps_;
|
||||
std::vector<node> resps_;
|
||||
std::queue<std::weak_ptr<user_session_base>> sessions_;
|
||||
|
||||
public:
|
||||
auto get_adapter()
|
||||
{ return adapter_wrapper{resps_}; }
|
||||
|
||||
void add_user_session(std::shared_ptr<user_session_base> session)
|
||||
{ sessions_.push(session); }
|
||||
|
||||
void on_message(std::error_code ec, command cmd)
|
||||
{
|
||||
if (ec) {
|
||||
@@ -43,21 +40,31 @@ public:
|
||||
case command::ping:
|
||||
{
|
||||
if (auto session = sessions_.front().lock()) {
|
||||
session->deliver(resps_.simple_string);
|
||||
session->deliver(resps_.front().data);
|
||||
} else {
|
||||
std::cout << "Session expired." << std::endl;
|
||||
}
|
||||
|
||||
sessions_.pop();
|
||||
resps_.simple_string.clear();
|
||||
} break;
|
||||
case command::incr:
|
||||
{
|
||||
std::cout << "Echos so far: " << resps_.number << std::endl;
|
||||
std::cout << "Echos so far: " << resps_.front().data << std::endl;
|
||||
} break;
|
||||
default: { assert(false); }
|
||||
}
|
||||
|
||||
resps_.clear();
|
||||
}
|
||||
|
||||
auto get_adapter()
|
||||
{
|
||||
return [adapter = adapt(resps_)](command, type t, std::size_t aggregate_size, std::size_t depth, char const* data, std::size_t size, std::error_code& ec) mutable
|
||||
{ return adapter(t, aggregate_size, depth, data, size, ec); };
|
||||
}
|
||||
|
||||
void add_user_session(std::shared_ptr<user_session_base> session)
|
||||
{ sessions_.push(session); }
|
||||
};
|
||||
|
||||
net::awaitable<void> listener()
|
||||
|
||||
@@ -1,70 +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/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aedis/aedis.hpp>
|
||||
|
||||
namespace net = aedis::net;
|
||||
using aedis::redis::command;
|
||||
using aedis::resp3::adapt;
|
||||
using aedis::resp3::response_traits;
|
||||
using aedis::resp3::type;
|
||||
using aedis::resp3::node;
|
||||
|
||||
// Groups the responses used in the examples.
|
||||
struct responses {
|
||||
int number;
|
||||
std::string simple_string;
|
||||
std::vector<node> general;
|
||||
};
|
||||
|
||||
// Adpter as required by experimental::client.
|
||||
class adapter_wrapper {
|
||||
private:
|
||||
response_traits<int>::adapter_type number_adapter_;
|
||||
response_traits<std::string>::adapter_type str_adapter_;
|
||||
response_traits<std::vector<node>>::adapter_type general_adapter_;
|
||||
|
||||
public:
|
||||
adapter_wrapper(responses& resps)
|
||||
: number_adapter_{adapt(resps.number)}
|
||||
, str_adapter_{adapt(resps.simple_string)}
|
||||
, general_adapter_{adapt(resps.general)}
|
||||
{}
|
||||
|
||||
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)
|
||||
{
|
||||
// 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.
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,16 +10,16 @@
|
||||
#include <aedis/aedis.hpp>
|
||||
#include <aedis/src.hpp>
|
||||
|
||||
#include "lib/responses.hpp"
|
||||
|
||||
namespace net = aedis::net;
|
||||
using aedis::redis::command;
|
||||
using aedis::resp3::experimental::client;
|
||||
using aedis::resp3::node;
|
||||
using aedis::resp3::type;
|
||||
|
||||
int main()
|
||||
{
|
||||
try {
|
||||
responses resps;
|
||||
std::vector<node> resps;
|
||||
|
||||
auto on_msg = [&resps](std::error_code ec, command cmd)
|
||||
{
|
||||
@@ -28,29 +28,19 @@ int main()
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case command::ping:
|
||||
{
|
||||
std::cout << "ping: " << resps.simple_string << std::endl;
|
||||
resps.simple_string.clear();
|
||||
} break;
|
||||
case command::quit:
|
||||
{
|
||||
std::cout << "quit: " << resps.simple_string << std::endl;
|
||||
resps.simple_string.clear();
|
||||
} break;
|
||||
case command::incr:
|
||||
{
|
||||
std::cout << "incr: " << resps.number << std::endl;
|
||||
} break;
|
||||
default: { assert(false); }
|
||||
}
|
||||
std::cout << cmd << ": " << resps.front().data << std::endl;
|
||||
resps.clear();
|
||||
};
|
||||
|
||||
net::io_context ioc{1};
|
||||
|
||||
// This adapter uses the general response that is suitable for
|
||||
// all commands, so the command parameter will be ignored.
|
||||
auto adapter = [adapter = adapt(resps)](command, type t, std::size_t aggregate_size, std::size_t depth, char const* data, std::size_t size, std::error_code& ec) mutable
|
||||
{ return adapter(t, aggregate_size, depth, data, size, ec); };
|
||||
|
||||
auto db = std::make_shared<client>(ioc.get_executor());
|
||||
db->set_adapter(adapter_wrapper{resps});
|
||||
db->set_adapter(adapter);
|
||||
db->set_msg_callback(on_msg);
|
||||
db->send(command::ping, "O rato roeu a roupa do rei de Roma");
|
||||
db->send(command::incr, "redis-client-counter");
|
||||
|
||||
Reference in New Issue
Block a user