mirror of
https://github.com/boostorg/redis.git
synced 2026-01-19 04:42:09 +00:00
Adds serialization example.
This commit is contained in:
@@ -15,6 +15,7 @@ check_PROGRAMS =
|
||||
check_PROGRAMS += intro_sync
|
||||
check_PROGRAMS += intro
|
||||
check_PROGRAMS += containers
|
||||
check_PROGRAMS += serialization
|
||||
check_PROGRAMS += adapter
|
||||
check_PROGRAMS += test_low_level
|
||||
if HAVE_CXX20
|
||||
@@ -27,7 +28,6 @@ EXTRA_PROGRAMS += commands
|
||||
if HAVE_CXX20
|
||||
EXTRA_PROGRAMS += echo_server
|
||||
EXTRA_PROGRAMS += echo_server_direct
|
||||
EXTRA_PROGRAMS += echo_server_over_redis
|
||||
EXTRA_PROGRAMS += chat_room
|
||||
EXTRA_PROGRAMS += echo_server_client
|
||||
endif
|
||||
@@ -44,12 +44,12 @@ subscriber_SOURCES = $(top_srcdir)/examples/subscriber.cpp
|
||||
test_low_level_SOURCES = $(top_srcdir)/tests/low_level.cpp
|
||||
intro_SOURCES = $(top_srcdir)/examples/intro.cpp
|
||||
containers_SOURCES = $(top_srcdir)/examples/containers.cpp
|
||||
serialization_SOURCES = $(top_srcdir)/examples/serialization.cpp
|
||||
adapter_SOURCES = $(top_srcdir)/examples/adapter.cpp
|
||||
if HAVE_CXX20
|
||||
test_high_level_SOURCES = $(top_srcdir)/tests/high_level.cpp
|
||||
chat_room_SOURCES = $(top_srcdir)/examples/chat_room.cpp
|
||||
echo_server_SOURCES = $(top_srcdir)/examples/echo_server.cpp
|
||||
echo_server_over_redis_SOURCES = $(top_srcdir)/benchmarks/cpp/echo_server_over_redis.cpp
|
||||
echo_server_direct_SOURCES = $(top_srcdir)/benchmarks/cpp/echo_server_direct.cpp
|
||||
echo_server_client_SOURCES = $(top_srcdir)/benchmarks/cpp/echo_server_client.cpp
|
||||
endif
|
||||
@@ -82,7 +82,6 @@ nobase_include_HEADERS =\
|
||||
|
||||
nobase_noinst_HEADERS =\
|
||||
$(top_srcdir)/examples/print.hpp\
|
||||
$(top_srcdir)/examples/mystruct.hpp\
|
||||
$(top_srcdir)/tests/check.hpp
|
||||
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/* Copyright (c) 2018-2022 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <boost/asio.hpp>
|
||||
#include <aedis/aedis.hpp>
|
||||
#include <aedis/src.hpp>
|
||||
|
||||
namespace net = boost::asio;
|
||||
using aedis::adapt;
|
||||
using aedis::command;
|
||||
using aedis::resp3::request;
|
||||
using tcp_socket = net::use_awaitable_t<>::as_default_on_t<net::ip::tcp::socket>;
|
||||
using tcp_acceptor = net::use_awaitable_t<>::as_default_on_t<net::ip::tcp::acceptor>;
|
||||
using connection = aedis::connection<tcp_socket>;
|
||||
|
||||
net::awaitable<void> echo_loop(tcp_socket socket, std::shared_ptr<connection> db)
|
||||
{
|
||||
try {
|
||||
for (std::string buffer;;) {
|
||||
auto n = co_await net::async_read_until(socket, net::dynamic_buffer(buffer, 1024), "\n");
|
||||
request req;
|
||||
req.push(command::ping, buffer);
|
||||
std::tuple<std::string> resp;
|
||||
co_await db->async_exec(req, adapt(resp));
|
||||
co_await net::async_write(socket, net::buffer(std::get<0>(resp)));
|
||||
buffer.erase(0, n);
|
||||
}
|
||||
} catch (std::exception const& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
net::awaitable<void> listener(bool coalesce_requests)
|
||||
{
|
||||
auto ex = co_await net::this_coro::executor;
|
||||
connection::config cfg;
|
||||
cfg.coalesce_requests = coalesce_requests;
|
||||
auto db = std::make_shared<connection>(ex, cfg);
|
||||
db->async_run("127.0.0.1", "6379", net::detached);
|
||||
|
||||
tcp_acceptor acc(ex, {net::ip::tcp::v4(), 55555});
|
||||
for (;;)
|
||||
net::co_spawn(ex, echo_loop(co_await acc.async_accept(), db), net::detached);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
try {
|
||||
net::io_context ioc;
|
||||
co_spawn(ioc, listener(argc == 1), net::detached);
|
||||
ioc.run();
|
||||
} catch (std::exception const& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,11 @@
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <boost/asio.hpp>
|
||||
#include <aedis/aedis.hpp>
|
||||
#include <aedis/src.hpp>
|
||||
#include "print.hpp"
|
||||
#include "mystruct.hpp"
|
||||
|
||||
namespace net = boost::asio;
|
||||
using boost::optional;
|
||||
@@ -21,54 +18,39 @@ using aedis::command;
|
||||
using aedis::resp3::request;
|
||||
using connection = aedis::connection<>;
|
||||
|
||||
// Response used in this example.
|
||||
using C1 = std::vector<int>;
|
||||
using C2 = std::set<mystruct>;
|
||||
using C3 = std::map<std::string, std::string>;
|
||||
|
||||
auto handler =[](auto ec, auto...)
|
||||
{ std::cout << ec.message() << std::endl; };
|
||||
|
||||
int main()
|
||||
{
|
||||
net::io_context ioc;
|
||||
connection db{ioc};
|
||||
std::vector<int> vec
|
||||
{1, 2, 3, 4, 5, 6};
|
||||
|
||||
// Request that sends the containers.
|
||||
C1 vec {1, 2, 3, 4, 5, 6};
|
||||
C2 set {{1, "one"}, {2, "two"}, {3, "three"}, {4, "four"}};
|
||||
C3 map {{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
|
||||
std::map<std::string, int> map
|
||||
{{"key1", 10}, {"key2", 20}, {"key3", 30}};
|
||||
|
||||
request req1;
|
||||
req1.push_range(command::rpush, "rpush-key", vec);
|
||||
req1.push_range(command::sadd, "sadd-key", set);
|
||||
req1.push_range(command::hset, "hset-key", map);
|
||||
|
||||
// Request that retrieves the containers.
|
||||
request req2;
|
||||
req2.push(command::multi);
|
||||
req2.push(command::lrange, "rpush-key", 0, -1);
|
||||
req2.push(command::smembers, "sadd-key");
|
||||
req2.push(command::hgetall, "hset-key");
|
||||
req2.push(command::exec);
|
||||
req2.push(command::quit);
|
||||
request req;
|
||||
req.push_range(command::rpush, "rpush-key", vec);
|
||||
req.push_range(command::hset, "hset-key", map);
|
||||
req.push(command::multi);
|
||||
req.push(command::lrange, "rpush-key", 0, -1);
|
||||
req.push(command::hgetall, "hset-key");
|
||||
req.push(command::exec);
|
||||
req.push(command::quit);
|
||||
|
||||
std::tuple<
|
||||
std::string, // rpush
|
||||
std::string, // hset
|
||||
std::string, // multi
|
||||
std::string, // lrange
|
||||
std::string, // smembers
|
||||
std::string, // hgetall
|
||||
std::tuple<optional<C1>, optional<C2>, optional<C3>>, // exec
|
||||
std::tuple<optional<std::vector<int>>, optional<std::map<std::string, int>>>, // exec
|
||||
std::string // quit
|
||||
> resp;
|
||||
|
||||
db.async_exec(req1, aedis::adapt(), handler);
|
||||
db.async_exec(req2, aedis::adapt(resp), handler);
|
||||
db.async_run("127.0.0.1", "6379", handler);
|
||||
net::io_context ioc;
|
||||
connection db{ioc};
|
||||
db.async_exec("127.0.0.1", "6379", req, aedis::adapt(resp),
|
||||
[](auto ec, auto) { std::cout << ec.message() << std::endl; });
|
||||
ioc.run();
|
||||
|
||||
auto const& r = std::get<4>(resp);
|
||||
print(std::get<0>(r).value());
|
||||
print(std::get<1>(r).value());
|
||||
print(std::get<2>(r).value());
|
||||
print(std::get<0>(std::get<5>(resp)).value());
|
||||
print(std::get<1>(std::get<5>(resp)).value());
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ int main()
|
||||
|
||||
ioc.run();
|
||||
|
||||
// Print
|
||||
std::cout << std::get<0>(resp) << std::endl;
|
||||
std::cout << std::get<1>(resp) << std::endl;
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/* Copyright (c) 2018-2022 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <aedis/aedis.hpp>
|
||||
|
||||
// Arbitrary struct to de/serialize.
|
||||
struct mystruct {
|
||||
std::int32_t x;
|
||||
std::string y;
|
||||
};
|
||||
|
||||
// TODO: Use json instead.
|
||||
// Serializes mystruct
|
||||
void to_bulk(std::string& to, mystruct const& obj)
|
||||
{
|
||||
using aedis::resp3::type;
|
||||
using aedis::resp3::add_header;
|
||||
using aedis::resp3::add_separator;
|
||||
|
||||
auto const size = sizeof obj.x + obj.y.size();
|
||||
add_header(to, type::blob_string, size);
|
||||
auto const* p = reinterpret_cast<char const*>(&obj.x);
|
||||
std::copy(p, p + sizeof obj.x, std::back_inserter(to));
|
||||
std::copy(std::cbegin(obj.y), std::cend(obj.y), std::back_inserter(to));
|
||||
add_separator(to);
|
||||
}
|
||||
|
||||
// Deserialize the struct.
|
||||
void from_string(mystruct& obj, boost::string_view sv, boost::system::error_code& ec)
|
||||
{
|
||||
char* p = reinterpret_cast<char*>(&obj.x);
|
||||
std::copy(std::cbegin(sv), std::cbegin(sv) + sizeof obj.x, p);
|
||||
std::copy(std::cbegin(sv) + sizeof obj.x, std::cend(sv), std::back_inserter(obj.y));
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, mystruct const& obj)
|
||||
{
|
||||
os << "x: " << obj.x << ", y: " << obj.y;
|
||||
return os;
|
||||
}
|
||||
|
||||
bool operator<(mystruct const& a, mystruct const& b)
|
||||
{
|
||||
return std::tie(a.x, a.y) < std::tie(b.x, b.y);
|
||||
}
|
||||
|
||||
@@ -39,11 +39,11 @@ void print(std::vector<T> const& cont)
|
||||
template <class T>
|
||||
void print(std::set<T> const& cont)
|
||||
{
|
||||
for (auto const& e: cont) std::cout << e << " ";
|
||||
std::cout << "\n";
|
||||
for (auto const& e: cont) std::cout << e << "\n";
|
||||
}
|
||||
|
||||
void print(std::map<std::string, std::string> const& cont)
|
||||
template <class T, class U>
|
||||
void print(std::map<T, U> const& cont)
|
||||
{
|
||||
for (auto const& e: cont)
|
||||
std::cout << e.first << ": " << e.second << "\n";
|
||||
|
||||
Reference in New Issue
Block a user