Skip to content
This repository was archived by the owner on Apr 6, 2019. It is now read-only.

Commit 599085b

Browse files
committed
add ability to setup its own network module and to use it in place of tacopie
1 parent 119595a commit 599085b

File tree

8 files changed

+234
-21
lines changed

8 files changed

+234
-21
lines changed

includes/cpp_redis/network/redis_connection.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323
#pragma once
2424

2525
#include <functional>
26+
#include <memory>
2627
#include <mutex>
2728
#include <string>
2829
#include <vector>
2930

3031
#include <cpp_redis/builders/reply_builder.hpp>
31-
32-
#include <tacopie/tacopie>
32+
#include <cpp_redis/network/tcp_client_iface.hpp>
3333

3434
#ifndef __CPP_REDIS_READ_SIZE
3535
#define __CPP_REDIS_READ_SIZE 4096
@@ -67,7 +67,7 @@ class redis_connection {
6767

6868
private:
6969
//! receive & disconnection handlers
70-
void tcp_client_receive_handler(const tacopie::tcp_client::read_result& result);
70+
void tcp_client_receive_handler(const tcp_client_iface::read_result& result);
7171
void tcp_client_disconnection_handler(void);
7272

7373
std::string build_command(const std::vector<std::string>& redis_cmd);
@@ -77,7 +77,7 @@ class redis_connection {
7777

7878
private:
7979
//! tcp client for redis connection
80-
tacopie::tcp_client m_client;
80+
std::shared_ptr<cpp_redis::network::tcp_client_iface> m_client;
8181

8282
//! reply callback
8383
reply_callback_t m_reply_callback;
@@ -95,6 +95,8 @@ class redis_connection {
9595
std::mutex m_buffer_mutex;
9696
};
9797

98+
extern std::function<std::shared_ptr<tcp_client_iface>()> get_tcp_client;
99+
98100
} //! network
99101

100102
} //! cpp_redis
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// MIT License
2+
//
3+
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in all
13+
// copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
23+
#pragma once
24+
25+
#include <cpp_redis/network/tcp_client_iface.hpp>
26+
#include <cpp_redis/redis_error.hpp>
27+
28+
#include <tacopie/tacopie>
29+
30+
namespace cpp_redis {
31+
32+
namespace network {
33+
34+
class tcp_client : public tcp_client_iface {
35+
public:
36+
//! ctor & dtor
37+
tcp_client(void) = default;
38+
~tcp_client(void) = default;
39+
40+
public:
41+
//! start & stop the tcp client
42+
void
43+
connect(const std::string& addr, std::uint32_t port) {
44+
m_client.connect(addr, port);
45+
}
46+
47+
void
48+
disconnect(bool wait_for_removal = false) {
49+
m_client.disconnect(wait_for_removal);
50+
}
51+
52+
//! returns whether the client is currently connected or not
53+
bool
54+
is_connected(void) const {
55+
return m_client.is_connected();
56+
}
57+
58+
public:
59+
//! async read & write operations
60+
void
61+
async_read(read_request& request) {
62+
auto callback = std::move(request.async_read_callback);
63+
64+
m_client.async_read({request.size, [=](tacopie::tcp_client::read_result& result) {
65+
if (not callback) {
66+
return;
67+
}
68+
69+
read_result converted_result = {result.success, std::move(result.buffer)};
70+
callback(converted_result);
71+
}});
72+
}
73+
74+
void
75+
async_write(write_request& request) {
76+
auto callback = std::move(request.async_write_callback);
77+
78+
m_client.async_write({std::move(request.buffer), [=](tacopie::tcp_client::write_result& result) {
79+
if (not callback) {
80+
return;
81+
}
82+
83+
write_result converted_result = {result.success, result.size};
84+
callback(converted_result);
85+
}});
86+
}
87+
88+
public:
89+
//! set on disconnection handler
90+
void
91+
set_on_disconnection_handler(const disconnection_handler_t& disconnection_handler) {
92+
m_client.set_on_disconnection_handler(disconnection_handler);
93+
}
94+
95+
private:
96+
//! tcp client for redis connection
97+
tacopie::tcp_client m_client;
98+
};
99+
100+
} //! network
101+
102+
} //! cpp_redis
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// MIT License
2+
//
3+
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in all
13+
// copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
23+
#pragma once
24+
25+
namespace cpp_redis {
26+
27+
namespace network {
28+
29+
class tcp_client_iface {
30+
public:
31+
//! ctor & dtor
32+
tcp_client_iface(void) = default;
33+
virtual ~tcp_client_iface(void) = default;
34+
35+
public:
36+
//! start & stop the tcp client
37+
virtual void connect(const std::string& addr, std::uint32_t port) = 0;
38+
virtual void disconnect(bool wait_for_removal = false) = 0;
39+
40+
//! returns whether the client is currently connected or not
41+
virtual bool is_connected(void) const = 0;
42+
43+
public:
44+
//! structure to store read requests result
45+
struct read_result {
46+
bool success;
47+
std::vector<char> buffer;
48+
};
49+
50+
//! structure to store write requests result
51+
struct write_result {
52+
bool success;
53+
std::size_t size;
54+
};
55+
56+
public:
57+
//! async read & write completion callbacks
58+
typedef std::function<void(read_result&)> async_read_callback_t;
59+
typedef std::function<void(write_result&)> async_write_callback_t;
60+
61+
public:
62+
//! structure to store read requests information
63+
struct read_request {
64+
std::size_t size;
65+
async_read_callback_t async_read_callback;
66+
};
67+
68+
//! structure to store write requests information
69+
struct write_request {
70+
std::vector<char> buffer;
71+
async_write_callback_t async_write_callback;
72+
};
73+
74+
public:
75+
//! async read & write operations
76+
virtual void async_read(read_request& request) = 0;
77+
virtual void async_write(write_request& request) = 0;
78+
79+
public:
80+
//! disconnection handle
81+
typedef std::function<void()> disconnection_handler_t;
82+
83+
//! set on disconnection handler
84+
virtual void set_on_disconnection_handler(const disconnection_handler_t& disconnection_handler) = 0;
85+
};
86+
87+
} //! network
88+
89+
} //! cpp_redis

includes/cpp_redis/redis_client.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#pragma once
2424

25+
#include <atomic>
2526
#include <condition_variable>
2627
#include <functional>
2728
#include <mutex>

sources/network/redis_connection.cpp

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,28 @@
2222

2323
#include <cpp_redis/logger.hpp>
2424
#include <cpp_redis/network/redis_connection.hpp>
25+
#include <cpp_redis/network/tcp_client.hpp>
2526
#include <cpp_redis/redis_error.hpp>
2627

28+
#include <tacopie/tacopie>
29+
2730
namespace cpp_redis {
2831

2932
namespace network {
3033

34+
std::function<std::shared_ptr<tcp_client_iface>()> get_tcp_client = []() -> std::shared_ptr<tcp_client_iface> {
35+
return std::make_shared<tcp_client>();
36+
};
37+
3138
redis_connection::redis_connection(void)
32-
: m_reply_callback(nullptr)
39+
: m_client(get_tcp_client())
40+
, m_reply_callback(nullptr)
3341
, m_disconnection_handler(nullptr) {
3442
__CPP_REDIS_LOG(debug, "cpp_redis::network::redis_connection created");
3543
}
3644

3745
redis_connection::~redis_connection(void) {
38-
m_client.disconnect(true);
46+
m_client->disconnect(true);
3947
__CPP_REDIS_LOG(debug, "cpp_redis::network::redis_connection destroyed");
4048
}
4149

@@ -46,14 +54,17 @@ redis_connection::connect(const std::string& host, std::size_t port,
4654
try {
4755
__CPP_REDIS_LOG(debug, "cpp_redis::network::redis_connection attempts to connect");
4856

49-
//! connect client and start to read asynchronously
50-
m_client.connect(host, port);
51-
m_client.async_read({__CPP_REDIS_READ_SIZE, std::bind(&redis_connection::tcp_client_receive_handler, this, std::placeholders::_1)});
52-
m_client.set_on_disconnection_handler(std::bind(&redis_connection::tcp_client_disconnection_handler, this));
57+
//! connect client
58+
m_client->connect(host, port);
59+
m_client->set_on_disconnection_handler(std::bind(&redis_connection::tcp_client_disconnection_handler, this));
60+
61+
//! start to read asynchronously
62+
tcp_client_iface::read_request request = {__CPP_REDIS_READ_SIZE, std::bind(&redis_connection::tcp_client_receive_handler, this, std::placeholders::_1)};
63+
m_client->async_read(request);
5364

5465
__CPP_REDIS_LOG(debug, "cpp_redis::network::redis_connection connected");
5566
}
56-
catch (const tacopie::tacopie_error& e) {
67+
catch (const std::exception& e) {
5768
__CPP_REDIS_LOG(error, std::string("cpp_redis::network::redis_connection ") + e.what());
5869
throw redis_error(e.what());
5970
}
@@ -65,13 +76,13 @@ redis_connection::connect(const std::string& host, std::size_t port,
6576
void
6677
redis_connection::disconnect(bool wait_for_removal) {
6778
__CPP_REDIS_LOG(debug, "cpp_redis::network::redis_connection attempts to disconnect");
68-
m_client.disconnect(wait_for_removal);
79+
m_client->disconnect(wait_for_removal);
6980
__CPP_REDIS_LOG(debug, "cpp_redis::network::redis_connection disconnected");
7081
}
7182

7283
bool
7384
redis_connection::is_connected(void) {
74-
return m_client.is_connected();
85+
return m_client->is_connected();
7586
}
7687

7788
std::string
@@ -104,9 +115,10 @@ redis_connection::commit(void) {
104115
std::string buffer = std::move(m_buffer);
105116

106117
try {
107-
m_client.async_write({std::vector<char>{buffer.begin(), buffer.end()}, nullptr});
118+
tcp_client_iface::write_request request = {std::vector<char>{buffer.begin(), buffer.end()}, nullptr};
119+
m_client->async_write(request);
108120
}
109-
catch (const tacopie::tacopie_error& e) {
121+
catch (const std::exception& e) {
110122
__CPP_REDIS_LOG(error, std::string("cpp_redis::network::redis_connection ") + e.what());
111123
throw redis_error(e.what());
112124
}
@@ -125,7 +137,7 @@ redis_connection::call_disconnection_handler(void) {
125137
}
126138

127139
void
128-
redis_connection::tcp_client_receive_handler(const tacopie::tcp_client::read_result& result) {
140+
redis_connection::tcp_client_receive_handler(const tcp_client_iface::read_result& result) {
129141
if (!result.success) { return; }
130142

131143
try {
@@ -151,9 +163,10 @@ redis_connection::tcp_client_receive_handler(const tacopie::tcp_client::read_res
151163
}
152164

153165
try {
154-
m_client.async_read({__CPP_REDIS_READ_SIZE, std::bind(&redis_connection::tcp_client_receive_handler, this, std::placeholders::_1)});
166+
tcp_client_iface::read_request request = {__CPP_REDIS_READ_SIZE, std::bind(&redis_connection::tcp_client_receive_handler, this, std::placeholders::_1)};
167+
m_client->async_read(request);
155168
}
156-
catch (const tacopie::tacopie_error&) {
169+
catch (const std::exception&) {
157170
//! Client disconnected in the meantime
158171
}
159172
}

tacopie

tests/sources/spec/redis_client_spec.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@
2020
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
// SOFTWARE.
2222

23+
#include <thread>
24+
2325
#include <cpp_redis/redis_client.hpp>
2426
#include <cpp_redis/redis_error.hpp>
27+
2528
#include <gtest/gtest.h>
2629

2730
TEST(RedisClient, ValidConnectionDefaultParams) {
@@ -46,7 +49,7 @@ TEST(RedisClient, InvalidConnection) {
4649
cpp_redis::redis_client client;
4750

4851
EXPECT_FALSE(client.is_connected());
49-
EXPECT_THROW(client.connect("invalid.url", 1234), cpp_redis::redis_error);
52+
EXPECT_THROW(client.connect("invalid url", 1234), cpp_redis::redis_error);
5053
EXPECT_FALSE(client.is_connected());
5154
}
5255

tests/sources/spec/redis_subscriber_spec.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@
2020
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
// SOFTWARE.
2222

23+
#include <thread>
24+
2325
#include <cpp_redis/redis_client.hpp>
2426
#include <cpp_redis/redis_error.hpp>
2527
#include <cpp_redis/redis_subscriber.hpp>
28+
2629
#include <gtest/gtest.h>
2730

2831
TEST(RedisSubscriber, ValidConnectionDefaultParams) {
@@ -47,7 +50,7 @@ TEST(RedisSubscriber, InvalidConnection) {
4750
cpp_redis::redis_subscriber client;
4851

4952
EXPECT_FALSE(client.is_connected());
50-
EXPECT_THROW(client.connect("invalid.url", 1234), cpp_redis::redis_error);
53+
EXPECT_THROW(client.connect("invalid url", 1234), cpp_redis::redis_error);
5154
EXPECT_FALSE(client.is_connected());
5255
}
5356

0 commit comments

Comments
 (0)