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

Commit a73f286

Browse files
YiuRULECylix
authored andcommitted
[3.5.4] Add implementation for the CLIENT KILL command (#91)
* Add implementation for the CLIENT KILL command * ensure compatibility for client_kill for g++ 4.8 * Clang-Format, code style consistency and move .hpp into ipp to remove inheritance. * windows compilation * clang-format * temporarily revert to older version of CMake as master branch of CMake is broken
1 parent 356ce7f commit a73f286

File tree

7 files changed

+356
-4
lines changed

7 files changed

+356
-4
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ IF (BUILD_TESTS)
188188
add_subdirectory(tests)
189189
ExternalProject_Add("googletest"
190190
GIT_REPOSITORY "https://github.com/google/googletest.git"
191+
GIT_TAG "461713fec4603806d2049835c0790bf94d2db631"
191192
CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${PROJECT_SOURCE_DIR}/deps")
192193
# Reset variable to false to ensure tacopie does no build tests
193194
set (BUILD_TESTS false)

examples/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,6 @@ target_link_libraries(cpp_redis_subscriber cpp_redis)
5454

5555
add_executable(cpp_redis_logger logger.cpp)
5656
target_link_libraries(cpp_redis_logger cpp_redis)
57+
58+
add_executable(kill_client kill_client.cpp)
59+
target_link_libraries(kill_client cpp_redis)

examples/kill_client.cpp

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2015-2017 Simon Ninon <[email protected]>
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+
#include <cpp_redis/cpp_redis>
24+
25+
#include <iostream>
26+
#include <sstream>
27+
28+
#ifdef _WIN32
29+
#include <Winsock2.h>
30+
#endif /* _WIN32 */
31+
32+
int
33+
main(void) {
34+
#ifdef _WIN32
35+
//! Windows netword DLL init
36+
WORD version = MAKEWORD(2, 2);
37+
WSADATA data;
38+
39+
if (WSAStartup(version, &data) != 0) {
40+
std::cerr << "WSAStartup() failure" << std::endl;
41+
return -1;
42+
}
43+
#endif /* _WIN32 */
44+
45+
cpp_redis::redis_client client;
46+
47+
client.connect("127.0.0.1", 6379, [](cpp_redis::redis_client&) {
48+
std::cout << "client disconnected (disconnection handler)" << std::endl;
49+
});
50+
51+
//! client kill ip:port
52+
client.client_list([&client](cpp_redis::reply& reply) {
53+
std::string addr;
54+
std::stringstream ss(reply.as_string());
55+
56+
ss >> addr >> addr;
57+
58+
std::string host = std::string(addr.begin() + addr.find('=') + 1, addr.begin() + addr.find(':'));
59+
int port = std::stoi(std::string(addr.begin() + addr.find(':') + 1, addr.end()));
60+
61+
client.client_kill(host, port, [](cpp_redis::reply& reply) {
62+
std::cout << reply << std::endl; //! OK
63+
});
64+
65+
client.commit();
66+
});
67+
68+
client.sync_commit();
69+
std::this_thread::sleep_for(std::chrono::seconds(1));
70+
71+
if (!client.is_connected()) {
72+
client.connect("127.0.0.1", 6379, [](cpp_redis::redis_client&) {
73+
std::cout << "client disconnected (disconnection handler)" << std::endl;
74+
});
75+
}
76+
77+
//! client kill filter
78+
client.client_list([&client](cpp_redis::reply& reply) {
79+
std::string id_str;
80+
std::stringstream ss(reply.as_string());
81+
82+
ss >> id_str;
83+
84+
uint64_t id = std::stoi(std::string(id_str.begin() + id_str.find('=') + 1, id_str.end()));
85+
client.client_kill(id, false, cpp_redis::redis_client::client_type::normal, [](cpp_redis::reply& reply) {
86+
std::cout << reply << std::endl; //! 1
87+
});
88+
89+
client.commit();
90+
});
91+
92+
client.sync_commit();
93+
std::this_thread::sleep_for(std::chrono::seconds(1));
94+
95+
#ifdef _WIN32
96+
WSACleanup();
97+
#endif /* _WIN32 */
98+
99+
return 0;
100+
}

includes/cpp_redis/future_client.hpp

+16-2
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ class future_client {
9393
future blpop(const std::vector<std::string>& keys, int timeout);
9494
future brpop(const std::vector<std::string>& keys, int timeout);
9595
future brpoplpush(const std::string& src, const std::string& dst, int timeout);
96-
// future client_kill() [ip:port] [id client-id] [type normal|master|slave|pubsub] [addr ip:port] [skipme yes/no]
96+
template <typename T, typename... Ts>
97+
future client_kill(const T, const Ts...);
9798
future client_list();
9899
future client_getname();
99100
future client_pause(int timeout);
@@ -305,4 +306,17 @@ class future_client {
305306
redis_client m_client;
306307
};
307308

308-
} //! cpp_redis
309+
310+
template <typename T, typename... Ts>
311+
future_client::future
312+
future_client::client_kill(const T arg, const Ts... args) {
313+
314+
//! gcc 4.8 doesn't handle variadic template capture arguments (appears in 4.9)
315+
//! so std::bind should capture all arguments because of the compiler.
316+
return exec_cmd(std::bind([this](T arg, Ts... args, const rcb_t& cb) -> rc& {
317+
return m_client.client_kill(arg, args..., cb);
318+
},
319+
arg, args..., std::placeholders::_1));
320+
}
321+
322+
} // namespace cpp_redis
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2015-2017 Simon Ninon <[email protected]>
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 <type_traits>
26+
27+
namespace cpp_redis {
28+
namespace helpers {
29+
30+
template <typename T, typename... Args>
31+
struct back {
32+
using type = typename back<Args...>::type;
33+
};
34+
35+
template <typename T>
36+
struct back<T> {
37+
using type = T;
38+
};
39+
40+
template <typename T, typename... Ts>
41+
struct front {
42+
using type = T;
43+
};
44+
45+
template <typename T1, typename T2, typename... Ts>
46+
struct is_type_present {
47+
static constexpr bool value = std::is_same<T1, T2>::value
48+
? true
49+
: is_type_present<T1, Ts...>::value;
50+
};
51+
52+
template <typename T1, typename T2>
53+
struct is_type_present<T1, T2> {
54+
static constexpr bool value = std::is_same<T1, T2>::value;
55+
};
56+
57+
template <typename T, typename... Args>
58+
struct is_different_types {
59+
static constexpr bool value = is_type_present<T, Args...>::value
60+
? false
61+
: is_different_types<Args...>::value;
62+
};
63+
64+
template <typename T1>
65+
struct is_different_types<T1> {
66+
static constexpr bool value = true;
67+
};
68+
} //! helpers
69+
} //! cpp_redis
+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2015-2017 Simon Ninon <[email protected]>
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+
#include <functional>
24+
#include <iostream>
25+
26+
namespace cpp_redis {
27+
28+
template <typename T>
29+
typename std::enable_if<std::is_same<T, redis_client::client_type>::value>::type
30+
redis_client::client_kill_unpack_arg(std::vector<std::string>& redis_cmd, reply_callback_t&, client_type type) {
31+
redis_cmd.emplace_back("TYPE");
32+
std::string type_string;
33+
34+
switch (type) {
35+
case client_type::normal: type_string = "normal"; break;
36+
case client_type::master: type_string = "master"; break;
37+
case client_type::pubsub: type_string = "pubsub"; break;
38+
case client_type::slave: type_string = "slave"; break;
39+
}
40+
41+
redis_cmd.emplace_back(type_string);
42+
}
43+
44+
template <typename T>
45+
typename std::enable_if<std::is_same<T, bool>::value>::type
46+
redis_client::client_kill_unpack_arg(std::vector<std::string>& redis_cmd, reply_callback_t&, bool skip) {
47+
redis_cmd.emplace_back("SKIPME");
48+
redis_cmd.emplace_back(skip ? "yes" : "no");
49+
}
50+
51+
template <typename T>
52+
typename std::enable_if<std::is_integral<T>::value>::type
53+
redis_client::client_kill_unpack_arg(std::vector<std::string>& redis_cmd, reply_callback_t&, uint64_t id) {
54+
redis_cmd.emplace_back("ID");
55+
redis_cmd.emplace_back(std::to_string(id));
56+
}
57+
58+
template <typename T>
59+
typename std::enable_if<std::is_class<T>::value>::type
60+
redis_client::client_kill_unpack_arg(std::vector<std::string>&, reply_callback_t& reply_callback, const T& cb) {
61+
reply_callback = cb;
62+
}
63+
64+
template <typename T, typename... Ts>
65+
void
66+
redis_client::client_kill_impl(std::vector<std::string>& redis_cmd, reply_callback_t& reply, const T& arg, const Ts&... args) {
67+
static_assert(!std::is_class<T>::value, "Reply callback should be in the end of the argument list");
68+
client_kill_unpack_arg<T>(redis_cmd, reply, arg);
69+
client_kill_impl(redis_cmd, reply, args...);
70+
};
71+
72+
template <typename T>
73+
void
74+
redis_client::client_kill_impl(std::vector<std::string>& redis_cmd, reply_callback_t& reply, const T& arg) {
75+
client_kill_unpack_arg<T>(redis_cmd, reply, arg);
76+
};
77+
78+
template <typename T, typename... Ts>
79+
inline redis_client&
80+
redis_client::client_kill(const T& arg, const Ts&... args) {
81+
static_assert(helpers::is_different_types<T, Ts...>::value, "Should only have one distinct value per filter type");
82+
static_assert(!(std::is_class<T>::value && std::is_same<T, typename helpers::back<T, Ts...>::type>::value), "Should have at least one filter");
83+
84+
std::vector<std::string> redis_cmd({"CLIENT", "KILL"});
85+
reply_callback_t reply_cb = nullptr;
86+
client_kill_impl<T, Ts...>(redis_cmd, reply_cb, arg, args...);
87+
88+
return send(redis_cmd, reply_cb);
89+
}
90+
91+
template <typename T, typename... Ts>
92+
inline redis_client&
93+
redis_client::client_kill(const std::string& host, int port, const T& arg, const Ts&... args) {
94+
static_assert(helpers::is_different_types<T, Ts...>::value, "Should only have one distinct value per filter type");
95+
std::vector<std::string> redis_cmd({"CLIENT", "KILL"});
96+
97+
//! If we have other type than lambda, then it's a filter
98+
if (!std::is_class<T>::value) {
99+
redis_cmd.emplace_back("ADDR");
100+
}
101+
102+
redis_cmd.emplace_back(host + ":" + std::to_string(port));
103+
reply_callback_t reply_cb = nullptr;
104+
client_kill_impl<T, Ts...>(redis_cmd, reply_cb, arg, args...);
105+
106+
return send(redis_cmd, reply_cb);
107+
}
108+
109+
inline redis_client&
110+
redis_client::client_kill(const std::string& host, int port) {
111+
return client_kill(host, port, reply_callback_t(nullptr));
112+
}
113+
114+
template <typename... Ts>
115+
inline redis_client&
116+
redis_client::client_kill(const char* host, int port, const Ts&... args) {
117+
return client_kill(std::string(host), port, args...);
118+
}
119+
120+
} // namespace cpp_redis

0 commit comments

Comments
 (0)